{"id":16138204,"url":"https://github.com/ul/ad-libitum","last_synced_at":"2026-01-20T04:04:09.085Z","repository":{"id":146516027,"uuid":"84862380","full_name":"ul/ad-libitum","owner":"ul","description":"Scheme Live Coding Environment","archived":false,"fork":false,"pushed_at":"2021-09-19T23:12:05.000Z","size":571,"stargazers_count":18,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-01-14T18:37:00.571Z","etag":null,"topics":["chez-scheme","literate-programming","livecoding","scheme"],"latest_commit_sha":null,"homepage":null,"language":"Scheme","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ul.png","metadata":{"files":{"readme":"README.html","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-13T18:45:25.000Z","updated_at":"2025-12-02T23:26:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"b967285d-8e0b-49ce-a01b-e6423d2b7180","html_url":"https://github.com/ul/ad-libitum","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ul/ad-libitum","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ul%2Fad-libitum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ul%2Fad-libitum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ul%2Fad-libitum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ul%2Fad-libitum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ul","download_url":"https://codeload.github.com/ul/ad-libitum/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ul%2Fad-libitum/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28595357,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T02:08:49.799Z","status":"ssl_error","status_checked_at":"2026-01-20T02:08:44.148Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chez-scheme","literate-programming","livecoding","scheme"],"created_at":"2024-10-09T23:32:56.652Z","updated_at":"2026-01-20T04:04:09.042Z","avatar_url":"https://github.com/ul.png","language":"Scheme","readme":"\u003c?xml version=\"1.0\" encoding=\"utf-8\"?\u003e\n\u003c!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\"\u003e\n\u003chtml xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\"\u003e\n\u003chead\u003e\n\u003c!-- 2021-09-20 Mon 09:10 --\u003e\n\u003cmeta http-equiv=\"Content-Type\" content=\"text/html;charset=utf-8\" /\u003e\n\u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1\" /\u003e\n\u003ctitle\u003eAd Libitum\u003c/title\u003e\n\u003cmeta name=\"generator\" content=\"Org mode\" /\u003e\n\u003cmeta name=\"author\" content=\"Ruslan Prakapchuk\" /\u003e\n\u003cstyle type=\"text/css\"\u003e\n \u003c!--/*--\u003e\u003c![CDATA[/*\u003e\u003c!--*/\n  .title  { text-align: center;\n             margin-bottom: .2em; }\n  .subtitle { text-align: center;\n              font-size: medium;\n              font-weight: bold;\n              margin-top:0; }\n  .todo   { font-family: monospace; color: red; }\n  .done   { font-family: monospace; color: green; }\n  .priority { font-family: monospace; color: orange; }\n  .tag    { background-color: #eee; font-family: monospace;\n            padding: 2px; font-size: 80%; font-weight: normal; }\n  .timestamp { color: #bebebe; }\n  .timestamp-kwd { color: #5f9ea0; }\n  .org-right  { margin-left: auto; margin-right: 0px;  text-align: right; }\n  .org-left   { margin-left: 0px;  margin-right: auto; text-align: left; }\n  .org-center { margin-left: auto; margin-right: auto; text-align: center; }\n  .underline { text-decoration: underline; }\n  #postamble p, #preamble p { font-size: 90%; margin: .2em; }\n  p.verse { margin-left: 3%; }\n  pre {\n    border: 1px solid #ccc;\n    box-shadow: 3px 3px 3px #eee;\n    padding: 8pt;\n    font-family: monospace;\n    overflow: auto;\n    margin: 1.2em;\n  }\n  pre.src {\n    position: relative;\n    overflow: auto;\n    padding-top: 1.2em;\n  }\n  pre.src:before {\n    display: none;\n    position: absolute;\n    background-color: white;\n    top: -10px;\n    right: 10px;\n    padding: 3px;\n    border: 1px solid black;\n  }\n  pre.src:hover:before { display: inline; margin-top: 14px;}\n  /* Languages per Org manual */\n  pre.src-asymptote:before { content: 'Asymptote'; }\n  pre.src-awk:before { content: 'Awk'; }\n  pre.src-C:before { content: 'C'; }\n  /* pre.src-C++ doesn't work in CSS */\n  pre.src-clojure:before { content: 'Clojure'; }\n  pre.src-css:before { content: 'CSS'; }\n  pre.src-D:before { content: 'D'; }\n  pre.src-ditaa:before { content: 'ditaa'; }\n  pre.src-dot:before { content: 'Graphviz'; }\n  pre.src-calc:before { content: 'Emacs Calc'; }\n  pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }\n  pre.src-fortran:before { content: 'Fortran'; }\n  pre.src-gnuplot:before { content: 'gnuplot'; }\n  pre.src-haskell:before { content: 'Haskell'; }\n  pre.src-hledger:before { content: 'hledger'; }\n  pre.src-java:before { content: 'Java'; }\n  pre.src-js:before { content: 'Javascript'; }\n  pre.src-latex:before { content: 'LaTeX'; }\n  pre.src-ledger:before { content: 'Ledger'; }\n  pre.src-lisp:before { content: 'Lisp'; }\n  pre.src-lilypond:before { content: 'Lilypond'; }\n  pre.src-lua:before { content: 'Lua'; }\n  pre.src-matlab:before { content: 'MATLAB'; }\n  pre.src-mscgen:before { content: 'Mscgen'; }\n  pre.src-ocaml:before { content: 'Objective Caml'; }\n  pre.src-octave:before { content: 'Octave'; }\n  pre.src-org:before { content: 'Org mode'; }\n  pre.src-oz:before { content: 'OZ'; }\n  pre.src-plantuml:before { content: 'Plantuml'; }\n  pre.src-processing:before { content: 'Processing.js'; }\n  pre.src-python:before { content: 'Python'; }\n  pre.src-R:before { content: 'R'; }\n  pre.src-ruby:before { content: 'Ruby'; }\n  pre.src-sass:before { content: 'Sass'; }\n  pre.src-scheme:before { content: 'Scheme'; }\n  pre.src-screen:before { content: 'Gnu Screen'; }\n  pre.src-sed:before { content: 'Sed'; }\n  pre.src-sh:before { content: 'shell'; }\n  pre.src-sql:before { content: 'SQL'; }\n  pre.src-sqlite:before { content: 'SQLite'; }\n  /* additional languages in org.el's org-babel-load-languages alist */\n  pre.src-forth:before { content: 'Forth'; }\n  pre.src-io:before { content: 'IO'; }\n  pre.src-J:before { content: 'J'; }\n  pre.src-makefile:before { content: 'Makefile'; }\n  pre.src-maxima:before { content: 'Maxima'; }\n  pre.src-perl:before { content: 'Perl'; }\n  pre.src-picolisp:before { content: 'Pico Lisp'; }\n  pre.src-scala:before { content: 'Scala'; }\n  pre.src-shell:before { content: 'Shell Script'; }\n  pre.src-ebnf2ps:before { content: 'ebfn2ps'; }\n  /* additional language identifiers per \"defun org-babel-execute\"\n       in ob-*.el */\n  pre.src-cpp:before  { content: 'C++'; }\n  pre.src-abc:before  { content: 'ABC'; }\n  pre.src-coq:before  { content: 'Coq'; }\n  pre.src-groovy:before  { content: 'Groovy'; }\n  /* additional language identifiers from org-babel-shell-names in\n     ob-shell.el: ob-shell is the only babel language using a lambda to put\n     the execution function name together. */\n  pre.src-bash:before  { content: 'bash'; }\n  pre.src-csh:before  { content: 'csh'; }\n  pre.src-ash:before  { content: 'ash'; }\n  pre.src-dash:before  { content: 'dash'; }\n  pre.src-ksh:before  { content: 'ksh'; }\n  pre.src-mksh:before  { content: 'mksh'; }\n  pre.src-posh:before  { content: 'posh'; }\n  /* Additional Emacs modes also supported by the LaTeX listings package */\n  pre.src-ada:before { content: 'Ada'; }\n  pre.src-asm:before { content: 'Assembler'; }\n  pre.src-caml:before { content: 'Caml'; }\n  pre.src-delphi:before { content: 'Delphi'; }\n  pre.src-html:before { content: 'HTML'; }\n  pre.src-idl:before { content: 'IDL'; }\n  pre.src-mercury:before { content: 'Mercury'; }\n  pre.src-metapost:before { content: 'MetaPost'; }\n  pre.src-modula-2:before { content: 'Modula-2'; }\n  pre.src-pascal:before { content: 'Pascal'; }\n  pre.src-ps:before { content: 'PostScript'; }\n  pre.src-prolog:before { content: 'Prolog'; }\n  pre.src-simula:before { content: 'Simula'; }\n  pre.src-tcl:before { content: 'tcl'; }\n  pre.src-tex:before { content: 'TeX'; }\n  pre.src-plain-tex:before { content: 'Plain TeX'; }\n  pre.src-verilog:before { content: 'Verilog'; }\n  pre.src-vhdl:before { content: 'VHDL'; }\n  pre.src-xml:before { content: 'XML'; }\n  pre.src-nxml:before { content: 'XML'; }\n  /* add a generic configuration mode; LaTeX export needs an additional\n     (add-to-list 'org-latex-listings-langs '(conf \" \")) in .emacs */\n  pre.src-conf:before { content: 'Configuration File'; }\n\n  table { border-collapse:collapse; }\n  caption.t-above { caption-side: top; }\n  caption.t-bottom { caption-side: bottom; }\n  td, th { vertical-align:top;  }\n  th.org-right  { text-align: center;  }\n  th.org-left   { text-align: center;   }\n  th.org-center { text-align: center; }\n  td.org-right  { text-align: right;  }\n  td.org-left   { text-align: left;   }\n  td.org-center { text-align: center; }\n  dt { font-weight: bold; }\n  .footpara { display: inline; }\n  .footdef  { margin-bottom: 1em; }\n  .figure { padding: 1em; }\n  .figure p { text-align: center; }\n  .equation-container {\n    display: table;\n    text-align: center;\n    width: 100%;\n  }\n  .equation {\n    vertical-align: middle;\n  }\n  .equation-label {\n    display: table-cell;\n    text-align: right;\n    vertical-align: middle;\n  }\n  .inlinetask {\n    padding: 10px;\n    border: 2px solid gray;\n    margin: 10px;\n    background: #ffffcc;\n  }\n  #org-div-home-and-up\n   { text-align: right; font-size: 70%; white-space: nowrap; }\n  textarea { overflow-x: auto; }\n  .linenr { font-size: smaller }\n  .code-highlighted { background-color: #ffff00; }\n  .org-info-js_info-navigation { border-style: none; }\n  #org-info-js_console-label\n    { font-size: 10px; font-weight: bold; white-space: nowrap; }\n  .org-info-js_search-highlight\n    { background-color: #ffff00; color: #000000; font-weight: bold; }\n  .org-svg { width: 90%; }\n  /*]]\u003e*/--\u003e\n\u003c/style\u003e\n\u003clink rel=\"stylesheet\" type=\"text/css\" href=\"https://fniessen.github.io/org-html-themes/src/readtheorg_theme/css/htmlize.css\"/\u003e\n\u003clink rel=\"stylesheet\" type=\"text/css\" href=\"https://fniessen.github.io/org-html-themes/src/readtheorg_theme/css/readtheorg.css\"/\u003e\n\u003cscript src=\"https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js\"\u003e\u003c/script\u003e\n\u003cscript src=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\" src=\"https://fniessen.github.io/org-html-themes/src/lib/js/jquery.stickytableheaders.min.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\" src=\"https://fniessen.github.io/org-html-themes/src/readtheorg_theme/js/readtheorg.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"text/javascript\"\u003e\n// @license magnet:?xt=urn:btih:e95b018ef3580986a04669f1b5879592219e2a7a\u0026dn=public-domain.txt Public Domain\n\u003c!--/*--\u003e\u003c![CDATA[/*\u003e\u003c!--*/\n     function CodeHighlightOn(elem, id)\n     {\n       var target = document.getElementById(id);\n       if(null != target) {\n         elem.classList.add(\"code-highlighted\");\n         target.classList.add(\"code-highlighted\");\n       }\n     }\n     function CodeHighlightOff(elem, id)\n     {\n       var target = document.getElementById(id);\n       if(null != target) {\n         elem.classList.remove(\"code-highlighted\");\n         target.classList.remove(\"code-highlighted\");\n       }\n     }\n    /*]]\u003e*///--\u003e\n// @license-end\n\u003c/script\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003cdiv id=\"content\"\u003e\n\u003ch1 class=\"title\"\u003eAd Libitum\u003c/h1\u003e\n\u003cdiv id=\"table-of-contents\"\u003e\n\u003ch2\u003eTable of Contents\u003c/h2\u003e\n\u003cdiv id=\"text-table-of-contents\"\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org60b23b7\"\u003e1. Getting Started\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#orgae7fbf2\"\u003e1.1. Chez Scheme\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org832873b\"\u003e1.1.1. Clone Chez Scheme repository\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgef9f628\"\u003e1.1.2. Configure, build and install Chez Scheme\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgf5c310f\"\u003e1.1.3. Test it's working\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orga38fa2c\"\u003e1.2. libsoundio\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org4470dca\"\u003e1.3. PortMidi\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org4b5d8e8\"\u003e1.4. Ad Libitum itself\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#orgd5db719\"\u003e1.4.1. Install\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgb9f4620\"\u003e1.4.2. Test\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgad169ed\"\u003e1.4.3. Play\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgeaf5b92\"\u003e2. Contribution\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org59a8a4c\"\u003e3. Kernel\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#orgb79f8fd\"\u003e3.1. Sound I/O\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgd311c09\"\u003e3.2. Scheduler\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#orgd112e7d\"\u003e3.2.1. Pairing Heap\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org5d93302\"\u003e3.3. Remote REPL\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org6c1f1b3\"\u003e3.3.1. \u003cspan class=\"todo TODO\"\u003eTODO\u003c/span\u003e Ensure that protocol is TCP\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org481e5de\"\u003e3.3.2. Blocking vs Async sockets\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org4b9a40d\"\u003e3.3.3. Open socket\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org3582e09\"\u003e3.3.4. Accept connections\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org934036f\"\u003e3.3.5. Spawn remote REPL\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org95ee76d\"\u003e3.3.6. \u003cspan class=\"todo TODO\"\u003eTODO\u003c/span\u003e Stop loop and close socket on disconnect\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orga58e6d9\"\u003e3.3.7. Start REPL server\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orge80390d\"\u003e4. Core\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#orga3cec52\"\u003e4.1. Math\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org7ec6f54\"\u003e4.2. Generators\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org131663f\"\u003e4.3. Envelopes\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#org5684e44\"\u003e4.3.1. ADSR\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org1517c56\"\u003e4.3.2. Impulse\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org9c0711a\"\u003e4.3.3. Transition\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org006427d\"\u003e4.4. Metronome\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orge56cf93\"\u003e4.5. Control signals\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgd4e35bd\"\u003e5. Std\u003c/a\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"#orgac328ce\"\u003e5.1. FFT\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgecc153e\"\u003e5.2. Filters\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgbac777e\"\u003e5.3. Instruments\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgb22d8bc\"\u003e5.4. Scales\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#orgf4ede71\"\u003e5.5. Rhythm\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org5e66f64\"\u003e5.6. MIDI\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"#org499e186\"\u003e6. Misc\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cp\u003e\nThe Scheme Live Coding Environment. Built on Chez Scheme and libsoundio.\n\u003c/p\u003e\n\n\u003cp\u003e\nYou might want to read this file here \u003ca href=\"http://ul.mantike.pro/ad-libitum/README.html\"\u003ehttp://ul.mantike.pro/ad-libitum/README.html\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cdiv id=\"outline-container-org60b23b7\" class=\"outline-2\"\u003e\n\u003ch2 id=\"org60b23b7\"\u003e\u003cspan class=\"section-number-2\"\u003e1\u003c/span\u003e Getting Started\u003c/h2\u003e\n\u003cdiv class=\"outline-text-2\" id=\"text-1\"\u003e\n\u003cp\u003e\nThis guide describes initial setup required to produce your first piece of\ndigital noise with Ad Libitum. At the moment Ad Libitum is tested only on\nMacOS therefore following instructions are MacOS-specific. Any feedback and\nimprovement for other platforms is more than welcome! Current state of Ad\nLibitum dependencies is that it should be easy to port it to Linux and\nmoderately hard (but possible) to Windows.\n\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgae7fbf2\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgae7fbf2\"\u003e\u003cspan class=\"section-number-3\"\u003e1.1\u003c/span\u003e Chez Scheme\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-1-1\"\u003e\n\u003cp\u003e\nFirst, you need Chez Scheme itself. Ad Libitum requires threaded version and\nyou probably don't want to install x11 dependency, that's why better to do it\nfrom source, not brew. Also we are using Racket's fork to be able to build on M1\nwhile \u003ca href=\"https://github.com/cisco/ChezScheme/issues/544\"\u003ehttps://github.com/cisco/ChezScheme/issues/544\u003c/a\u003e is in progress.\n\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org832873b\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org832873b\"\u003e\u003cspan class=\"section-number-4\"\u003e1.1.1\u003c/span\u003e Clone Chez Scheme repository\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-1-1-1\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003egit clone https://github.com/racket/ChezScheme.git\n\u003cspan style=\"font-weight: bold;\"\u003ecd\u003c/span\u003e ChezScheme\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgef9f628\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orgef9f628\"\u003e\u003cspan class=\"section-number-4\"\u003e1.1.2\u003c/span\u003e Configure, build and install Chez Scheme\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-1-1-2\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003e./configure --disable-x11\nmake\nsudo make install\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nThe first command may suggest you to build boot image first, e.g. on M1:\n\u003c/p\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003e./configure --pb\nmake tarm64osx.bootquick\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgf5c310f\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orgf5c310f\"\u003e\u003cspan class=\"section-number-4\"\u003e1.1.3\u003c/span\u003e Test it's working\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-1-1-3\"\u003e\n\u003cp\u003e\nRun \u003ccode\u003escheme\u003c/code\u003e from terminal and try to evaluate simple expression:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003e~/ChezScheme\u0026gt; scheme\n\nChez Scheme Version 9.5.5.5\nCopyright 1984-2020 Cisco Systems, Inc.\n\n\u0026gt; (+ 1 2 3)\n6\n\u0026gt;\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orga38fa2c\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orga38fa2c\"\u003e\u003cspan class=\"section-number-3\"\u003e1.2\u003c/span\u003e libsoundio\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-1-2\"\u003e\n\u003cp\u003e\nThis is library used by Ad Libitum for communication with your computer's\nsound system.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003ebrew install libsoundio\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org4470dca\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org4470dca\"\u003e\u003cspan class=\"section-number-3\"\u003e1.3\u003c/span\u003e PortMidi\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-1-3\"\u003e\n\u003cp\u003e\nYou need it if you plan to use MIDI controller.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003ebrew install portmidi\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org4b5d8e8\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org4b5d8e8\"\u003e\u003cspan class=\"section-number-3\"\u003e1.4\u003c/span\u003e Ad Libitum itself\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-1-4\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-orgd5db719\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orgd5db719\"\u003e\u003cspan class=\"section-number-4\"\u003e1.4.1\u003c/span\u003e Install\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-1-4-1\"\u003e\n\u003cp\u003e\nYou need to clone repository and build several helping libraries. You may\nneed to set \u003ccode\u003eSCHEMEH\u003c/code\u003e environment variable to your platform-specific\nlocation (default value is \u003ccode\u003e/usr/local/lib/csv9.5.5.5/tarm64osx/\u003c/code\u003e).\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003egit clone https://github.com/ul/ad-libitum.git\n\u003cspan style=\"font-weight: bold;\"\u003ecd\u003c/span\u003e ad-libitum\ngit submodule update --init --recursive --remote\nmake libs\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgb9f4620\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orgb9f4620\"\u003e\u003cspan class=\"section-number-4\"\u003e1.4.2\u003c/span\u003e Test\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-1-4-2\"\u003e\n\u003cp\u003e\nFire up \u003ccode\u003escheme ad-libitum.ss\u003c/code\u003e and play 440Hz tuner (beware of loud sound!\nreduce speakers/headphones volume before running). Congratulations, you\nlivecoded your first Ad Libitum piece!\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\"\u003e~/ad-libitum\u0026gt; scheme ad-libitum.ss\n\nChez Scheme Version 9.5.1\nCopyright 1984-2017 Cisco Systems, Inc.\n\n\u0026gt; (play! tuner)\n\u0026gt;\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgad169ed\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orgad169ed\"\u003e\u003cspan class=\"section-number-4\"\u003e1.4.3\u003c/span\u003e Play\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-1-4-3\"\u003e\n\u003cp\u003e\nRun \u0026amp; \u003ccode\u003egeiser-connect\u003c/code\u003e\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-shell\"\u003escheme --optimize-level 2 violet.ss\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-orgeaf5b92\" class=\"outline-2\"\u003e\n\u003ch2 id=\"orgeaf5b92\"\u003e\u003cspan class=\"section-number-2\"\u003e2\u003c/span\u003e Contribution\u003c/h2\u003e\n\u003cdiv class=\"outline-text-2\" id=\"text-2\"\u003e\n\u003cp\u003e\nContribution is more than welcome and highly appreciated! Any small or non-code\nfix is valuable as well, including spelling and grammar and setting proper\nlicensing.\n\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org59a8a4c\" class=\"outline-2\"\u003e\n\u003ch2 id=\"org59a8a4c\"\u003e\u003cspan class=\"section-number-2\"\u003e3\u003c/span\u003e Kernel\u003c/h2\u003e\n\u003cdiv class=\"outline-text-2\" id=\"text-3\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-orgb79f8fd\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgb79f8fd\"\u003e\u003cspan class=\"section-number-3\"\u003e3.1\u003c/span\u003e Sound I/O\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-3-1\"\u003e\n\u003cp\u003e\nAd Libitum relies on \u003ccode\u003echez-soundio\u003c/code\u003e bindings and high-level wrapper. We are\ngoing to create and open default i/o (only 'o' at the moment) stream and\nprovide it globally.\n\u003c/p\u003e\n\n\u003cp\u003e\nFor performance reasons \u003ccode\u003echez-sound\u003c/code\u003e itself doesn't provide any protection\nagainst broken \u003ccode\u003ewrite-callback\u003c/code\u003e. But in livecoding mistakes are the part of\nexploration and arguably we want to sacrifice some performance to be able to\nnot restart entire sound subsystem for fixing our \u003ccode\u003ewrite-callback\u003c/code\u003e. That's\nwhy calling \u003ccode\u003e*dsp*\u003c/code\u003e is wrapped into \u003ccode\u003eguard\u003c/code\u003e.\n\u003c/p\u003e\n\n\u003cp\u003e\nTo keep our scheduler clock in sync with audio we store audio time and return\nit from \u003ccode\u003enow\u003c/code\u003e function which is passed to scheduler later.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org034ab78\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;sound\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*time*\u003c/span\u003e 0.0)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003enow\u003c/span\u003e) *time*)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esilence\u003c/span\u003e time channel) 0.0)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*dsp*\u003c/span\u003e silence)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eset-dsp!\u003c/span\u003e f) (set! *dsp* f))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ehush!\u003c/span\u003e) (set-dsp! silence))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ewrite-callback\u003c/span\u003e time channel)\n  (set! *time* time)\n  (\u003cspan style=\"font-weight: bold;\"\u003eguard\u003c/span\u003e (_ [else 0.0])\n    (*dsp* time channel)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*sound-out*\u003c/span\u003e (soundio:open-default-out-stream write-callback))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*sample-rate*\u003c/span\u003e (soundio:sample-rate *sound-out*))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*channels*\u003c/span\u003e (soundio:channel-count *sound-out*))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estart\u003c/span\u003e) (soundio:start-out-stream *sound-out*))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estop\u003c/span\u003e) (soundio:stop-out-stream *sound-out*))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/sound\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgd311c09\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgd311c09\"\u003e\u003cspan class=\"section-number-3\"\u003e3.2\u003c/span\u003e Scheduler\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-3-2\"\u003e\n\u003cp\u003e\nMuch of music is about time. Before we produce any single sample of wave, we\nwant to control when to start and when to stop doing it. Much of live coding\nis about decoupling our commands from their execution. We want to say \"play\nnote a second later\" now, but play it a second later. It's where scheduler\ncomes to play. Essentially, scheduler's API is simple and allows to get\ncurrent time mark (whatever it means: system clock, time elapsed from\nscheduler start or number of rendered samples) and to callback procedure at\nsome point of time with more or less guaranteed skew limit.\n\u003c/p\u003e\n\n\u003cp\u003e\nLet's start with scheduler interface. As has been said there are two basic\nfunctions it must provide, \u003ccode\u003enow\u003c/code\u003e and \u003ccode\u003eschedule\u003c/code\u003e. First one allows to get\ncurrent point in time, and it is usually comes to schedule from external\nsource like audio stream to be in sync with it. Second one allows to schedule\nexecution at some point in future.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org360784b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;scheduler-interface\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;now\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;schedule\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/scheduler-interface\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nAs far as scheduler is stateful and even involves thread creation, it must\nhave two other basic methods:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org1a7e54e\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;scheduler-interface\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;start-scheduler\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;stop-scheduler\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/scheduler-interface\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nLet's shape scheduler's data. Obviously, \u003ccode\u003enow\u003c/code\u003e appears here, in form of either\nscheduler's own counter or function (which will get system time or related\nwrite thread sample number). Another thing is \u003ccode\u003equeue\u003c/code\u003e, where \u003ccode\u003eschedule\u003c/code\u003e will\nstore callbacks. Because queuing could happen from different threads at the\nsame time, as well as dequeuing inside scheduler could happen together with\nqueuing from another thread, we need to protect it with \u003ccode\u003emutex\u003c/code\u003e. We also need\n\u003ccode\u003ethread\u003c/code\u003e id or flag or whatever used to control thread exit, because Scheme\ndoesn't expose \u003ccode\u003epthread_kill\u003c/code\u003e. And the last one which comes to the mind at the\nmoment is \u003ccode\u003eresolution\u003c/code\u003e as a number of times per second scheduler checks the\n\u003ccode\u003equeue\u003c/code\u003e for expired events.\n\u003c/p\u003e\n\n\u003cp\u003e\nTogether with record definition we provide \u003ccode\u003esimple-scheduler\u003c/code\u003e which creates\nschedule with reasonable default parameters. The only thing it accepts is\n\u003ccode\u003enow\u003c/code\u003e, because usually you want you schedule to be in sync with external\nclock.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org97e9a1d\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;scheduler-record\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-record-type\u003c/span\u003e scheduler\n  (fields now (mutable queue) resolution (mutable thread) mutex))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esimple-scheduler\u003c/span\u003e now)\n  (make-scheduler\n   now           \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003enow\u003c/span\u003e\n   heap/empty    \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003equeue\u003c/span\u003e\n   250           \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eresolution\u003c/span\u003e\n   #f            \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ethread\u003c/span\u003e\n   (make-mutex)  \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003emutex\u003c/span\u003e\n   ))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/scheduler-record\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nLet's implement scheduler interface.\n\u003c/p\u003e\n\n\u003cp\u003e\n\u003ccode\u003enow\u003c/code\u003e then would just call \u003ccode\u003enow\u003c/code\u003e field:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org6048cb2\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;now\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003enow\u003c/span\u003e scheduler) ((scheduler-now scheduler)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/now\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nEvent queue accepts events which must have \u003ccode\u003ef\u003c/code\u003e with its\n\u003ccode\u003eargs\u003c/code\u003e to execute at \u003ccode\u003etime\u003c/code\u003e:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org187760b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;event-record\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-record-type\u003c/span\u003e event\n  (fields time f args))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/event-record\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nFor \u003ccode\u003equeue\u003c/code\u003e we need some heap implementation, I'm going to jump into \u003ca href=\"#orgd112e7d\"\u003e3.2.1\u003c/a\u003e!\n\u003c/p\u003e\n\n\u003cp\u003e\nMutex is used to prevent data race on insert and remove from queue happening\nin different threads.\n\u003c/p\u003e\n\n\u003cp\u003e\n\u003ccode\u003eschedule\u003c/code\u003e should accept either \u003ccode\u003eevent\u003c/code\u003e record, or its fields (and create\nrecord by itself) to unclutter user code.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org17a53cd\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;schedule\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eschedule\u003c/span\u003e\n  (\u003cspan style=\"font-weight: bold;\"\u003ecase-lambda\u003c/span\u003e\n    [(scheduler event)\n     (with-mutex (scheduler-mutex scheduler)\n                 (scheduler-queue-set! scheduler (heap/insert event-time event (scheduler-queue scheduler))))]\n    [(scheduler t f . args)\n     (schedule scheduler (make-event (inexact t) f args))]))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/schedule\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nProcessing events is just executing any expired events' functions and removing\nthem from the queue.\n\u003c/p\u003e\n\n\u003cp\u003e\nTo enable dynamic temporal recursion we support event's \u003ccode\u003ef\u003c/code\u003e to be a symbol\nreferring top level function.\n\u003c/p\u003e\n\n\u003cp\u003e\nOf course, live events are error prone, but we don't want flawed event to blow\nentire thread. Thus \u003ccode\u003ef\u003c/code\u003e execution is secured with \u003ccode\u003eguard\u003c/code\u003e.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgefc1c8b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;scheduler-process-events\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eprocess-events\u003c/span\u003e scheduler time)\n  (with-mutex\n   (scheduler-mutex scheduler)\n   (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003enext-event\u003c/span\u003e ()\n     (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([event (heap/find-min (scheduler-queue scheduler))])\n       (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eand\u003c/span\u003e event (\u0026lt;= (event-time event) time))\n         (scheduler-queue-set!\n          scheduler\n          (heap/delete-min event-time (scheduler-queue scheduler)))\n         (\u003cspan style=\"font-weight: bold;\"\u003eguard\u003c/span\u003e (_ [else #f])\n           (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([f (event-f event)])\n             (apply (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (symbol? f)\n                        (top-level-value f)\n                        f)\n                    (event-args event))))\n         (next-event))))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/scheduler-process-events\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nNow it's a time for start/stop thread. Stopping thread would be just setting a\nflag which I used to call \"poison pill\".\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org508b692\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;stop-scheduler\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estop-scheduler\u003c/span\u003e scheduler)\n  (scheduler-thread-set! scheduler #f))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/stop-scheduler\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nStarting thread will fork and loop calling expired events. We set expire\nperiod for a half of resolution period in future to compensate a little bit\nthat events could expire during \u003ccode\u003eprocess-events\u003c/code\u003e. Proper adjustment require\nfurther investigation taking in account that audio clock is not uniform (it\nmoves fast inside filling audio buffer process then waits to buffer to be\navailable again).\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgee84bde\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;start-scheduler\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estart-scheduler\u003c/span\u003e scheduler)\n  (fork-thread\n   (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e ()\n     (scheduler-thread-set! scheduler (get-thread-id))\n     (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([resolution (scheduler-resolution scheduler)]\n            [expired-horizon (/ 0.5 resolution)]\n            [microseconds-to-sleep (exact (floor (/ 1e6 resolution)))])\n       (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eloop\u003c/span\u003e ()\n         (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e (scheduler-thread scheduler)\n           (process-events scheduler (+ (now scheduler) expired-horizon))\n           (usleep 0 microseconds-to-sleep)\n           (loop)))))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/start-scheduler\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org29a49b9\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;scheduler\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;scheduler-record\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;event-record\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;scheduler-process-events\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;scheduler-interface\u0026gt;\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/scheduler\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nWe need just a simple default scheduler at hand for Ad Libitum needs:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org525c2fd\"\u003e(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*scheduler*\u003c/span\u003e #f)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003einit\u003c/span\u003e now) (set! *scheduler* (simple-scheduler now)))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estart\u003c/span\u003e) (start-scheduler *scheduler*))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estop\u003c/span\u003e) (stop-scheduler *scheduler*))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*schedule*\u003c/span\u003e t f . args) (schedule *scheduler* (make-event t f args)))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*now*\u003c/span\u003e) (now *scheduler*))\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgd112e7d\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orgd112e7d\"\u003e\u003cspan class=\"section-number-4\"\u003e3.2.1\u003c/span\u003e Pairing Heap\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-3-2-1\"\u003e\n\u003cp\u003e\nWikipedia's type definition for pairing heap structure looks like Scheme's\npairs (surprise =) ). Using them implementation is quite straightforward.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgf3d5ad9\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;pairing-heap\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ewe do some #f-punning and don't throw on empty heaps\u003c/span\u003e\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eheap/empty\u003c/span\u003e '())\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eheap/find-min\u003c/span\u003e heap)\n  (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (null? heap)\n      #f\n      (car heap)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eheap/merge\u003c/span\u003e comparator h1 h2)\n  (\u003cspan style=\"font-weight: bold;\"\u003econd\u003c/span\u003e\n   [(null? h1) h2]\n   [(null? h2) h1]\n   [(\u0026lt; (comparator (car h1)) (comparator (car h2)))\n    (cons (car h1) (cons h2 (cdr h1)))]\n   [else\n    (cons (car h2) (cons h1 (cdr h2)))]))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eheap/insert\u003c/span\u003e comparator elem heap)\n  (heap/merge comparator (cons elem '()) heap))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eheap/merge-pairs\u003c/span\u003e comparator subheaps)\n  (\u003cspan style=\"font-weight: bold;\"\u003econd\u003c/span\u003e\n   [(null? subheaps) heap/empty]\n   [(null? (cdr subheaps)) (car subheaps)]\n   [else (heap/merge comparator\n          (heap/merge comparator (car subheaps) (cadr subheaps))\n          (heap/merge-pairs comparator (cddr subheaps)))]))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eheap/delete-min\u003c/span\u003e comparator heap)\n  (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (null? heap)\n      heap/empty\n      (heap/merge-pairs comparator (cdr heap))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/pairing-heap\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org5d93302\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org5d93302\"\u003e\u003cspan class=\"section-number-3\"\u003e3.3\u003c/span\u003e Remote REPL\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-3-3\"\u003e\n\u003cp\u003e\nNB. REPL is currently disabled as sockets library doesn't work on M1.\nTo enable it back uncomment \u003ccode\u003e(repl:start-repl-server)\u003c/code\u003e in \u003ccode\u003ead-libitum-init\u003c/code\u003e.\n\u003c/p\u003e\n\n\u003cp\u003e\nWe need own repl server because music doesn't work in geiser repl for\nsomewhat reason. The most universal solution would be to have REPL over\neither UDP or TCP with the simplest possible protocol. We want it to be just\na carrier, everything else should happen inside editor and engine. Sadly Chez\nScheme has no sockets in its std lib. We are gonna try Aaron W. Hsu's\n\u003ca href=\"https://github.com/arcfide/chez-sockets\"\u003echez-sockets\u003c/a\u003e library.\n\u003c/p\u003e\n\n\u003cp\u003e\nActually, we are still able to use Geiser with our REPL server because it\nsupports remote REPL. See \"Connecting to an external Scheme\" at \u003ca href=\"http://www.nongnu.org/geiser/geiser_3.html#The-REPL\"\u003edocs\u003c/a\u003e. The\nonly thing required for it is to load \u003ccode\u003escheme/chez/geiser/geiser.ss\u003c/code\u003e into the\nREPL thread.\n\u003c/p\u003e\n\n\u003cp\u003e\nFirst, let's create a TCP socket. Here we rely on assumption, that default\nprotocol is TCP.\n\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org6c1f1b3\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org6c1f1b3\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.1\u003c/span\u003e \u003cspan class=\"todo TODO\"\u003eTODO\u003c/span\u003e Ensure that protocol is TCP\u003c/h4\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org481e5de\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org481e5de\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.2\u003c/span\u003e Blocking vs Async sockets\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-3-3-2\"\u003e\n\u003cp\u003e\nThough Aaron doesn't recommend using blocking sockets, they are so much\neasier for our case! No need to implement polling when waiting for\nconnection or receiving value.\n\u003c/p\u003e\n\n\u003cp\u003e\nTried blocking sockets. They work fine by themselves, but play bad with\n\u003ccode\u003esleep\u003c/code\u003e called from other threads! Falling back to async sockets and polling\nthen.\n\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org4b9a40d\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org4b9a40d\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.3\u003c/span\u003e Open socket\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-3-3-3\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgc2bdb05\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;open-socket\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eopen-socket\u003c/span\u003e)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([socket (sock:create-socket\n                 sock:socket-domain/internet\n                 sock:socket-type/stream\n                 sock:socket-protocol/auto)])\n    \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;bind-socket\u0026gt;\u0026gt;\u003c/span\u003e\n    \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;listen-socket\u0026gt;\u0026gt;\u003c/span\u003e\n    socket\n    ))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/open-socket\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nThen we are going to listen address and port for input. We'll make it\nconfigurable later, let's provide some sensible hardcoded defaults for now.\n\u003ci\u003elocalhost\u003c/i\u003e is for security reasons, and \u003ci\u003e37146\u003c/i\u003e is default Geiser port.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org833e011\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;bind-socket\u0026gt;\u003c/span\u003e\n(sock:bind-socket socket (sock:string-\u0026gt;internet-address \u003cspan style=\"font-style: italic;\"\u003e\"127.0.0.1:37146\"\u003c/span\u003e))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/bind-socket\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nAnd then let's listen for new connections!\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgdeb8006\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;listen-socket\u0026gt;\u003c/span\u003e\n(sock:listen-socket socket 1024)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/listen-socket\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org3582e09\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org3582e09\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.4\u003c/span\u003e Accept connections\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-3-3-4\"\u003e\n\u003cp\u003e\nTo actually accept new connections we are going to create new thread and\njust run infinite loop with \u003ccode\u003eaccept-socket\u003c/code\u003e inside. Remember, our socket is\nnon-blocking so we are to make polling to not eat all CPU by eager calls.\nAfter accepting new connection we'll proceed it in new thread.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orge22f54e\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;accept-connections\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eaccept-connections\u003c/span\u003e repl-server-socket)\n  (fork-thread\n   (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e ()\n     (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eloop\u003c/span\u003e ()\n       (usleep 0 polling-microseconds)\n       (\u003cspan style=\"font-weight: bold;\"\u003elet-values\u003c/span\u003e ([(socket address) (sock:accept-socket repl-server-socket)])\n         (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e socket\n           (printf \u003cspan style=\"font-style: italic;\"\u003e\"New REPL @ ~s\\r\\n\"\u003c/span\u003e (sock:internet-address-\u0026gt;string address))\n           (spawn-remote-repl socket address)))\n       (loop)))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/accept-connections\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org934036f\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org934036f\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.5\u003c/span\u003e Spawn remote REPL\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-3-3-5\"\u003e\n\u003cp\u003e\nEvery new connection accepted would spawn new thread with a REPL loop inside\nit. Because we are using async sockets, we are forced to run actual loop and\npoll socket for values. \u003ci\u003e50ms\u003c/i\u003e should be a reasonable polling delay to keep\nit responsive and not resource greedy at the same time. Also\n\u003ccode\u003ereceive-from-socket\u003c/code\u003e require to limit maximum message length. Here \u003ci\u003e65k\u003c/i\u003e is\nalso is a kind of a guess. Chez Scheme operates UTF-8 strings and messages\nare read as bytevectors from sockets, thus we need a transcoder to convert\nthem back and forth. Let's put all these requirements to values:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org3518c0b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;spawn-remote-repl-options\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003epolling-microseconds\u003c/span\u003e 50000)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003emax-chunk-length\u003c/span\u003e 65536)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003ecode-tx\u003c/span\u003e (make-transcoder (utf-8-codec) (eol-style lf) (error-handling-mode replace)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/spawn-remote-repl-options\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nPreparations are straightforward: define some helpers, send initial prompt,\nand start loop.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org7619b37\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;spawn-remote-repl\u0026gt;\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;spawn-remote-repl-options\u0026gt;\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003espawn-remote-repl\u003c/span\u003e socket address)\n  (fork-thread\n   (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e ()\n     (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e (\n            \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;repl-send-helpers\u0026gt;\u0026gt;\u003c/span\u003e\n            )\n       (send-prompt)\n       \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;repl-loop\u0026gt;\u0026gt;\u003c/span\u003e\n       ))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/spawn-remote-repl\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nConverting messages to bytevectors and sending to proper port is quite\ntedious, let's write a couple of helpers:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgd7b7b17\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;repl-send-helpers\u0026gt;\u003c/span\u003e\n[call-with-send-port\n (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e (f)\n   (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([response (call-with-bytevector-output-port f code-tx)])\n     (sock:send-to-socket socket response address)))]\n[send-prompt\n (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e ()\n   (call-with-send-port (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e (p) (display \u003cspan style=\"font-style: italic;\"\u003e\"\u0026gt; \"\u003c/span\u003e p))))]\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/repl-send-helpers\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nLoop starts with polling delay. For simplicity it's constant and\nunconditional in the beginning of every cycle. If socket is ready and\ncontains non-empty message then we do evaluation and send result back.\nReading from socket is implemented via ports, look at \u003ccode\u003echez-socket\u003c/code\u003e\ndocumentation for more info.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgd5e0816\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;repl-loop\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eloop\u003c/span\u003e ()\n  (usleep 0 polling-microseconds)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet-values\u003c/span\u003e ([(request address)\n                (sock:receive-from-socket socket max-chunk-length)])\n    (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eand\u003c/span\u003e request (positive? (bytevector-length request)))\n        (call-with-port\n         (open-bytevector-input-port request code-tx)\n         \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;repl-read-eval-print\u0026gt;\u0026gt;\u003c/span\u003e\n         )\n        (loop))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/repl-loop\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nOur remote REPL supports multi-form messages, therefore we need inner loop to\nread and process them one by one.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org50ed6cc\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;repl-read-eval-print\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e (p)\n  (\u003cspan style=\"font-weight: bold;\"\u003edo\u003c/span\u003e ([x (read p) (read p)])\n      ((eof-object? x))\n    (printf \u003cspan style=\"font-style: italic;\"\u003e\"\u0026gt; ~s\\r\\n\"\u003c/span\u003e x)\n    (call-with-send-port\n     \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;repl-eval-print\u0026gt;\u0026gt;\u003c/span\u003e\n     ))\n  (send-prompt)\n  (loop))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/repl-read-eval-print\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nEval and send result back, easy, huh?\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgc47a4d3\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;repl-eval-print\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e (p)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e (\n         \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;repl-eval\u0026gt;\u0026gt;\u003c/span\u003e\n         )\n    \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;\u0026lt;repl-print\u0026gt;\u0026gt;\u003c/span\u003e\n    )\n  )\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/repl-eval-print\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nTricky part is that we want to:\n\u003c/p\u003e\n\n\u003cul class=\"org-ul\"\u003e\n\u003cli\u003ecapture output performed by evaluated form\u003c/li\u003e\n\u003cli\u003ecapture result of form evaluated\u003c/li\u003e\n\u003cli\u003edon't blow up on exception and capture its message\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003e\nThat's why we can't just call \u003ccode\u003eeval\u003c/code\u003e\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org17d7b49\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;repl-eval\u0026gt;\u003c/span\u003e\n[result #f]\n[output\n (with-output-to-string\n   (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e ()\n     (set! result (\u003cspan style=\"font-weight: bold;\"\u003eguard\u003c/span\u003e (x [else (display-condition x)]) (eval x)))))]\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/repl-eval\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nOn the other hand, sending is quite straightforward, because we need just to\nwrite to port provided by \u003ccode\u003ecall-with-send-port\u003c/code\u003e\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org1595ed5\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;repl-print\u0026gt;\u003c/span\u003e\n(printf \u003cspan style=\"font-style: italic;\"\u003e\"| ~s\\r\\n\"\u003c/span\u003e output)\n(printf \u003cspan style=\"font-style: italic;\"\u003e\"\u0026lt; ~s\\r\\n\"\u003c/span\u003e result)\n(display output p)\n(display result p)\n(newline p)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/repl-print\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org95ee76d\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org95ee76d\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.6\u003c/span\u003e \u003cspan class=\"todo TODO\"\u003eTODO\u003c/span\u003e Stop loop and close socket on disconnect\u003c/h4\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orga58e6d9\" class=\"outline-4\"\u003e\n\u003ch4 id=\"orga58e6d9\"\u003e\u003cspan class=\"section-number-4\"\u003e3.3.7\u003c/span\u003e Start REPL server\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-3-3-7\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org8a991c6\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;start-repl-server\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estart-repl-server\u003c/span\u003e)\n  (accept-connections (open-socket)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/start-repl-server\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orge80390d\" class=\"outline-2\"\u003e\n\u003ch2 id=\"orge80390d\"\u003e\u003cspan class=\"section-number-2\"\u003e4\u003c/span\u003e Core\u003c/h2\u003e\n\u003cdiv class=\"outline-text-2\" id=\"text-4\"\u003e\n\u003cp\u003e\nWoohoo! Naive \u003ca href=\"#org59a8a4c\"\u003e3\u003c/a\u003e draft is here and we could start to explore Core basics\nof Sound. At this point Ad Libitum splits into into interwinded parts: the\nframework and the book. In the framework we are going to grow all necessary\ninstruments for live coding. In the book we are going to use those instruments\nto experiment with sound.\n\u003c/p\u003e\n\n\u003cp\u003e\nOne of the naming principles of Ad Libitum variables and functions is that\nthey should have proper long self-describing name for clarity and could have\nany funky alias for shortening during performance and for fun cryptic\nlibrettos.\n\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orga3cec52\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orga3cec52\"\u003e\u003cspan class=\"section-number-3\"\u003e4.1\u003c/span\u003e Math\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-4-1\"\u003e\n\u003cp\u003e\nBefore diving into the abyss of digital music let's define several useful\nbasic math constants and functions.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orge5c693e\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;basic-math\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003epi\u003c/span\u003e (inexact (* (asin 1.0) 2)))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003etwo-pi\u003c/span\u003e (* 2.0 pi))\n(alias \u0026#960; pi)\n(alias 2\u0026#960; two-pi)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003erandom-amplitude\u003c/span\u003e)\n  (- (random 2.0) 1.0))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eclamp\u003c/span\u003e value start end)\n  (\u003cspan style=\"font-weight: bold;\"\u003econd\u003c/span\u003e\n   [(\u0026lt; value start) start]\n   [(\u0026gt; value end) end]\n   [else value]))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/basic-math\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org7ec6f54\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org7ec6f54\"\u003e\u003cspan class=\"section-number-3\"\u003e4.2\u003c/span\u003e Generators\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-4-2\"\u003e\n\u003cp\u003e\nSound is about motion. About our mean of sensing somewhat periodic motion\na.k.a waves. The higher is period, the higher is signal pitch. Waveform\ndetermines character of signal. And irregularities determine\u0026#x2026; Something.\nNoise? Personality? We'll try to discover.\n\u003c/p\u003e\n\n\u003cp\u003e\nThough signal demonstration usually started with sine waveform as the most\nrecognizable and surprisingly pleasant one, we are going to start with\ncomputationally simplest one (though potentially not the fastest to calculate).\n\u003c/p\u003e\n\n\u003cp\u003e\nTechnically, the simplest generator is just a constant value, no motion,\nsilence. But which stands next in simplicity?\n\u003c/p\u003e\n\n\u003cp\u003e\nIt's the signal, which is in one position half of a time and in another position\nin another half. By \"time\" here I mean one cycle, one period of signal.\n\u003c/p\u003e\n\n\u003cp\u003e\nBut first let define a couple of constants to start with. It's a frequency we\nwant to hear and its derivatives.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org326c63d\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;tuner-constants\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003etuner-frequency\u003c/span\u003e 440.0)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003etuner-period\u003c/span\u003e (/ tuner-frequency))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003etuner-half-period\u003c/span\u003e (* 0.5 tuner-period))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/tuner-constants\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org29b0a4e\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;simplest-oscillator\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esimplest-oscillator\u003c/span\u003e time channel)\n  (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026gt; (mod time tuner-period) tuner-half-period)\n      1.0\n      -1.0))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/simplest-oscillator\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nActually, this waveform is called square, because of shape. Once we'll add\nvisualisation library to Ad Libitum, before that try to draw function plot by hands.\n\u003c/p\u003e\n\n\u003cp\u003e\nFeel free to experiment with different waveforms, we will do it together\nlater. Let's step back and look at our example and try to come up with useful\nabstraction. Our DSP callback has signature \u003ccode\u003ef(time, channel) -\u0026gt; amplitude\u003c/code\u003e,\nwhich is the basis for any audio signal. But what prevents us using audio\nsignals as the main medium for building sound? Nothing! It's even very handy.\nAudio signals then are capable of control parameters of other signal,\nnaturally forming audio graph. And Chez Scheme should optimize that CSP-like\nstyle well. But we need to think carefully ahead of time about signature\nitself. What if later we want add additional information flowing every\nsample? What if returning just float is not enough to express all we want?\nBecause it's very beautiful, that every signal could be either interpreted as\na DSP callback alone, and could be passed to other signals. But in the latter\ncase sometimes it's not enough to communicate between signals with a single\nfloat. Perhaps something like \u003ccode\u003ef(time, channel, data) -\u0026gt; (amplitude, data)\u003c/code\u003e\ncould do the job? Where structure of \u003ccode\u003edata\u003c/code\u003e is determined by your\napplication, and parent signal is responsible for using or discarding the\n\u003ccode\u003edata\u003c/code\u003e returned by child signal. OTOH, \u003ccode\u003edata\u003c/code\u003e in parameters plays like a\ncontainer for some global state to survive between samples, and we could\nreplace it with actual global or closured state in our application. The same\nthing for returned data.\n\u003c/p\u003e\n\n\u003cp\u003e\nLet's start with \u003ccode\u003ef(time, channel) -\u0026gt; amplitude\u003c/code\u003e then and pray that we didn't\noverlook something important.\n\u003c/p\u003e\n\n\u003cp\u003e\nTo ease writing signal creators and spotting them in code let's introduce\nsmall helper:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org6bf8fff\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;signal\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003esignal\u003c/span\u003e stx)\n  (syntax-case stx ()\n    [(k body ...)\n     (with-syntax ([time (datum-\u0026gt;syntax #'k 'time)]\n                   [channel (datum-\u0026gt;syntax #'k 'channel)])\n       #'(\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (time channel) body ...))]))\n\n(alias ~\u0026lt; signal)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003edefine-signal\u003c/span\u003e stx)\n  (syntax-case stx ()\n    [(k args body ...)\n     (with-syntax ([time (datum-\u0026gt;syntax #'k 'time)]\n                   [channel (datum-\u0026gt;syntax #'k 'channel)])\n       #'(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eargs\u003c/span\u003e\n           (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (time channel)\n             body ...)))]))\n\n(alias define~ define-signal)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/signal\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nUsage of that syntax sugar is highly encouraged as it eases refactor in case\nof arguments change, e.g. adding sample from audio input.\n\u003c/p\u003e\n\n\u003cp\u003e\nThe most basic signal is just a constant one, which is essentially created by\nour shiny new syntax \u003ccode\u003e(~\u0026lt; amplitude)\u003c/code\u003e. But \u003ccode\u003e~\u0026lt;\u003c/code\u003e is a macro and having\nfunction is useful for composition matters:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgb626d47\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;constant\u0026gt;\u003c/span\u003e\n(define~ (constant amplitude) amplitude)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/constant\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nThen we are able to define \u003ccode\u003esilence\u003c/code\u003e as follows:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org264e9c5\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;silence\u0026gt;\u003c/span\u003e\n(define~ silence 0.0)\n(alias \u0026#8709; silence)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/silence\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nQuick question for self-test: what sound would \u003ccode\u003e(~\u0026lt; 1.0)\u003c/code\u003e produce?\n\u003c/p\u003e\n\n\u003cp\u003e\nThough it's still very useful signal, let give it a separate name:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgea3d73f\"\u003e(define~ unit 1.0)\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nAnother useful syntax sugar is for referrign and setting vector element\ncorresponding to the current channel. It is very common pattern to store\nsignal state in vector on per-channel basis.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgca6063b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;channel\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003emake-channel-vector\u003c/span\u003e stx)\n  (syntax-case stx ()\n    [(k)\n     (with-syntax ([*channels* (datum-\u0026gt;syntax #'k '*channels*)])\n       #'(make-vector *channels*))]\n    [(k value)\n     (with-syntax ([*channels* (datum-\u0026gt;syntax #'k '*channels*)])\n       #'(make-vector *channels* value))]))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003echannel-ref\u003c/span\u003e stx)\n  (syntax-case stx ()\n    [(k name)\n     (with-syntax ([channel (datum-\u0026gt;syntax #'k 'channel)])\n       #'(vector-ref name channel))]))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003echannel-set!\u003c/span\u003e stx)\n  (syntax-case stx ()\n    [(k name value)\n     (with-syntax ([channel (datum-\u0026gt;syntax #'k 'channel)])\n       #'(vector-set! name channel value))]))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/channel\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nFor composing signal creators we could define a helper, which is the regular\nfunction composition!\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org69c1f6b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;compose\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ecompose\u003c/span\u003e . fns)\n  (\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-chain\u003c/span\u003e fn chain)\n    (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e args (call-with-values (cut apply fn args) chain)))\n  (reduce make-chain values fns))\n\n(alias \u0026#8728; compose)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/compose\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nFor unifying oscillators we are going to define signal which will care about\nconverting time to proper phase. When you deal with periodic signals it's\nimportant to distinguish time from phase, because at different frequencies\nphase would be different at the given point of time. Which is okay when\nfrequency of you oscillator is constant. When it's variable as in FM\nsynthesis, you need to track phase for your oscillator to make it behave\nproperly. Let's create special signal \u003ccode\u003ephasor\u003c/code\u003e for that purpose. It will take\n\u003ccode\u003efrequency\u003c/code\u003e signal and \u003ccode\u003ephase0\u003c/code\u003e signal and return signal of phase in \u003ccode\u003e[0, 1)\u003c/code\u003e\nhalf-interval.\n\u003c/p\u003e\n\n\u003cp\u003e\nHere we have an opportunity for a small syntactic improvement. The use-case\nwhen signal is applied to parameters named exactly \u003ccode\u003etime\u003c/code\u003e and \u003ccode\u003echannel\u003c/code\u003e in\ncurrent scope is very common. Let's create a special syntax for it.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org890a0cc\"\u003e(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;~\u003c/span\u003e stx)\n  (syntax-case stx ()\n    [(k signal)\n     (with-syntax ([time (datum-\u0026gt;syntax #'k 'time)]\n                   [channel (datum-\u0026gt;syntax #'k 'channel)])\n       #'(signal time channel))]))\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nThere is a need trick to increase performance w/o breaching abstraction. If\nyou have composite signal which you are sure produces same samples for every\nchannel then you can build composite signal as usual, but wrap it in \u003ccode\u003emono\u003c/code\u003e\nin the end to reduce load.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orge8dce38\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;mono\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emono\u003c/span\u003e signal)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([x 0.0])\n    (~\u0026lt;\n     (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e (zero? channel)\n       (set! x (\u0026lt;~ signal)))\n     x)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/mono\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nLet's use it in our phasor signal. Phasor is used so frequently that we want\nto provide a small optimization for the case when frequency is known to be\nconstant.\n\u003c/p\u003e\n\n\u003cp\u003e\nNote that \u003ccode\u003edynamic-phasor\u003c/code\u003e relies on being called sample by sample. Skipping\nsamples is okay-ish (it's like pausing phasor), but calling the same phasor\nfrom several other signals could make it move too fast. We need additional\ncheck to protect it.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org4265027\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;phasor\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003edynamic-phasor\u003c/span\u003e frequency phase0)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([previous-times (make-channel-vector 0.0)]\n        [previous-phases (make-channel-vector 0.0)])\n    (~\u0026lt;\n     (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([previous-time (channel-ref previous-times)]\n            [phase-delta (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt; previous-time time)\n                             (/ (\u0026lt;~ frequency) *sample-rate*)\n                             0.0)]\n            [next-phase (-\u0026gt; (channel-ref previous-phases)\n                            (+ phase-delta)\n                            (mod 1.0))])\n       (channel-set! previous-times time)\n       (channel-set! previous-phases next-phase)\n       (-\u0026gt; (\u0026lt;~ phase0)\n           (+ next-phase)\n           (mod 1.0))))))\n\n(define~ (static-phasor frequency phase0)\n  (-\u0026gt; time (* frequency) (+ phase0) (mod 1.0)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003ephasor\u003c/span\u003e\n  (\u003cspan style=\"font-weight: bold;\"\u003ecase-lambda\u003c/span\u003e\n    [(frequency phase0)\n     (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (number? frequency)\n         (static-phasor frequency phase0)\n         (dynamic-phasor frequency phase0))]\n    [(frequency)\n     (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (number? frequency)\n         (static-phasor frequency 0.0)\n         (dynamic-phasor frequency \u0026#8709;))]))\n\n(alias /// phasor)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/phasor\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nThen basic waveforms are defined in very clean way:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org3fbc3fb\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;waveforms\u0026gt;\u003c/span\u003e\n(define~ (sine phase)\n  (sin (* 2\u0026#960; (\u0026lt;~ phase))))\n\n(define~ (cosine phase)\n  (cos (* 2\u0026#960; (\u0026lt;~ phase))))\n\n(define~ (square phase)\n  (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt; (\u0026lt;~ phase) 0.5)\n      1.0\n      -1.0))\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ewhen `pulse-width' is `(constant 0.5)' it's identical to `square-wave'\u003c/span\u003e\n(define~ (pulse pulse-width phase)\n  (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt; (\u0026lt;~ phase) (\u0026lt;~ pulse-width))\n      1.0\n      -1.0))\n\n(define~ (tri phase)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([phase (\u0026lt;~ phase)])\n    (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt; phase 0.5)\n        (- (* 4.0 phase) 1.0)\n        (+ (* -4.0 phase) 3.0))))\n\n(define~ (saw phase)\n  (- (* 2.0 (\u0026lt;~ phase)) 1.0))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esampler\u003c/span\u003e table phase)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([N (vector-length (vector-ref table 0))]\n         [N-1 (- N 1)]\n         [n (fixnum-\u0026gt;flonum N)])\n    (~\u0026lt; (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([position (* n (\u0026lt;~ phase))])\n          (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([i (-\u0026gt; position\n                       (fltruncate)\n                       (flonum-\u0026gt;fixnum)\n                       (clamp 0 N-1))]\n                [a (mod position 1.0)]\n                [table (channel-ref table)])\n            (+ (* (- 1.0 a) (vector-ref table i))\n               (* a (vector-ref table (mod (+ i 1) N)))))))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eunroll\u003c/span\u003e signal base-frequency)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([n (-\u0026gt; *sample-rate* (/ base-frequency) (round) (exact))]\n         [table (make-channel-vector)])\n    (do-ec (: channel *channels*)\n           (channel-set! table (make-vector n)))\n    \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003echannel is in inner loop because many `signal' functions\u003c/span\u003e\n    \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003erely on ordered sample-by-sample execution\u003c/span\u003e\n    (do-ec (: sample n)\n           (: channel *channels*)\n           (vector-set!\n            (channel-ref table)\n            sample\n            (signal (/ sample *sample-rate*) channel)))\n    table))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003esine///\u003c/span\u003e (\u0026#8728; sine phasor))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003ecosine///\u003c/span\u003e (\u0026#8728; cosine phasor))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003esquare///\u003c/span\u003e (\u0026#8728; square phasor))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003epulse///\u003c/span\u003e\n  (\u003cspan style=\"font-weight: bold;\"\u003ecase-lambda\u003c/span\u003e\n    [(pulse-width frequency phase0)\n     (pulse pulse-width (phasor frequency phase0))]\n    [(pulse-width frequency)\n     (pulse pulse-width (phasor frequency \u0026#8709;))]))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003etri///\u003c/span\u003e (\u0026#8728; tri phasor))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003esaw///\u003c/span\u003e (\u0026#8728; saw phasor))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003esampler///\u003c/span\u003e\n  (\u003cspan style=\"font-weight: bold;\"\u003ecase-lambda\u003c/span\u003e\n    [(table frequency) (sampler table (phasor frequency))]\n    [(table frequency phase0) (sampler table (phasor frequency phase0))]))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/waveforms\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nBefore we play something interesting with stuff we already defined we need\none more helper. Drawback of our way of composition of signals is that we\ncan't change code of one of them in live and make changed reloaded live, even\nif signal is not anonymous and was defined as a top-level variable. For\nsignal which we plan to reload dynamically we are going to introduce wrapper\nwhich will look for given signal's symbol on every invocation:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orge845c87\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;live-signal\u0026gt;\u003c/span\u003e\n(define~ (live-signal symbol) (\u0026lt;~ (top-level-value symbol)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/live-signal\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nAlso useful to have live value counterpart:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org4b6afa0\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;live-value\u0026gt;\u003c/span\u003e\n(define~ (live-value symbol) (top-level-value symbol))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/live-value\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nNext step is implementation of signal arithmetics to ease their mixing and\nmatching.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org41cb0eb\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;signal-operators\u0026gt;\u003c/span\u003e\n(define~ (signal-sum* x y)\n  (+ (\u0026lt;~ x) (\u0026lt;~ y)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esignal-sum\u003c/span\u003e x . xs)\n  (fold-left signal-sum* x xs))\n\n(define~ (signal-prod* x y)\n  (* (\u0026lt;~ x) (\u0026lt;~ y)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esignal-prod\u003c/span\u003e x . xs)\n  (fold-left signal-prod* x xs))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esignal-diff\u003c/span\u003e x . xs)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([y (apply signal-sum xs)])\n    (~\u0026lt; (- (\u0026lt;~ x) (\u0026lt;~ y)))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esignal-div\u003c/span\u003e x . xs)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([y (apply signal-prod xs)])\n    (~\u0026lt; (/ (\u0026lt;~ x) (\u0026lt;~ y)))))\n\n(alias +~ signal-sum)\n(alias *~ signal-prod)\n(alias -~ signal-diff)\n(alias /~ signal-div)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u0026#8721; (cut apply signal-sum \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;...\u0026gt;\u003c/span\u003e))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u0026#8719; (cut apply signal-prod \u003cspan style=\"font-weight: bold; text-decoration: underline;\"\u003e\u0026lt;...\u0026gt;\u003c/span\u003e))\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003enormalizing +~\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emix\u003c/span\u003e . args)\n  (*~ (\u0026#8721; args) (constant (inexact (/ (sqrt (length args)))))))\n\n(define~ (pan p)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([p (* 0.5 (+ 1.0 (\u0026lt;~ p)))])\n    (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (zero? channel)\n        (- 1.0 p)\n        p)))\n\n(define~ (phase-\u0026gt;interval phase start end)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([phase (\u0026lt;~ phase)]\n        [start (\u0026lt;~ start)]\n        [end (\u0026lt;~ end)])\n    (+ start (* phase (- end start)))))\n\n(define~ (amplitude-\u0026gt;phase s)\n  (* 0.5 (+ 1.0 (\u0026lt;~ s))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/signal-operators\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org131663f\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org131663f\"\u003e\u003cspan class=\"section-number-3\"\u003e4.3\u003c/span\u003e Envelopes\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-4-3\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-org5684e44\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org5684e44\"\u003e\u003cspan class=\"section-number-4\"\u003e4.3.1\u003c/span\u003e ADSR\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-4-3-1\"\u003e\n\u003cp\u003e\nADSR envelope shapes signal with polyline described with 4 parameters:\n\u003c/p\u003e\n\n\u003cul class=\"org-ul\"\u003e\n\u003cli\u003eAttack time is the time taken for initial run-up of level from nil to peak,\nbeginning when the key is first pressed.\u003c/li\u003e\n\u003cli\u003eDecay time is the time taken for the subsequent run down from the attack\nlevel to the designated sustain level.\u003c/li\u003e\n\u003cli\u003eSustain level is the level during the main sequence of the sound's\nduration, until the key is released.\u003c/li\u003e\n\u003cli\u003eRelease time is the time taken for the level to decay from the sustain\nlevel to zero after the key is released.\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cp\u003e\n(Thanks, \u003ca href=\"https://en.wikipedia.org/wiki/Synthesizer#Attack_Decay_Sustain_Release_.28ADSR.29_envelope\"\u003eWikipedia\u003c/a\u003e)\n\u003c/p\u003e\n\n\u003cp\u003e\nTwo more parameter required to apply envelope in real performance: note's\nmoments of start and end. To make envelope generic and open for crazy\nexperiments all 6 parameters are going to be signals:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org52e7a2c\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;adsr\u0026gt;\u003c/span\u003e\n(define~ (adsr start end attack decay sustain release)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([end (\u0026lt;~ end)])\n    (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt;= end time)\n        \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eNOTE OFF\u003c/span\u003e\n        (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([\u0026#916;t (- time end)]\n              [r (\u0026lt;~ release)])\n          (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eand\u003c/span\u003e (positive? r)\n                   (\u0026lt;= \u0026#916;t r))\n              (* (- 1.0 (/ \u0026#916;t r)) (\u0026lt;~ sustain))\n              0.0))\n        \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eNOTE ON\u003c/span\u003e\n        (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([start (\u0026lt;~ start)])\n          (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt;= start time)\n              (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([\u0026#916;t (- time start)]\n                    [a (\u0026lt;~ attack)])\n                (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eand\u003c/span\u003e (positive? a)\n                         (\u0026lt;= \u0026#916;t a))\n                    (/ \u0026#916;t a)\n                    (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([\u0026#916;t (- \u0026#916;t a)]\n                          [d (\u0026lt;~ decay)]\n                          [s (\u0026lt;~ sustain)])\n                      (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eand\u003c/span\u003e (positive? d)\n                               (\u0026lt;= \u0026#916;t d))\n                          (- 1.0 (* (- 1.0 s) (/ \u0026#916;t d)))\n                          s))))\n              0.0)))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/adsr\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nLet's test it with simple note play:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org5c8de06\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;play-note\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003esimple-instrument\u003c/span\u003e start end freq a d s r)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([start (live-value start)]\n         [end (live-value end)]\n         [freq (live-value freq)]\n         [osc (sine-wave (phasor freq))]\n         [env (adsr start end (~\u0026lt; a) (~\u0026lt; d) (~\u0026lt; s) (~\u0026lt; r))])\n    (*~ env osc)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-play-note\u003c/span\u003e start end frequency)\n  (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (freq dur)\n    (set-top-level-value! frequency freq)\n    (set-top-level-value! start (now))\n    (set-top-level-value! end (+ (now) dur))))\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(define start 0.0)\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(define end 1.0)\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(define frequency 440.0)\u003c/span\u003e\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(define inst (simple-intrument 'start 'end 'frequency 0.3 0.5 0.8 1.0))\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(define play-note (make-play-note 'start 'end 'frequency))\u003c/span\u003e\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(sound:set-dsp! (live-signal 'inst))\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(play-note 440.0 1.1)\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/play-note\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nWe return to instrument concept later and come up with better design for it.\n\u003c/p\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org1517c56\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org1517c56\"\u003e\u003cspan class=\"section-number-4\"\u003e4.3.2\u003c/span\u003e Impulse\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-4-3-2\"\u003e\n\u003cp\u003e\nAnother simple though useful envelope is impulse.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org1fc7b3b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;impulse\u0026gt;\u003c/span\u003e\n(define~ (impulse start apex)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([start (\u0026lt;~ start)])\n    (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u0026lt;= start time)\n        (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([h (/ (- time start)\n                    (- (\u0026lt;~ apex) start))])\n          (* h (exp (- 1.0 h))))\n        0.0)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/impulse\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org9c0711a\" class=\"outline-4\"\u003e\n\u003ch4 id=\"org9c0711a\"\u003e\u003cspan class=\"section-number-4\"\u003e4.3.3\u003c/span\u003e Transition\u003c/h4\u003e\n\u003cdiv class=\"outline-text-4\" id=\"text-4-3-3\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org1ac2587\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;transition\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003etransition\u003c/span\u003e curve \u0026#916;t signal)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([starts (make-channel-vector (now))]\n        [previous-values (make-channel-vector 0.0)]\n        [current-values (make-channel-vector 0.0)]\n        [next-values (make-channel-vector 0.0)])\n    (~\u0026lt;\n     (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([\u0026#916;t (\u0026lt;~ \u0026#916;t)]\n           [current-value (\u0026lt;~ signal)]\n           [next-value (channel-ref next-values)])\n       (\u003cspan style=\"font-weight: bold;\"\u003eunless\u003c/span\u003e (= current-value next-value)\n         (channel-set! previous-values (channel-ref current-values))\n         (channel-set! next-values current-value)\n         (channel-set! starts time))\n       (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([current-value\n              (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([\u0026#948;t (- time (channel-ref starts))])\n                (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eand\u003c/span\u003e (positive? \u0026#916;t) (\u0026lt; \u0026#948;t \u0026#916;t))\n                    (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([previous-value (channel-ref previous-values)])\n                      (+ previous-value\n                         (curve (/ \u0026#948;t \u0026#916;t) (- current-value previous-value))))\n                    current-value))])\n         (channel-set! current-values current-value)\n         current-value)))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003einstant-curve\u003c/span\u003e a \u0026#916;x)\n  \u0026#916;x)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003elinear-curve\u003c/span\u003e a \u0026#916;x)\n  (* a \u0026#916;x))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003equadratic-curve\u003c/span\u003e a \u0026#916;x)\n  (* (expt a 4.0) \u0026#916;x))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003einstant-transition\u003c/span\u003e (cut transition instant-curve unit \u0026lt;\u0026gt;))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003elinear-transition\u003c/span\u003e (cut transition linear-curve \u0026lt;\u0026gt; \u0026lt;\u0026gt;))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003equadratic-transition\u003c/span\u003e (cut transition quadratic-curve \u0026lt;\u0026gt; \u0026lt;\u0026gt;))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/transition\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org006427d\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org006427d\"\u003e\u003cspan class=\"section-number-3\"\u003e4.4\u003c/span\u003e Metronome\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-4-4\"\u003e\n\u003cp\u003e\nMetronome is a mean to align scheduling with some periodic beat.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org2937f2b\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;beat\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003etime-\u0026gt;beat\u003c/span\u003e time bpm)\n  (-\u0026gt; time (* bpm) (/ 60) (round)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ebeat-\u0026gt;time\u003c/span\u003e beat bpm)\n  (-\u0026gt; beat (* 60) (/ bpm)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003enext-beat\u003c/span\u003e time bpm)\n  (beat-\u0026gt;time (+ 1 (time-\u0026gt;beat time bpm)) bpm))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emetro\u003c/span\u003e bpm . args)\n  (apply schedule (next-beat (now) bpm) args))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*bpm*\u003c/span\u003e 60.0)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eset-bpm!\u003c/span\u003e bpm)\n  (set! *bpm* bpm))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*beat*\u003c/span\u003e)\n  (time-\u0026gt;beat (now) *bpm*))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*metro*\u003c/span\u003e . args)\n  (apply metro *bpm* args))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/beat\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orge56cf93\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orge56cf93\"\u003e\u003cspan class=\"section-number-3\"\u003e4.5\u003c/span\u003e Control signals\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-4-5\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org0454920\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;control-signal\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-control\u003c/span\u003e x)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([b (box x)])\n    (values (~\u0026lt; (unbox b)) b)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine-syntax\u003c/span\u003e (\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003edefine-control\u003c/span\u003e stx)\n  (\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003econstruct-name\u003c/span\u003e\n    (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e (template-identifier . args)\n      (datum-\u0026gt;syntax\n       template-identifier\n       (string-\u0026gt;symbol\n        (apply string-append\n               (\u003cspan style=\"font-weight: bold;\"\u003emap\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e (x)\n                      (\u003cspan style=\"font-weight: bold;\"\u003eif\u003c/span\u003e (string? x)\n                          x\n                          (symbol-\u0026gt;string (syntax-\u0026gt;datum x))))\n                    args))))))\n  (syntax-case stx ()\n    [(_ name initial-value)\n     (with-syntax ([s (construct-name #'name #'name '~)]\n                   [ref (construct-name #'name #'name '-ref)]\n                   [set (construct-name #'name #'name '-set!)])\n       #'(\u003cspan style=\"font-weight: bold;\"\u003ebegin\u003c/span\u003e\n           (\u003cspan style=\"font-weight: bold;\"\u003edefine-values\u003c/span\u003e (s name) (make-control initial-value))\n           (\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eref\u003c/span\u003e) (unbox name))\n           (\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eset\u003c/span\u003e value) (set-box! name value))))]))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/control-signal\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nHand by hand with control signal go various measurements. For them\nsignal-proxy \u003ccode\u003ewindow\u003c/code\u003e is very useful. It's result also could be used as the\ninput table for \u003ccode\u003eosc:sampler\u003c/code\u003e.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgaec263f\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;window\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ewindow\u003c/span\u003e width signal)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([windows (make-vector *channels*)]\n        [N (-\u0026gt; width (* *sample-rate*) (ceiling) (exact))]\n        [cursor -1])\n    (do-ec (: i *channels*)\n           (vector-set! windows i (make-vector N 0.0)))\n    (values\n     (~\u0026lt;\n      (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e (zero? channel)\n        (set! cursor (mod (+ cursor 1) N)))\n      (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([sample (\u0026lt;~ signal)]\n            [window (channel-ref windows)])\n        (vector-set! window cursor sample)\n        sample))\n     (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e () windows))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/window\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgd4e35bd\" class=\"outline-2\"\u003e\n\u003ch2 id=\"orgd4e35bd\"\u003e\u003cspan class=\"section-number-2\"\u003e5\u003c/span\u003e Std\u003c/h2\u003e\n\u003cdiv class=\"outline-text-2\" id=\"text-5\"\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-orgac328ce\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgac328ce\"\u003e\u003cspan class=\"section-number-3\"\u003e5.1\u003c/span\u003e FFT\u003c/h3\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-orgecc153e\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgecc153e\"\u003e\u003cspan class=\"section-number-3\"\u003e5.2\u003c/span\u003e Filters\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-5-2\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgcc23667\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;delay\u0026gt;\u003c/span\u003e\n(define~ (\u003cspan style=\"font-weight: bold;\"\u003edelay\u003c/span\u003e \u0026#916;t f)\n  (f (- time (\u0026lt;~ \u0026#916;t)) channel))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/delay\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgbb4a2b0\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;echo\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*max-line-duration-slow*\u003c/span\u003e 10)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*max-line-duration-fast*\u003c/span\u003e 1)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-echo\u003c/span\u003e max-line-duration)\n  (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003edelay\u003c/span\u003e feedback signal)\n    (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([line-size (* max-line-duration *sample-rate*)]\n          [lines (make-channel-vector)]\n          [cursor -1])\n      (\u003cspan style=\"font-weight: bold;\"\u003edo\u003c/span\u003e ([channel 0 (+ channel 1)])\n          ((= channel *channels*) 0)\n        (channel-set! lines (make-vector line-size 0.0)))\n      (~\u0026lt;\n       (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e(zero? channel)\n         (set! cursor (mod (+ cursor 1) line-size)))\n       (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([line (channel-ref lines)]\n             [x (\u0026lt;~ signal)]\n             [delay (flonum-\u0026gt;fixnum (round (* (\u0026lt;~ delay) *sample-rate*)))]\n             [feedback (\u0026lt;~ feedback)])\n         (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([i (mod (+ line-size (- cursor delay)) line-size)]\n                [y (vector-ref line i)]\n                [z (+ x (* feedback y))])\n           (vector-set! line cursor z)\n           z))))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eecho\u003c/span\u003e (make-echo *max-line-duration-fast*))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eecho*\u003c/span\u003e (make-echo *max-line-duration-slow*))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/echo\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org7176f17\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;lpf\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003elpf-frequency-\u0026gt;\u0026#945;\u003c/span\u003e frequency)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([k (* frequency *sample-angular-period*)])\n    (/ k (+ k 1))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003elpf\u003c/span\u003e frequency x)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([ys (make-channel-vector 0.0)])\n    (~\u0026lt;\n     (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([y-1 (channel-ref ys)]\n            [\u0026#945; (lpf-frequency-\u0026gt;\u0026#945; (\u0026lt;~ frequency))])\n       (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([y (+ y-1 (* \u0026#945; (- (\u0026lt;~ x) y-1)))])\n         (channel-set! ys y)\n         y)))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/lpf\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orga3e45ab\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;hpf\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ehpf-frequency-\u0026gt;\u0026#945;\u003c/span\u003e frequency)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([k (* frequency *sample-angular-period*)])\n    (/ (+ k 1))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003ehpf\u003c/span\u003e frequency x)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([xs (make-channel-vector 0.0)]\n        [ys (make-channel-vector 0.0)])\n    (~\u0026lt;\n     (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([x-1 (channel-ref xs)]\n           [y-1 (channel-ref ys)]\n           [x (\u0026lt;~ x)]\n           [\u0026#945; (hpf-frequency-\u0026gt;\u0026#945; (\u0026lt;~ frequency))])\n       (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([y (* \u0026#945; (+ y-1 (- x x-1)))])\n         (channel-set! xs x)\n         (channel-set! ys y)\n         y)))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/hpf\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orga78d73d\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;make-biquad-filter\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-biquad-filter\u003c/span\u003e make-coefficients)\n  (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (Q frequency x)\n    (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([xs-1 (make-channel-vector 0.0)]\n          [xs-2 (make-channel-vector 0.0)]\n          [ys-1 (make-channel-vector 0.0)]\n          [ys-2 (make-channel-vector 0.0)])\n      (~\u0026lt;\n       (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([x-1 (channel-ref xs-1)]\n             [x-2 (channel-ref xs-2)]\n             [y-1 (channel-ref ys-1)]\n             [y-2 (channel-ref ys-2)]\n             [x (\u0026lt;~ x)]\n             [Q (\u0026lt;~ Q)]\n             [frequency (\u0026lt;~ frequency)])\n         (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([\u0026#969; (* frequency *sample-angular-period*)]\n                [sin-\u0026#969; (sin \u0026#969;)]\n                [cos-\u0026#969; (cos \u0026#969;)]\n                [\u0026#945; (/ sin-\u0026#969; (* 2.0 Q))])\n           (\u003cspan style=\"font-weight: bold;\"\u003elet-values\u003c/span\u003e ([(b0 b1 b2 a0 a1 a2) (make-coefficients sin-\u0026#969; cos-\u0026#969; \u0026#945;)])\n             (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([y (-\n                       (+\n                        (* (/ b0 a0) x)\n                        (* (/ b1 a0) x-1)\n                        (* (/ b2 a0) x-2))\n                       (* (/ a1 a0) y-1)\n                       (* (/ a2 a0) y-2))])\n               (channel-set! xs-1 x)\n               (channel-set! xs-2 x-1)\n               (channel-set! ys-1 y)\n               (channel-set! ys-2 y-1)\n               y))))))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/make-biquad-filter\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgaedbe1e\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;biquad-lpf\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-lpf-coefficients\u003c/span\u003e sin-\u0026#969; cos-\u0026#969; \u0026#945;)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([b0 (* 0.5 (- 1.0 cos-\u0026#969;))])\n    (values\n     b0             \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eb0\u003c/span\u003e\n     (- 1.0 cos-\u0026#969;)  \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eb1\u003c/span\u003e\n     b0             \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eb2\u003c/span\u003e\n     (+ 1.0 \u0026#945;)      \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ea0\u003c/span\u003e\n     (* -2.0 cos-\u0026#969;) \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ea1\u003c/span\u003e\n     (- 1.0 \u0026#945;)      \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ea2\u003c/span\u003e\n     )))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003ebiquad-lpf\u003c/span\u003e (make-biquad-filter make-lpf-coefficients))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/biquad-lpf\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org9376b39\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;biquad-hpf\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-hpf-coefficients\u003c/span\u003e sin-\u0026#969; cos-\u0026#969; \u0026#945;)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([b0 (* 0.5 (+ 1.0 cos-\u0026#969;))])\n    (values\n     b0             \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eb0\u003c/span\u003e\n     (- -1.0 cos-\u0026#969;) \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eb1\u003c/span\u003e\n     b0             \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003eb2\u003c/span\u003e\n     (+ 1.0 \u0026#945;)      \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ea0\u003c/span\u003e\n     (* -2.0 cos-\u0026#969;) \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ea1\u003c/span\u003e\n     (- 1.0 \u0026#945;)      \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ea2\u003c/span\u003e\n     )))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003ebiquad-hpf\u003c/span\u003e (make-biquad-filter make-hpf-coefficients))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/biquad-hpf\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgbac777e\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgbac777e\"\u003e\u003cspan class=\"section-number-3\"\u003e5.3\u003c/span\u003e Instruments\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-5-3\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org047e853\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;polyphony\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-polyphony\u003c/span\u003e n make-voice)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([voices (make-vector n \u0026#8709;)]\n        [cursor 0])\n    (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([signal\n           (apply mix (list-ec (: i n) (~\u0026lt; (\u0026lt;~ (vector-ref voices i)))))]\n          [play-note\n           (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e args\n             (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([voice (apply make-voice args)])\n               (vector-set! voices cursor voice)\n               (set! cursor (mod (+ cursor 1) n))\n               voice))])\n      (values signal play-note))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-static-polyphony\u003c/span\u003e n make-voice)\n  \u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(make-voice) -\u0026gt; (list signal play-note)\u003c/span\u003e\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([voices (list-ec (: i n) (make-voice))]\n        [cursor 0])\n    (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([signal (apply mix (\u003cspan style=\"font-weight: bold;\"\u003emap\u003c/span\u003e first voices))]\n          [play-note\n           (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e args\n             (apply (second (vector-ref voices cursor)) args)\n             (set! cursor (mod (+ cursor 1) n)))])\n      (values signal play-note))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/polyphony\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\n\u003cdiv id=\"outline-container-orgb22d8bc\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgb22d8bc\"\u003e\u003cspan class=\"section-number-3\"\u003e5.4\u003c/span\u003e Scales\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-5-4\"\u003e\n\u003cp\u003e\nWe are going to represent scales with Scheme's basic data structure, list.\nAnd the most basic operation which we want to perform on scale is chosing a\nnote from it without worrying about falling out of range:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgf4c3b5e\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;choice\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003echoice\u003c/span\u003e list n)\n  (list-ref list (mod n (length list))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003erandom-choice\u003c/span\u003e list)\n  (list-ref list (random (length list))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/choice\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nBasic intervals from Western music.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org5a8b4a3\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;intervals\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003echromatic-scale-half-step\u003c/span\u003e\n  (expt 2 1/12))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003esecond-interval\u003c/span\u003e (expt chromatic-scale-half-step 2))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003ethird-interval\u003c/span\u003e (expt chromatic-scale-half-step 4))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eperfect-fourth-interval\u003c/span\u003e (expt chromatic-scale-half-step 5))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eperfect-fifth-interval\u003c/span\u003e (expt chromatic-scale-half-step 7))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003emajor-sixth-interval\u003c/span\u003e (expt chromatic-scale-half-step 9))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003emajor-seventh-interval\u003c/span\u003e (expt chromatic-scale-half-step 11))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eperfect-octave-interval\u003c/span\u003e (expt chromatic-scale-half-step 12))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eminor-second-interval\u003c/span\u003e (expt chromatic-scale-half-step 1))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eminor-third-interval\u003c/span\u003e (expt chromatic-scale-half-step 3))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eminor-sixth-interval\u003c/span\u003e (expt chromatic-scale-half-step 8))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eminor-seventh-interval\u003c/span\u003e (expt chromatic-scale-half-step 11))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003etriton-interval\u003c/span\u003e (expt chromatic-scale-half-step 11))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/intervals\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nSome basic scales from Western music.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org1b7fb35\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;scales\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003echromatic-scale\u003c/span\u003e '(1 2 3 4 5 6 7 8 9 10 11 12))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003epentatonic-scale\u003c/span\u003e '(1 3 5 8 10))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003emajor-scale\u003c/span\u003e '(1 3 5 6 8 10 12))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003eminor-scale\u003c/span\u003e '(1 3 4 6 8 9 11))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-scale\u003c/span\u003e base-frequency scale)\n  (\u003cspan style=\"font-weight: bold;\"\u003emap\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (x) (* base-frequency (expt chromatic-scale-half-step (- x 1)))) scale))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/scales\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-orgf4ede71\" class=\"outline-3\"\u003e\n\u003ch3 id=\"orgf4ede71\"\u003e\u003cspan class=\"section-number-3\"\u003e5.5\u003c/span\u003e Rhythm\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-5-5\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org57ad369\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;pattern\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eplay-pattern\u003c/span\u003e pattern sound beat)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([n (length pattern)])\n    (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e (positive? (choice pattern (exact beat)))\n      (sound))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/pattern\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\n\u003cdiv id=\"outline-container-org5e66f64\" class=\"outline-3\"\u003e\n\u003ch3 id=\"org5e66f64\"\u003e\u003cspan class=\"section-number-3\"\u003e5.6\u003c/span\u003e MIDI\u003c/h3\u003e\n\u003cdiv class=\"outline-text-3\" id=\"text-5-6\"\u003e\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org387e454\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;midi\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*on-note-on*\u003c/span\u003e timestamp data1 data2 channel)\n  (printf \u003cspan style=\"font-style: italic;\"\u003e\"~s:~s:~s:~s\\r\\n\"\u003c/span\u003e timestamp data1 data2 channel))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*on-note-off*\u003c/span\u003e timestamp data1 data2 channel)\n  (printf \u003cspan style=\"font-style: italic;\"\u003e\"~s:~s:~s:~s\\r\\n\"\u003c/span\u003e timestamp data1 data2 channel))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003e*on-cc*\u003c/span\u003e timestamp data1 data2 channel)\n  (printf \u003cspan style=\"font-style: italic;\"\u003e\"~s:~s:~s:~s\\r\\n\"\u003c/span\u003e timestamp data1 data2 channel))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eset-note-on!\u003c/span\u003e f) (set! *on-note-on* f))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eset-note-off!\u003c/span\u003e f) (set! *on-note-off* f))\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eset-cc!\u003c/span\u003e f) (set! *on-cc* f))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*polling-cycle*\u003c/span\u003e 0.005)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*stream*\u003c/span\u003e #f)\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e \u003cspan style=\"font-weight: bold;\"\u003e*scheduler*\u003c/span\u003e #f)\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eprocess-event\u003c/span\u003e timestamp type data1 data2 channel)\n  (\u003cspan style=\"font-weight: bold;\"\u003econd\u003c/span\u003e\n    [(= type pm:*midi-note-on*) (*on-note-on* timestamp data1 data2 channel)]\n    [(= type pm:*midi-note-off*) (*on-note-off* timestamp data1 data2 channel)]\n    [(= type pm:*midi-cc*) (*on-cc* timestamp data1 data2 channel)]\n    [else (printf \u003cspan style=\"font-style: italic;\"\u003e\"Unsupported event type: ~s\\r\\n\"\u003c/span\u003e type)]))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-safe-process-event\u003c/span\u003e timestamp)\n  (\u003cspan style=\"font-weight: bold;\"\u003elambda\u003c/span\u003e args\n    (\u003cspan style=\"font-weight: bold;\"\u003eguard\u003c/span\u003e (_ [else #f]) (apply process-event timestamp args))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eprocess-events\u003c/span\u003e)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([timestamp (scheduler:now *scheduler*)])\n    (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e (pm:poll *stream*)\n      (pm:read *stream* (make-safe-process-event timestamp)))\n    (scheduler:schedule *scheduler*\n                        (+ timestamp *polling-cycle*)\n                        process-events)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estart\u003c/span\u003e now)\n  (\u003cspan style=\"font-weight: bold;\"\u003eunless\u003c/span\u003e *stream*\n    (pm:init)\n    (set! *stream* (pm:open-input 0))\n    (set! *scheduler* (scheduler:simple-scheduler now))\n    (scheduler:start-scheduler *scheduler*)\n    (process-events)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003estop\u003c/span\u003e)\n  (\u003cspan style=\"font-weight: bold;\"\u003ewhen\u003c/span\u003e *stream*\n    (scheduler:stop-scheduler *scheduler*)\n    (pm:close *stream*)\n    (pm:terminate)\n    (set! *stream* #f)\n    (set! *scheduler* #f)))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/midi\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv id=\"outline-container-org499e186\" class=\"outline-2\"\u003e\n\u003ch2 id=\"org499e186\"\u003e\u003cspan class=\"section-number-2\"\u003e6\u003c/span\u003e Misc\u003c/h2\u003e\n\u003cdiv class=\"outline-text-2\" id=\"text-6\"\u003e\n\u003cp\u003e\nTo import \u003ccode\u003echez-soundio\u003c/code\u003e and \u003ccode\u003echez-sockets\u003c/code\u003e we must add respective folders to\n\u003ccode\u003elibrary-directories\u003c/code\u003e To do that let's create a couple of helpers:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgc5775b4\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;add-library-directories\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eadd-library-directory\u003c/span\u003e dir)\n  (library-directories\n   (cons dir (library-directories))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eadd-library-directories\u003c/span\u003e . dirs)\n  (\u003cspan style=\"font-weight: bold;\"\u003eunless\u003c/span\u003e (null? dirs)\n    (add-library-directory (car dirs))\n    (apply add-library-directories (cdr dirs))))\n\n(add-library-directories\n \u003cspan style=\"font-style: italic;\"\u003e\"./chez-soundio\"\u003c/span\u003e\n \u003cspan style=\"font-style: italic;\"\u003e\"./chez-portmidi\"\u003c/span\u003e\n \u003cspan style=\"font-style: italic;\"\u003e\"./chez-sockets\"\u003c/span\u003e)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/add-library-directories\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nAlso let's define several useful aliases and finally start our services:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org12ea47d\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;ad-libitum-init\u0026gt;\u003c/span\u003e\n(alias now sound:now)\n(alias schedule scheduler:*schedule*)\n(alias callback schedule)\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003ein case of emergency \u0026#9786;\u003c/span\u003e\n(alias hush! sound:hush!)\n(alias h! hush!)\n\n(alias play! sound:set-dsp!)\n\n(sound:start)\n(scheduler:init now)\n(scheduler:start)\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(repl:start-repl-server)\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/ad-libitum-init\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nTuner stuff to test everything is working:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orgf87602c\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;test-tuner\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003etuner\u003c/span\u003e time channel)\n  (sin (* 2\u0026#960; time tuner-frequency)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003equick-test\u003c/span\u003e signal)\n  (signal (random 1.0) (random *channels*)))\n\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e(sound:set-dsp! tuner)\u003c/span\u003e\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/test-tuner\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nSome useful conversions, see TTEM.org for more details.\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"orga5f71d2\"\u003e(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003eamp-\u0026gt;dB\u003c/span\u003e x)\n  (* 20.0 (log x 10.0)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003edB-\u0026gt;amp\u003c/span\u003e x)\n  (expt 10.0 (/ x 20.0)))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emidi-pitch-\u0026gt;frequency\u003c/span\u003e m)\n  (* 440.0 (expt 2.0 (/ (- m 69.0) 12.0))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003efrequency-\u0026gt;midi-pitch\u003c/span\u003e f)\n  (+ 69 (exact (round (* 12.0 (log (/ f 440.0) 2.0))))))\n\u003c/pre\u003e\n\u003c/div\u003e\n\n\u003cp\u003e\nSome stuff about time and scales to be moved to appropriate sections when\nwe'll come to them:\n\u003c/p\u003e\n\n\u003cdiv class=\"org-src-container\"\u003e\n\u003cpre class=\"src src-scheme\" id=\"org266d4bf\"\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;sandbox\u0026gt;\u003c/span\u003e\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003emake-overtone\u003c/span\u003e amplitudes wave frequency phase0)\n  (\u0026#8721; (\u003cspan style=\"font-weight: bold;\"\u003emap\u003c/span\u003e\n      (\u003cspan style=\"font-weight: bold;\"\u003e\u0026#955;\u003c/span\u003e (amplitude factor)\n        (\u003cspan style=\"font-weight: bold;\"\u003elet\u003c/span\u003e ([factor (inexact factor)])\n          (*~ amplitude\n              (wave (osc:phasor (*~ (~\u0026lt; factor) frequency) phase0)))))\n      amplitudes\n      (iota (length amplitudes)))))\n\n(\u003cspan style=\"font-weight: bold;\"\u003edefine\u003c/span\u003e (\u003cspan style=\"font-weight: bold;\"\u003efix-duration\u003c/span\u003e duration)\n  (\u003cspan style=\"font-weight: bold;\"\u003elet*\u003c/span\u003e ([start (now)]\n         [end (+ start duration)])\n    (values (~\u0026lt; start) (~\u0026lt; end))))\n\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e;; \u003c/span\u003e\u003cspan style=\"font-weight: bold; font-style: italic;\"\u003e\u0026lt;/sandbox\u0026gt;\u003c/span\u003e\n\u003c/pre\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003c/div\u003e\n\u003cdiv id=\"postamble\" class=\"status\"\u003e\n\u003cp class=\"author\"\u003eAuthor: Ruslan Prakapchuk\u003c/p\u003e\n\u003cp class=\"date\"\u003eCreated: 2021-09-20 Mon 09:10\u003c/p\u003e\n\u003cp class=\"validation\"\u003e\u003ca href=\"https://validator.w3.org/check?uri=referer\"\u003eValidate\u003c/a\u003e\u003c/p\u003e\n\u003c/div\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ful%2Fad-libitum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ful%2Fad-libitum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ful%2Fad-libitum/lists"}