tidal.html98 lines · 3.1 KB · raw
1<!doctype html>
2<html lang="en">
3  <head>
4    <meta charset="UTF-8" />
5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6    <title>tidal.html</title>
7  </head>
8  <body style="margin: 0; padding: 0">
9    <textarea id="code" style="width: 100%; height: 200px"></textarea>
10    <pre id="result"></pre>
11    <script src="https://unpkg.com/hs2js@0.0.8"></script>
12    <script src="https://unpkg.com/@strudel/web@1.0.3"></script>
13    <script>
14      const { initStrudel } = strudel;
15      const { run, parse, setBase, loadParser } = hs2js;
16      setBase('https://unpkg.com/hs2js@0.0.4/dist/');
17      const ready = loadParser();
18      initStrudel({
19        prebake: () => samples('github:tidalcycles/dirt-samples'),
20      });
21
22      const textarea = document.getElementById('code');
23      if (window.location.hash) {
24        textarea.value = atob(window.location.hash.slice(1));
25      } else {
26        textarea.value = 'd1 $ s "jvbass(3,8)"';
27      }
28      textarea.addEventListener('input', (e) => {
29        window.location.hash = btoa(e.target.value);
30        update();
31      });
32      update();
33
34      function getInfixOperators() {
35        let operators = {
36          '>': 'set',
37          '#': 'set',
38          '+': 'add',
39          '-': 'sub',
40          '*': 'mul',
41          '/': 'div',
42        };
43        let alignments = {
44          in: (s) => '|' + s,
45          out: (s) => s + '|',
46          mix: (s) => '|' + s + '|',
47        };
48        let ops = {};
49        Object.entries(operators).forEach(([o, name]) => {
50          // operator without alignment
51          ops[o] = (l, r) => reify(l)[name](reify(r));
52          Object.entries(alignments).forEach(([a, getSymbol]) => {
53            // get symbol with alignment
54            let symbol = getSymbol(o);
55            ops[symbol] = (l, r) => reify(l)[name][a](reify(r));
56          });
57        });
58        ops['~>'] = (l, r) => reify(l).late(reify(r));
59        ops['<~'] = (l, r) => reify(l).early(reify(r));
60        ops['<$>'] = (l, r) => reify(r).fmap(l).outerJoin(); // is this right?
61        return ops;
62      }
63      const ops = getInfixOperators();
64
65      async function update() {
66        let result, tree;
67        await ready;
68        try {
69          tree = parse(textarea.value);
70        } catch (err) {
71          console.warn('parse error');
72          console.error(err);
73        }
74        console.log('parsed tree');
75        console.log(tree.rootNode.toString());
76        try {
77          let patterns = {};
78          window.p = (name, pattern) => {
79            patterns[name] = pattern;
80          };
81          window.d1 = (pat) => window.p(1, pat);
82          window.d2 = (pat) => window.p(2, pat);
83          window.d3 = (pat) => window.p(3, pat);
84          window.rot = late;
85          result = run(tree.rootNode, window, ops);
86          if (Object.values(patterns).length) {
87            stack(...Object.values(patterns)).play();
88          }
89        } catch (err) {
90          console.warn('eval error');
91          console.error(err);
92          result = 'ERROR: ' + err.message;
93        }
94        document.getElementById('result').innerHTML = 'Result: ' + result;
95      }
96    </script>
97  </body>
98</html>