Compare commits

..

460 Commits

Author SHA1 Message Date
Felix Roos b04a262433 Publish
- @strudel/codemirror@0.11.0
 - @strudel/core@0.11.0
 - @strudel/csound@0.11.0
 - @strudel/embed@0.11.0
 - @strudel/hydra@0.11.0
 - @strudel/midi@0.11.0
 - @strudel/mini@0.11.0
 - @strudel/osc@0.11.0
 - @strudel/repl@0.11.0
 - @strudel/serial@0.11.0
 - @strudel/soundfonts@0.11.0
 - @strudel/tonal@0.11.0
 - @strudel/transpiler@0.11.0
 - @strudel/web@0.11.0
 - @strudel/webaudio@0.11.0
 - @strudel/xen@0.11.0
2024-01-18 09:59:57 +01:00
Felix Roos 96bafa7f0b the big rename: @strudel.cycles/* -> @strudel/* 2024-01-18 09:54:37 +01:00
Felix Roos b10612da5c Publish
- @strudel/codemirror@0.10.0
 - @strudel.cycles/core@0.10.0
 - @strudel.cycles/csound@0.10.0
 - @strudel.cycles/embed@0.10.0
 - @strudel/hydra@0.10.0
 - @strudel.cycles/midi@0.10.0
 - @strudel.cycles/mini@0.10.0
 - @strudel.cycles/osc@0.10.0
 - @strudel/repl@0.10.0
 - @strudel.cycles/serial@0.10.0
 - @strudel.cycles/soundfonts@0.10.0
 - superdough@0.10.0
 - @strudel.cycles/tonal@0.10.0
 - @strudel.cycles/transpiler@0.10.0
 - @strudel/web@0.10.0
 - @strudel.cycles/webaudio@0.10.0
 - @strudel.cycles/xen@0.10.0
2024-01-18 09:35:20 +01:00
Felix Roos 171f4206a8 Merge branch 'main' into deprecate-old-package-names 2024-01-18 09:33:16 +01:00
Felix Roos bd83d19197 Merge pull request #913 from tidalcycles/pitch-envelopes
pitch envelope
2024-01-18 06:54:33 +01:00
Felix Roos 95cf201c6d fix: heading 2024-01-18 06:49:09 +01:00
Felix Roos 4107711dae snapshot 2024-01-18 06:48:21 +01:00
Felix Roos 67f0758cb5 document pitch envelope 2024-01-18 06:47:54 +01:00
Felix Roos 1c99944a32 pitch envelope now also works when setting one of the controls (penv not needed) 2024-01-18 06:47:44 +01:00
Felix Roos d3ea4959b4 - more flexible pitch envelopes
- fix: exponential envelopes could break due to 0 values
2024-01-18 06:47:12 +01:00
Felix Roos 70b27fbff2 Merge pull request #916 from oscarbyrne/fix-swatch-static-paths
Fix: swatch/[name].png.js static path
2024-01-18 05:09:38 +01:00
Oscar Byrne 96c2144857 Use astro Response class for swatch/[name].png.js endpoint 2024-01-17 17:09:11 -08:00
Felix Roos 0655af4d4f add pcurve 2024-01-17 17:35:35 +01:00
Felix Roos 3fc0fdbe62 remove todo 2024-01-16 17:57:52 +01:00
Felix Roos fd73571744 make sure the sustained pitch is the selected note 2024-01-16 17:56:38 +01:00
Felix Roos 80d861c12c Merge pull request #907 from fnordomat/more-vowels
Add more vowel qualities for the vowels function
2024-01-16 08:22:27 +01:00
Felix Roos 3506de8d1a vibrato for soundfonts
+ add getVibratoOscillator helper
2024-01-16 00:07:56 +01:00
Felix Roos 32456d6966 pitch envelope for sampler and soundfonts
+ added getPitchEnvelope helper
2024-01-15 23:55:49 +01:00
Felix Roos bdc2af9733 basic pitch envelope 2024-01-15 23:25:22 +01:00
Felix Roos a7daf41934 Merge pull request #911 from tidalcycles/blog
adds a blog
2024-01-14 23:56:36 +01:00
Felix Roos fe6ff2528a Merge pull request #894 from rjulian/feat/add-header-workshop
Remove hideHeader for better mobile UI and consistency
2024-01-14 23:52:41 +01:00
Felix Roos 7ceb8708b0 fix: do not format autogenerated file 2024-01-14 23:47:50 +01:00
Felix Roos 4d22d957a1 add more videos to showcase 2024-01-14 23:45:39 +01:00
Felix Roos 79f1a863b6 add date + author to posts + dedupe headings 2024-01-14 23:39:03 +01:00
Felix Roos 98db3d37ef add anchor links 2024-01-14 23:30:26 +01:00
Felix Roos c02976782b add video component 2024-01-14 23:22:10 +01:00
Felix Roos ceb4376eb8 format autogenerated types 2024-01-14 23:16:44 +01:00
Felix Roos 0566b7bcb3 basic blog with release notes 2024-01-14 23:16:09 +01:00
Jade (Rose) Rowland 6d0ecb9f5e Merge pull request #868 from daslyfe/envelope_improvements
Further Envelope improvements
2024-01-14 16:43:06 -05:00
Felix Roos 0901948564 fanchor default to 0.5 for now 2024-01-14 21:32:38 +01:00
Felix Roos e6d028fd6b soundfont mixing 2024-01-14 16:27:11 +01:00
Alex McLean 945e7082cd Update metadata.mdx 2024-01-14 10:15:40 +00:00
Alex McLean 0d6bdfb514 Link to creative commons chooser 2024-01-14 10:14:43 +00:00
fnordomat 70712bdab6 fix codeformat 2024-01-14 10:19:49 +01:00
Felix Roos 53771d7f95 hotfix: avoid crash for anonymous patterns 2024-01-14 01:50:48 +01:00
Felix Roos 6d32d4024d hotfix: fix built version loading at runtime.. 2024-01-14 01:08:01 +01:00
Felix Roos f387589342 hotfix: fix build error 2024-01-14 00:53:43 +01:00
Felix Roos 47a5080352 Merge pull request #910 from tidalcycles/browse
public sharing
2024-01-14 00:48:03 +01:00
Felix Roos 5314c83534 delete browse page for now 2024-01-14 00:02:27 +01:00
Felix Roos 204c964050 integrate public patterns into patterns tab 2024-01-13 23:53:46 +01:00
Felix Roos 1ede99f71e ask for public sharing (very cheap) + order browse list 2024-01-13 23:12:22 +01:00
Felix Roos 3c1844046a basic browse page 2024-01-13 23:01:16 +01:00
Felix Roos eefa90a2bc fix: synth default envelope 2024-01-13 22:24:59 +01:00
fnordomat efa0737660 added some aliases for the vowels (cosmetics) 2024-01-13 15:11:30 +01:00
fnordomat 6232560273 document extra vowels in quick reference 2024-01-13 11:11:31 +01:00
fnordomat e051d383a0 add 10 new vowel qualities to formant table 2024-01-13 11:11:31 +01:00
Felix Roos 4fb5c1828d i have no clue why this works 2024-01-13 01:16:26 +01:00
Felix Roos 6f3b2fa66b negative fenv values now stay in the same range as positives 2024-01-13 00:26:16 +01:00
Felix Roos f17459fdc3 Merge branch 'main' into envelope_improvements 2024-01-12 19:41:05 +01:00
Felix Roos a053f40e59 Merge pull request #902 from tidalcycles/build-warnings
fix some build warnings
2024-01-12 18:31:41 +01:00
Felix Roos 9a0459fdd3 move non pages out of pages dir 2024-01-12 18:16:57 +01:00
Felix Roos 46a859736a Merge pull request #891 from daslyfe/remove_jsx_exports_for_vite
prevent vite from complaining about additional exports in jsx files
2024-01-12 18:01:55 +01:00
Felix Roos e4524a2be9 Merge pull request #892 from daslyfe/update_vite
Update Vite version so hot reload works properly with newest pnpm version
2024-01-12 17:05:46 +01:00
Felix Roos f3ee1cc947 Merge pull request #886 from tidalcycles/polymeter-slowcat
support , in < >
2024-01-12 15:09:40 +01:00
Felix Roos 86bc28dfb3 add deprecation notes 2024-01-11 20:46:22 +01:00
Felix Roos 1bc0934228 Merge branch 'main' into envelope_improvements 2024-01-10 15:15:22 +01:00
Felix Roos f26fd18c7a use 0.001 as linear mintime as well (to prevent cracks) 2024-01-10 15:02:10 +01:00
Felix Roos c68dba8c21 fix: use end 2024-01-10 14:28:38 +01:00
Felix Roos f768e1eece Merge pull request #898 from tidalcycles/fix-autocomplete
fix: autocomplete / tooltip code example bug
2024-01-10 13:55:39 +01:00
Felix Roos f99557cc05 fix: fanchor + default fanchor to 0 (breaking change) 2024-01-10 00:08:49 +01:00
Felix Roos f785823e00 add fenv to filter cutoff controls 2024-01-10 00:08:13 +01:00
Felix Roos 62cd2263c2 add silent flag to nanFallback 2024-01-10 00:03:18 +01:00
Felix Roos 7157634db0 fix: autocomplete / tooltip code example bug 2024-01-09 22:34:16 +01:00
Jade (Rose) Rowland 86442adb20 prettier 2024-01-06 15:09:09 -05:00
Richard Julian 569137eb22 Formatting for passing CI 2024-01-06 12:05:39 -08:00
Jade (Rose) Rowland 5e3a37c9e8 init 2024-01-06 14:55:45 -05:00
Richard Julian 4651066472 Remove hideHeader for better mobile UI and consistency 2024-01-06 11:55:00 -08:00
Jade (Rose) Rowland 8d325b96ea init 2024-01-06 14:49:52 -05:00
Felix Roos b52cb198b5 Merge pull request #889 from tidalcycles/invisible-selection
fix: invisible selection on vim + emacs mode
2024-01-06 15:23:55 +01:00
Felix Roos bcee6632af fix: invisible selection on vim + emacs mode 2024-01-06 15:21:58 +01:00
Jade (Rose) Rowland 150a1b8eed restore buffer hold behavior 2024-01-05 17:45:09 -05:00
Felix Roos 4c49b84213 Merge pull request #888 from tidalcycles/scale-anchors
scales can now be anchored
2024-01-05 22:29:20 +01:00
Felix Roos b27f177138 scales can now be anchored 2024-01-05 13:03:40 +01:00
Jade (Rose) Rowland b2f63897f9 change default FM env to exp because it modulates frequency and sounds way better :) 2024-01-05 01:07:54 -05:00
Jade (Rose) Rowland 2ee392be9b fixed all the things 2024-01-05 01:00:22 -05:00
Felix Roos f37652edb3 Merge pull request #887 from tidalcycles/root-voicings
add root mode for voicings
2024-01-04 11:21:42 +01:00
Felix Roos 27049eb706 add root mode for voicings
+ allow numbers as anchor
2024-01-04 11:02:13 +01:00
Felix Roos a2974099c1 add dec synonym for decay 2024-01-03 23:06:23 +01:00
Felix Roos 041a809b07 add ar function 2024-01-03 22:41:03 +01:00
Felix Roos 2ecc6b30aa add ad function 2024-01-03 22:37:35 +01:00
Felix Roos d582bbbb60 fix: format 2024-01-03 22:17:11 +01:00
Felix Roos ca3eda8fc7 support , in < > 2024-01-03 21:54:10 +01:00
Felix Roos 4d25e3b90b hotfix: Zach B-B 2024-01-03 00:23:28 +01:00
Jade (Rose) Rowland 83c820a18c prettier again 2024-01-01 18:50:23 -05:00
Jade (Rose) Rowland 3eface706c Merge branch 'tidalcycles:main' into envelope_improvements 2024-01-01 18:47:28 -05:00
Felix Roos 8d143f4bf1 Merge pull request #885 from tidalcycles/showcase
Showcase
2024-01-01 18:32:17 +01:00
Felix Roos 88fbd78492 fix: shuffle by default 2024-01-01 18:04:38 +01:00
Felix Roos 9a235a7c15 comment out chalmers vid 2024-01-01 17:59:54 +01:00
Felix Roos d99607ea14 add showcase 2024-01-01 17:56:29 +01:00
Felix Roos 5150ec06dc Merge pull request #882 from daslyfe/audio_device_selection
bugfix: suspend and close exisiting audio context when changing interface
2024-01-01 14:22:10 +01:00
Felix Roos b9f190562e Merge pull request #884 from tidalcycles/mastodon-links
add mastodon link
2024-01-01 14:21:52 +01:00
Felix Roos eb189d077d add mastodon link 2024-01-01 14:20:01 +01:00
Jade (Rose) Rowland 9756d63cf1 prettier 2023-12-31 11:58:06 -05:00
Jade (Rose) Rowland a800b32529 Merge branch 'main' into envelope_improvements 2023-12-31 11:51:49 -05:00
Jade (Rose) Rowland 8f56ef6507 suspend and close exisiting audio context 2023-12-31 11:39:14 -05:00
Felix Roos 92e0d09c28 Merge pull request #881 from tidalcycles/error-tolerance
fix: make sure n is never undefined before nanFallback
2023-12-31 17:02:57 +01:00
Felix Roos 64d80f98db fix: make sure n is never undefined before nanFallback 2023-12-31 16:59:45 +01:00
Felix Roos 01391d316b Merge pull request #880 from tidalcycles/error-tolerance
Error tolerance
2023-12-31 16:47:22 +01:00
Felix Roos 1d32da075d mini: tolerate non-breaking space (alt+spacebar on macos) 2023-12-31 16:44:35 +01:00
Felix Roos 9b32900b96 revert changing default voicing dict for now... 2023-12-31 16:27:35 +01:00
Felix Roos ecf837636b show line where mini notation parse errors happen 2023-12-31 15:06:30 +01:00
Felix Roos 5a76bc93b8 rename default dict to legacy 2023-12-31 14:19:16 +01:00
Felix Roos b14e5577b4 breaking: use ireal as default voicing dictionary
+ this has the big benefit that all chord symbols work by default without the need to specify a dict
2023-12-31 12:19:05 +01:00
Felix Roos 4121ac91ee fix: graceful handling of invalid chord symbols 2023-12-31 12:11:08 +01:00
Felix Roos c44f202c44 fix: scale errors safety net 2023-12-31 12:07:08 +01:00
Felix Roos 9059b16c7c fix: editor focus on click below code 2023-12-31 11:20:35 +01:00
Felix Roos 3760f51c3c Merge pull request #871 from daslyfe/bugfix_sample_select
bugfix: sound select indexes out of bounds
2023-12-31 10:06:24 +01:00
Felix Roos aa18293f1d Merge pull request #854 from daslyfe/audio_device_selection
Audio device selection
2023-12-31 10:03:00 +01:00
Jade (Rose) Rowland 63066937e9 remove leftover setting 2023-12-30 22:51:30 -05:00
Jade (Rose) Rowland 34f0d631d9 remove console statement 2023-12-30 22:44:40 -05:00
Jade (Rose) Rowland b3522fea6a prevent selection while playing to avoid artifacts 2023-12-30 22:40:27 -05:00
Felix Roos 2ae3ce53f3 hotfix: zen mode was broken 2023-12-31 01:19:46 +01:00
Felix Roos 2adacbd27b Merge pull request #879 from tidalcycles/dependency-update
Dependency update
2023-12-31 00:59:49 +01:00
Felix Roos 45eed1b7e7 fix: for some reason, ci fails without it... 2023-12-31 00:58:09 +01:00
Felix Roos b36d334f78 fix: duplicate pretest 2023-12-31 00:56:38 +01:00
Felix Roos bd648185bc use node 20 for deployment too + bump node types 2023-12-31 00:54:39 +01:00
Felix Roos 67f1dc32a5 bump node version for test 2023-12-31 00:52:01 +01:00
Felix Roos d47d9dadf4 fix: build
+ seems fraction.js now works with ssr
2023-12-31 00:45:04 +01:00
Felix Roos b52f8c2925 update remaining packages 2023-12-31 00:41:06 +01:00
Felix Roos 59ce624521 update webmidi + codemirror 2023-12-31 00:34:55 +01:00
Felix Roos 70b9fbfcf6 updates..
+ codemirror-themes
+ acorn + escodegen
+ supabase
2023-12-31 00:13:05 +01:00
Felix Roos 74b9279416 update eslint 2023-12-31 00:03:45 +01:00
Felix Roos c3ba8ee0fa update fraction js 2023-12-30 23:59:00 +01:00
Felix Roos 4f5ca0767d updates... 2023-12-30 23:50:30 +01:00
Felix Roos d0a1374d2f more updates.. 2023-12-30 23:43:54 +01:00
Felix Roos a747c976fe update nanostores 2023-12-30 23:26:27 +01:00
Felix Roos 94fcea1040 codeformat 2023-12-30 23:21:34 +01:00
Felix Roos 7db684e308 update lerna 2023-12-30 23:19:22 +01:00
Felix Roos 1981e1c34c update dependency-tree + prettier
+ rerun undocumented script
2023-12-30 23:15:44 +01:00
Felix Roos 5274508665 fix: wrong parens.. 2023-12-30 23:09:31 +01:00
Felix Roos 6f68bdcf5b update vite + astro 2023-12-30 23:08:15 +01:00
Felix Roos cf20f1059f Merge branch 'main' into dependency-update 2023-12-30 22:26:05 +01:00
Felix Roos 307c69edb9 hotfix: another slight logic error 2023-12-30 10:36:50 +01:00
Felix Roos 9a07b15952 hotfix: update button behavior 2023-12-30 10:07:47 +01:00
Jade (Rose) Rowland a178d310fd Merge branch 'tidalcycles:main' into bugfix_sample_select 2023-12-29 23:51:09 -05:00
Jade (Rose) Rowland 12451ba5fc Merge branch 'tidalcycles:main' into envelope_improvements 2023-12-29 22:27:52 -05:00
Jade (Rose) Rowland 69554c0762 merged with vanilla updates 2023-12-29 22:27:01 -05:00
Jade (Rose) Rowland 3152bc123a Merge branch 'main' into audio_device_selection 2023-12-29 20:37:29 -05:00
Felix Roos 4871abbd71 fix superdough example readme 2023-12-29 16:57:46 +01:00
Felix Roos bd2333377f Merge pull request #878 from tidalcycles/move-examples
move all examples to separate examples folder
2023-12-29 16:53:39 +01:00
Felix Roos 76aaedba66 lockfile 2023-12-29 16:50:58 +01:00
Felix Roos b0f316eecd add readme to examples folder 2023-12-29 16:49:05 +01:00
Felix Roos 49903abed7 better naming 2023-12-29 16:48:00 +01:00
Felix Roos d106875605 Merge branch 'main' into move-examples 2023-12-29 16:40:28 +01:00
Felix Roos c13feccdcd better names + more readme 2023-12-29 16:36:38 +01:00
Felix Roos 6aebf99ebc hotfix: panel style 2023-12-29 16:22:50 +01:00
Felix Roos 5d6ccf56d7 add some readme 2023-12-29 16:18:13 +01:00
Felix Roos 0323f75bae move all examples to separate examples folder 2023-12-29 16:05:10 +01:00
Felix Roos f31fdb0988 Merge pull request #876 from tidalcycles/vanilla-repl-4
final vanillification
2023-12-29 15:29:17 +01:00
Felix Roos 92024f68cf default panel position right 2023-12-29 15:26:47 +01:00
Felix Roos f9c1e46c01 delete outdated svg graphics 2023-12-29 15:17:00 +01:00
Felix Roos a5af6d5f4c remove gist function 2023-12-29 15:07:53 +01:00
Felix Roos b1d06c4eb7 remove nano-repl workspace 2023-12-29 15:04:12 +01:00
Felix Roos 89bf3b2817 fix: tooltip padding 2023-12-29 15:03:36 +01:00
Felix Roos ea8aabceed fix: loader 2023-12-29 15:03:26 +01:00
Felix Roos 9fd2d3d640 add missing flash checkbox 2023-12-29 13:58:06 +01:00
Felix Roos 967dea346f fix: lint error 2023-12-29 13:57:52 +01:00
Felix Roos 57bc0b7032 cleanup 2023-12-29 01:07:11 +01:00
Felix Roos 9974311344 better repl init + a bit of ssr for main repl 2023-12-29 00:55:14 +01:00
Felix Roos b0bdd09032 fix: dumb react ssr workaround 2023-12-29 00:30:46 +01:00
Felix Roos f477273d8a delete react package 2023-12-28 21:06:18 +01:00
Felix Roos 014303b0d5 remove dependencies to @strudel.cycles/react 2023-12-28 21:04:29 +01:00
Felix Roos 201fe726b6 replace main repl 2023-12-28 20:48:59 +01:00
Felix Roos 2ed3a5c582 fix: lint 2023-12-28 20:36:59 +01:00
Felix Roos 975a198ee9 whole docs now run new repl
- move MicroRepl code to MiniRepl
- fix a ssr bug
2023-12-28 20:36:23 +01:00
Felix Roos 837f8f318d microrepl claviature support 2023-12-28 19:40:01 +01:00
Felix Roos f96827d052 fix: initial highlighting 2023-12-28 18:03:50 +01:00
Felix Roos a9dc0912d0 fix: drawer performance issue 2023-12-28 17:54:51 +01:00
Jade (Rose) Rowland b5039ecce8 fix import 2023-12-28 10:19:20 -05:00
Felix Roos 624affe092 Merge pull request #874 from daslyfe/clock_drift
Bug Fix #119: Clock drift
2023-12-27 18:38:09 +01:00
Felix Roos 9b5842b20e hotfix: fix build error 2023-12-27 13:28:20 +01:00
Felix Roos edfa0c65f9 Merge pull request #873 from tidalcycles/vanilla-repl-3
main repl vanillification
2023-12-27 13:17:02 +01:00
Felix Roos 39e81aa77c reduce drawTime to fix perf (for now) 2023-12-27 12:46:10 +01:00
Felix Roos 8bde87246b load imported samples directly in prebake 2023-12-27 12:45:27 +01:00
Felix Roos e2a082f748 move repl2 to /next 2023-12-27 11:42:18 +01:00
Felix Roos d7c2cf562f fix: hot reloading 2023-12-27 11:40:07 +01:00
Felix Roos f44ceb46cd remove react-dom dependency 2023-12-26 18:26:51 +01:00
Felix Roos f524dde5ae tooltip without react + simplify autocomplete 2023-12-26 18:03:58 +01:00
Felix Roos 47aa4cf198 autocomplete without react 2023-12-26 17:56:07 +01:00
Felix Roos 1b55a5e3e0 add trailing slash 2023-12-26 17:55:08 +01:00
Jade (Rose) Rowland cb57d8f497 working 2023-12-25 20:42:20 -05:00
Jade (Rose) Rowland e12421cee8 still getting too late 2023-12-25 20:27:42 -05:00
Felix Roos 53484db768 style fixes + remove lastShared state 2023-12-26 00:29:43 +01:00
Felix Roos 4c337a5114 fix: lint errors 2023-12-26 00:06:59 +01:00
Felix Roos 63ae95186b repl2: share + clean up imports 2023-12-26 00:06:15 +01:00
Felix Roos 8c0065f563 pull out repl utility functions
+ repl2 initCode / switching patterns works now
2023-12-25 23:53:54 +01:00
Felix Roos 5c41d6789c checkbox for isPatternHighlightingEnabled 2023-12-25 21:11:28 +01:00
Felix Roos e19f799046 wire up settings and theming 2023-12-25 20:52:00 +01:00
Felix Roos 7dac1e275d repl2: working update + shuffle buttons + faster loading 2023-12-25 20:08:57 +01:00
Felix Roos d74d50c40a first steps of using StrudelMirror in main repl 2023-12-25 19:37:03 +01:00
Felix Roos 8b4be4d100 Merge pull request #866 from tidalcycles/vanilla-repl-2
more work on vanilla repl: repl web component + package
2023-12-25 17:47:25 +01:00
Felix Roos de4460a047 remove redundant test pages 2023-12-25 15:45:49 +01:00
Felix Roos 0ed615a312 fix: add .piano function 2023-12-25 15:32:12 +01:00
Felix Roos e8e8f888dd fix: stop other repls on start 2023-12-25 15:21:54 +01:00
Jade (Rose) Rowland 3776791239 working 2023-12-23 12:30:55 -05:00
Jade (Rose) Rowland 77fee0b866 fixed popping on font envelope 2023-12-20 17:39:11 -05:00
Jade (Rose) Rowland 5671b40707 account for phase complete 2023-12-20 15:24:14 -05:00
Jade (Rose) Rowland dec039ead3 fixed filter envelope popping... 2023-12-20 13:09:04 -05:00
Jade (Rose) Rowland fb81f6f268 still working on popping issue with firefox 2023-12-20 10:50:06 -05:00
Jade (Rose) Rowland deb973afa5 fixed hold behavior 2023-12-20 10:17:12 -05:00
Jade (Rose) Rowland 2dea3911ba remove unused variable 2023-12-20 09:29:07 -05:00
Jade (Rose) Rowland e0a7fb8290 filter should decay to set frequency 2023-12-20 09:28:40 -05:00
Jade (Rose) Rowland 30e402b9f1 fixed release bug 2023-12-20 01:52:43 -05:00
Jade (Rose) Rowland f6d9ad51c6 trying to fix divergent firefox behavior 2023-12-20 01:44:34 -05:00
Jade (Rose) Rowland 34ba81a841 fixed test complaint 2023-12-20 00:25:56 -05:00
Jade (Rose) Rowland d7fae2620e create release audio param method, make volume envelopes consistant 2023-12-20 00:21:14 -05:00
Jade (Rose) Rowland 9979a08cb0 updated comment 2023-12-18 00:35:54 -05:00
Jade (Rose) Rowland 17dd48f2a4 prettier 2023-12-18 00:28:41 -05:00
Jade (Rose) Rowland 355ac2ea29 Merge branch 'main' into audio_device_selection 2023-12-18 00:22:33 -05:00
Jade Rowland 000e1293db initialize on first load 2023-12-18 00:09:30 -05:00
Jade Rowland 48fa04f164 system standard resets audio context 2023-12-17 23:15:38 -05:00
Felix Roos ed8f5bf24f fix: first frame 2023-12-17 22:51:43 +01:00
Felix Roos e17df79133 microrepl: ssr static code 2023-12-17 22:42:51 +01:00
Felix Roos 9519d286bd remove web component attribute support
+ settings are now controlled via nanostore
2023-12-17 21:48:53 +01:00
Felix Roos b462f19ef1 fix: boolean settings 2023-12-17 21:28:25 +01:00
Felix Roos 1cdb5964c6 settings sync 2023-12-17 21:16:29 +01:00
Felix Roos 592e54a53f delete strudelmirror example 2023-12-17 21:13:48 +01:00
Jade Rowland fe60f34015 removed accidental file commit 2023-12-17 12:13:05 -05:00
Jade Rowland b5dc65d52a format 2023-12-16 13:36:05 -05:00
Jade Rowland 93a4efcf6d updated fontloader 2023-12-16 13:21:23 -05:00
Felix Roos 40f3212efa fix: first frame active state 2023-12-16 17:04:08 +01:00
Felix Roos 53d6ef04b8 fix: drawTime + canvasHeight 2023-12-16 16:22:28 +01:00
Felix Roos c29d032027 add autodraw flag 2023-12-16 16:19:18 +01:00
Felix Roos 7fcd9d8a83 approaching proper draw logic in microrepl 2023-12-16 16:14:40 +01:00
Felix Roos fc034830d0 use StrudelMirror directly in MicroRepl 2023-12-16 13:08:09 +01:00
Felix Roos 48e06bd213 fix: redundant style injections for multiple repls 2023-12-16 12:37:16 +01:00
Jade Rowland 96e0cce2d2 improve response 2023-12-16 00:30:35 -05:00
Jade Rowland 88f677e910 fix envelope behavior 2023-12-15 18:54:04 -05:00
Jade (Rose) Rowland 9f50f6ef0e Merge branch 'tidalcycles:main' into envelope_improvements 2023-12-15 18:27:23 -05:00
Felix Roos 20e8a30583 copy recipes page to test new MicroRepl 2023-12-15 23:30:27 +01:00
Felix Roos 89c06046b5 fix: repl package import on server 2023-12-15 23:27:38 +01:00
Felix Roos 9c13f6bb53 fix: mini repl play toggle button 2023-12-15 23:20:21 +01:00
Felix Roos b5edcde638 cleanup 2023-12-15 23:18:58 +01:00
Felix Roos 93e8186388 MicroRepl poc 2023-12-15 22:23:20 +01:00
Felix Roos 8e35079fd1 more code in example 2023-12-15 21:01:45 +01:00
Jade Rowland 9663c2ec85 fileter envelopes 2023-12-15 12:16:28 -07:00
Jade Rowland 7da7554493 it works 2023-12-15 11:32:23 -07:00
Felix Roos 372e93e8f8 repl now accepts code in innerHTML + bump 2023-12-15 11:50:49 +01:00
Felix Roos 9b58cf9890 bump repl to 0.9.3 2023-12-15 11:34:14 +01:00
Felix Roos 9fac2c3c33 band aid fix for process is not defined 2023-12-15 11:33:35 +01:00
Felix Roos 505ad17447 fix: process is not defined 2023-12-15 11:25:36 +01:00
Felix Roos 129327077a bump repl to 0.9.2 2023-12-15 11:24:38 +01:00
Felix Roos 034df01e1f better theme style handling 2023-12-15 11:23:10 +01:00
Felix Roos be1e5a7d0e remove onReady callback
+ use strudelTheme as default
2023-12-15 11:21:48 +01:00
Felix Roos 9872a89a29 bump repl to 0.9.1 2023-12-15 10:49:13 +01:00
Felix Roos cf445633c2 bundle as iife instead of cjs 2023-12-15 10:47:58 +01:00
Felix Roos 2cec7bc1a6 fix: rollup warning 2023-12-15 10:47:45 +01:00
Felix Roos 46bfd74e8d repl build config without externals 2023-12-15 10:37:24 +01:00
Felix Roos f6b1e13113 fix: lint errors + wrong color 2023-12-15 10:14:20 +01:00
Felix Roos f0c3d38ea7 move repl web component to new repl package
+ use it in /vanilla + /vanilla/mini
2023-12-15 10:12:47 +01:00
Felix Roos d4afbc63e2 strudel web component 2023-12-15 09:22:50 +01:00
Felix Roos 466574a856 Merge pull request #865 from tidalcycles/vanilla-repl-2
Vanilla repl 3
2023-12-15 00:11:35 +01:00
Felix Roos a8d0d39055 fix: improve last fix by using Prec.highest 2023-12-15 00:07:08 +01:00
Felix Roos 1b04243af6 fix: ctrl+enter on linux 2023-12-15 00:03:12 +01:00
Felix Roos 29082808cb fix: make canvas visible
- automate editor background handling
2023-12-14 23:00:18 +01:00
Felix Roos d23cac506c fix: fontFamily setting 2023-12-14 22:51:17 +01:00
Felix Roos 8959c630ae move css variable injection to themes
+ prepare new HeadCommon in extra file
2023-12-14 22:39:44 +01:00
Felix Roos 35a4f9808d Merge pull request #863 from tidalcycles/vanilla-repl-2
Vanilla repl 2
2023-12-14 21:28:48 +01:00
Felix Roos 49906e98b7 get rid of duplication 2023-12-14 14:50:26 +01:00
Felix Roos 7b6f63db05 comment out fontFamily for now 2023-12-14 14:50:17 +01:00
Felix Roos 37f97e1c17 remove package-lock 2023-12-14 14:48:39 +01:00
Felix Roos 60e559a910 add /vanilla route to website
+ disable autocomplete for now
2023-12-14 14:38:10 +01:00
Felix Roos f6f5ee0375 fix: linter error 2023-12-14 11:50:52 +01:00
Felix Roos 72d1f129cf add settings form to codemirror example 2023-12-14 11:29:33 +01:00
Felix Roos 9474ed7d85 dedicated strudelmirror example 2023-12-14 10:37:16 +01:00
Felix Roos 99194814a9 move code hashing helpers to core 2023-12-14 10:36:56 +01:00
Felix Roos 87feac447b - make codemirror package more capable
- add themes from react package
- add Autocomplete from react package
- handle dynamic extensions
- handle keyboard shortcuts
- make StrudelMirror as capable as Repl
2023-12-14 09:42:25 +01:00
Felix Roos 0a070a2084 superdough 0.9.12 2023-12-12 22:27:08 +01:00
Felix Roos 1d3f87a431 Merge pull request #861 from tidalcycles/envelope-fix
fix: finally repair envelopes
2023-12-12 21:49:22 +01:00
Felix Roos f38d1c272e cleanup 2023-12-12 21:46:52 +01:00
Felix Roos b0bbd58f66 fix: finally repair envelopes 2023-12-12 21:36:32 +01:00
Felix Roos 73fd801907 Merge pull request #860 from tidalcycles/fix-slashless-urls
add missing trailing slashes
2023-12-12 21:20:00 +01:00
Felix Roos bc59f20af4 add missing trailing slashes 2023-12-12 21:17:15 +01:00
Felix Roos daf9187572 Merge pull request #839 from daslyfe/file_import
Sound Import from local file system
2023-12-12 19:08:31 +01:00
Felix Roos 783c856fd7 Merge pull request #858 from tidalcycles/pattern-organization
Pattern organization
2023-12-11 22:48:35 +01:00
Felix Roos f939e00a84 cleanup 2023-12-11 22:46:30 +01:00
Felix Roos b31faa9bbc Merge branch 'main' into pattern-organization 2023-12-11 22:43:53 +01:00
Felix Roos 853a31b638 improve code init logic 2023-12-11 22:17:10 +01:00
Felix Roos faaed61384 fix: do not sync activePattern between tabs
+ only deselect activePattern if code in url differs
2023-12-11 22:01:08 +01:00
Felix Roos b50f686a96 move dirt sample selection to prebake 2023-12-11 11:04:49 +01:00
Jade Rowland f45a3933de update text 2023-12-10 23:08:48 -05:00
Felix Roos 98a1786c10 hotfix: deselect user pattern when opening links 2023-12-10 21:06:51 +01:00
Felix Roos 1f16ebc5b2 fix: deselect user pattern when opening links 2023-12-10 21:01:51 +01:00
Felix Roos 79e8e430f1 fix: style for small screen 2023-12-10 19:50:20 +01:00
Felix Roos 6440621d5d Merge branch 'main' into audio_device_selection 2023-12-10 19:32:29 +01:00
Jade Rowland 59a4cd9cf8 updating buton location 2023-12-10 11:37:18 -05:00
Jade (Rose) Rowland 6238be7f2c Merge branch 'tidalcycles:main' into file_import 2023-12-10 11:28:50 -05:00
Jade Rowland 4051276d74 fixing merge conflicts 2023-12-10 11:27:39 -05:00
Jade Rowland 145510266a fixing merge conflicts 2023-12-10 11:26:46 -05:00
Jade Rowland 4d361a2b3d fixing merge conflicts 2023-12-10 11:24:39 -05:00
Jade Rowland c4fe664215 seperating things out 2023-12-10 11:22:50 -05:00
Jade Rowland ace71693b7 db utils should be reusable 2023-12-10 10:19:57 -05:00
Felix Roos f19ac748e6 slim down template
- move import + export logic to settings.mjs
2023-12-10 14:28:27 +01:00
Jade Rowland a7713213f9 indexdb 2023-12-10 00:44:34 -05:00
Felix Roos 845571a716 hotfix: pattern save was broken :-/ 2023-12-09 23:54:49 +01:00
Felix Roos 8b1dfab077 Merge pull request #855 from tidalcycles/export-patterns
Export patterns + ui tweaks
2023-12-09 17:25:11 +01:00
Felix Roos 6969800192 fix: update button bug 2023-12-09 17:23:24 +01:00
Felix Roos 37a13d1a00 add tooltips 2023-12-08 23:09:24 +01:00
Felix Roos 8c89938eaf pattern json export + import 2023-12-08 23:07:30 +01:00
Felix Roos 5116bf74ad reorder pattern action buttons 2023-12-08 22:25:05 +01:00
Felix Roos a6f969614e fix: rename cancel 2023-12-08 22:24:49 +01:00
Felix Roos c1b7476f43 + show active pattern at the top
+ move active pattern functions to top
2023-12-08 22:22:07 +01:00
Felix Roos 0ca4c1de0f make sure new recent patterns are on top 2023-12-08 22:21:26 +01:00
Jade Rowland ec44103d20 comments 2023-12-08 12:17:01 -05:00
Jade Rowland 89fe0f11ae cleaning up 2023-12-08 12:12:58 -05:00
Felix Roos 63a01088a0 hotfix: dont overwrite user pattern on shuffle 2023-12-08 11:42:15 +01:00
Felix Roos c3e48f1b4d Merge pull request #852 from tidalcycles/import-export-patterns
patterns tab: import patterns + style
2023-12-08 09:41:10 +01:00
Felix Roos 31cd626820 style sounds and patterns tab more consistently 2023-12-08 09:30:06 +01:00
Felix Roos 8dd0e9600d add some padding 2023-12-08 09:20:42 +01:00
Felix Roos 10d86ff835 more style + set reset flag 2023-12-08 09:18:55 +01:00
Felix Roos cec8553fb5 clear sounds + cps on pattern change
+ similar to shuffle
2023-12-08 09:18:33 +01:00
Felix Roos b03bf9ec3d remove log 2023-12-08 09:17:43 +01:00
Felix Roos a750490eea begin pattern import button 2023-12-08 08:49:03 +01:00
Jade Rowland 5281c61f99 fixing async stuff 2023-12-08 01:01:06 -05:00
Jade Rowland 52628920d9 working 2023-12-07 22:17:50 -05:00
Felix Roos ac2e450e38 fix: duplicate example 2023-12-07 21:43:08 +01:00
Felix Roos f8d1e9e004 Merge pull request #769 from tidalcycles/patterns-tab
Patterns tab + Refactor Panel
2023-12-07 20:42:00 +01:00
Felix Roos e551dfeddb reorder tabs + remove duplicated examples 2023-12-07 20:30:13 +01:00
Felix Roos 2f9244e90d style 2023-12-07 20:28:04 +01:00
Felix Roos 056fae518b add checks for forbidden actions 2023-12-07 20:28:01 +01:00
Felix Roos a45d87667f fix: update / fork logic 2023-12-07 20:17:01 +01:00
Felix Roos 7225b0b18d merge changes 2023-12-07 17:33:23 +01:00
Felix Roos e72c9cbebf Merge branch 'main' into patterns-tab 2023-12-07 17:33:07 +01:00
Felix Roos c787bb26c7 Merge pull request #850 from bwagner/pnpm_8.11.0
CHANGES: pnpm 8.1.3 to 8.11.0
2023-12-07 10:25:15 +01:00
Bernhard Wagner 20f3ddd277 CHANGES: pnpm 8.1.3 to 8.11.0 2023-12-07 10:19:26 +01:00
Felix Roos 5cac182b26 Merge pull request #849 from shiyouganai/shiyouganai-slashocalypse
Fix edge case with rehype-urls and trailing slashes in image file paths
2023-12-07 09:35:13 +01:00
Priere 78b2b5ccc3 Don't trim serialized query part of URL 2023-12-06 17:54:29 -05:00
Priere 60cee7fd2f Fix to not add trailing slash to URL with filename 2023-12-06 17:43:15 -05:00
Felix Roos 2bd21df762 Merge pull request #848 from shiyouganai/shiyouganai-slashocalypse
Fix examples page, piano() and a few workshop imgs
2023-12-06 23:02:31 +01:00
Priere a32ed02745 Fix piano and two doc images 2023-12-06 16:57:43 -05:00
Priere 93c5eeb99e Fix examples page and de workshop img 2023-12-06 16:45:37 -05:00
Felix Roos ff45baba2c Merge pull request #846 from tidalcycles/slashocalypse
fix: swatch png src
2023-12-06 22:30:59 +01:00
Felix Roos cc4d38b4a5 fix: swatch png src 2023-12-06 22:28:14 +01:00
Felix Roos bf30587180 Merge pull request #845 from tidalcycles/slashocalypse
fix: missing hash for links starting with /
2023-12-06 22:19:30 +01:00
Felix Roos 1b372a9a7b fix: missing hash for links starting with / 2023-12-06 22:16:43 +01:00
Felix Roos d9f78e1283 Merge pull request #842 from tidalcycles/slashocalypse
improve slashing + base href behavior
2023-12-06 22:05:05 +01:00
Felix Roos 2ddd2d1f39 fix: search links with basehref 2023-12-06 21:46:13 +01:00
Felix Roos 6b31160bbd fix: astro warnings 2023-12-06 21:34:39 +01:00
Felix Roos 74aa85b38b Merge pull request #843 from shiyouganai/shiyouganai-slashocalypse
Add in fixes from my fork to slashocalypse branch
2023-12-06 21:26:48 +01:00
Priere 8e9b607fa1 Revert to simpler link parsing and run formatter 2023-12-06 03:57:30 -05:00
Priere 5332f99a5a Fix another comment 2023-12-06 03:43:38 -05:00
Priere e1a8bd333d Fix comment 2023-12-06 03:41:54 -05:00
Priere 018a45e2d4 Rework rehype plugin and clean up changes 2023-12-06 02:57:28 -05:00
Priere 2c43fb2512 Remove unnecessary change 2023-12-05 19:34:15 -05:00
Priere 3e5664a877 Add quick fix for non root bases 2023-12-05 19:34:15 -05:00
Felix Roos ac41426a20 improve slashing + base href behavior
+ prefix sidebar links & mdx links with base
+ add trailing slashes
2023-12-05 23:09:34 +01:00
Felix Roos 8a0cf14fd7 Merge pull request #838 from ilesinge/prevent_crawler_404
Prevent 404 on Algolia crawls
2023-12-05 18:43:57 +01:00
Felix Roos 362f0df117 Merge pull request #820 from daslyfe/multichannel_audio
Multichannel audio
2023-12-05 18:26:47 +01:00
Felix Roos 1190f6e091 fix weird rounding change... 2023-12-05 18:17:33 +01:00
Bernhard Wagner ebf93c06dd ADDS: JetBrains IDE files (#840)
Co-authored-by: Bernhard Wagner <gitcommit@nosuch.biz>
2023-12-05 11:19:57 +00:00
Bernhard Wagner fe8debe6e8 CHANGES: github action pnpm version from 7 to 8.3.1 (#835)
Co-authored-by: Bernhard Wagner <gitcommit@nosuch.biz>
2023-12-05 11:19:26 +00:00
Bernhard Wagner b8866cf575 CHANGES: pin pnpm to version 8.3.1 (#834)
Co-authored-by: Bernhard Wagner <gitcommit@nosuch.biz>
2023-12-05 11:19:17 +00:00
Bernhard Wagner 2ce8576ab2 CHANGES: github action checkout v2->v4 (#837)
Co-authored-by: Bernhard Wagner <gitcommit@nosuch.biz>
2023-12-05 11:19:06 +00:00
Bernhard Wagner 1bca05e349 FIXES: palindrome abc -> abccba (#831)
* FIXES: palindrome abc -> abccba

* FIXES: tests for palindrome

---------

Co-authored-by: Bernhard Wagner <gitcommit@nosuch.biz>
2023-12-05 10:15:13 +00:00
Jade Rowland 8146725f89 removed unessecary change 2023-12-04 19:20:28 -05:00
Jade Rowland 34c44a29c6 style input 2023-12-04 19:11:38 -05:00
Alexandre G.-Raymond 7c948dd812 Prevent 404 on Algolia crawls 2023-12-04 14:48:54 +01:00
Jade Rowland 61919a1b3e upload samples 2023-12-03 23:33:04 -05:00
Jade Rowland 9be10890e1 update tests 2023-12-03 18:31:01 -05:00
Jade Rowland f51109cb26 comment 2023-12-03 18:26:48 -05:00
Jade Rowland 9aec18b3a0 add 1 to channel selection 2023-12-03 18:25:30 -05:00
Felix Roos b374cdf47c Merge pull request #830 from drewgbarnes/patch-1
Fix a typo
2023-12-02 09:43:50 +01:00
Drew Barnes b16f235e1c Update first-sounds.mdx 2023-12-01 14:23:07 -08:00
Felix Roos c26e5bbf0d Merge pull request #827 from ilesinge/add_search
Add and style algolia search
2023-11-30 10:42:41 +01:00
Alexandre G.-Raymond 020c326458 Codeformat for search 2023-11-26 22:52:17 +01:00
Alexandre G.-Raymond dacd1e6146 Add and style algolia search 2023-11-26 22:50:17 +01:00
Felix Roos 25b2eb5783 snapshot 2023-11-25 16:20:12 +01:00
Felix Roos 7c3dbac083 Merge branch 'main' into multichannel_audio 2023-11-25 16:19:44 +01:00
Felix Roos 54b5d69c8d Merge pull request #818 from atfornes/main
Hydra fixes and improvements
2023-11-25 15:50:43 +01:00
Felix Roos 407510e265 document feedStrudel 2023-11-25 15:20:19 +01:00
Felix Roos f7a283f87d add feedStrudel option + smarter reinit logic 2023-11-24 12:49:05 +01:00
Ámbar Tenorio Fornés 508a6c92b2 default hydra config without audio detection 2023-11-24 12:21:04 +01:00
Felix Roos 9045ce05da comment 2023-11-24 11:28:20 +01:00
Felix Roos 456be920d3 else clause 2023-11-24 11:17:30 +01:00
Felix Roos 71b4e14dd3 Merge branch 'main' into atfornesmain 2023-11-24 11:10:15 +01:00
Felix Roos fb7a9e2083 format 2023-11-24 10:28:40 +01:00
Felix Roos 69e99fa902 Merge pull request #808 from kasparsj/hydra-options
add options param to initHydra
2023-11-24 10:07:17 +01:00
Felix Roos 5e7e1ff0e8 Merge pull request #800 from ilesinge/improve_doc
Improve documentation for synonym functions
2023-11-24 09:57:02 +01:00
Felix Roos 18e9ceb501 populate autocomplete with all synonyms
+ properly display synonyms based on label
2023-11-24 09:52:39 +01:00
Felix Roos 458c97b927 list synonyms in Autocomplete 2023-11-24 09:37:26 +01:00
Felix Roos 4fd3e6e99c fix: entry.name mutation bug 2023-11-24 09:37:11 +01:00
Felix Roos c606f86e9d Merge pull request #806 from Bubobubobubobubo/noises
New noise type: "crackle"
2023-11-24 09:00:53 +01:00
Jade Rowland e7376c4fc8 panic function update 2023-11-23 14:17:17 -05:00
Jade Rowland 886b16d6fd fixed panic function 2023-11-23 14:07:32 -05:00
Jade Rowland 64c2e7c1e8 cleaning up 2023-11-23 13:45:58 -05:00
Jade Rowland 88e933ee25 cleaning up 2023-11-23 13:31:00 -05:00
Jade Rowland 1f62d85d8b cleaning up 2023-11-23 13:29:22 -05:00
Jade Rowland 3fd5fdf1ee preview outputs should be stereo 2023-11-23 12:43:51 -05:00
Jade Rowland e419733716 channel splitting and channels parameter 2023-11-23 01:04:53 -05:00
Alexandre Gravel-Raymond ecc8e0a108 More code beauty please 2023-11-22 20:38:25 +01:00
Alexandre Gravel-Raymond 2868a5ff4f Update the undocumented functions file 2023-11-22 20:36:01 +01:00
Alexandre Gravel-Raymond d71877f915 Move jsdoc files to subfolder 2023-11-22 20:35:19 +01:00
Ámbar Tenorio Fornés e0e896d4b5 improve hydra audio detection initialization 2023-11-22 17:39:16 +01:00
Ámbar Tenorio Fornés 0a280e9399 prettier code formatting 2023-11-22 15:47:16 +01:00
Ámbar Tenorio Fornés a58ac967a6 add Hydra audio example to documentation 2023-11-22 13:51:42 +01:00
Ámbar Tenorio Fornés ebc6723f55 enable hydra options update 2023-11-22 13:51:01 +01:00
Ámbar Tenorio Fornés 66fd20ace5 add hydra audio capture option 2023-11-22 12:36:43 +01:00
Ámbar Tenorio Fornés de00212bb6 fix hydra performance issues 2023-11-22 12:27:18 +01:00
Jade Rowland f0b458cd17 need to figure out channels input + seperating left right channels from source 2023-11-22 00:03:34 -05:00
Jade Rowland 7aa217828b testing 2023-11-20 23:06:35 -05:00
Felix Roos b27f8e45dc hotfix: build 2023-11-18 21:48:50 +01:00
Felix Roos 3e02f0a0ba Merge pull request #815 from tidalcycles/color-hsl
Color hsl
2023-11-18 21:18:16 +01:00
Felix Roos f759999826 pianoroll smear as float 2023-11-18 21:16:03 +01:00
Felix Roos 049aa35286 hsl + hsla functions 2023-11-18 21:15:52 +01:00
Felix Roos dd8be657c2 Merge pull request #813 from tidalcycles/fix-multiple-repls
fix: multiple repls
2023-11-17 23:18:23 +01:00
Felix Roos 09752241ba fix: multiple repls 2023-11-17 23:16:09 +01:00
Felix Roos 83561a0ceb Update README.md 2023-11-17 21:46:34 +01:00
Felix Roos b8ca83ddd1 rename pattern 2023-11-17 21:29:50 +01:00
Felix Roos 4cae6c051b fix: save pattern 2023-11-17 20:55:23 +01:00
Felix Roos e5f9467329 fix: slight layout improvement 2023-11-17 20:55:04 +01:00
Felix Roos 34c1f3c7de fix: examples layout 2023-11-17 20:54:48 +01:00
Kaspars c0f56be2a9 add options param to initHydra 2023-11-17 20:41:37 +01:00
Felix Roos c6f89431d9 fix: merge error 2023-11-17 20:37:21 +01:00
Felix Roos 80601451b6 Merge branch 'main' into patterns-tab 2023-11-17 20:36:15 +01:00
Felix Roos f74d1beb62 Merge branch 'main' of https://github.com/tidalcycles/strudel 2023-11-17 20:29:53 +01:00
Felix Roos b73ea7f086 Merge pull request #801 from ilesinge/add_doc
Add doc for euclidLegatoRot, wordfall and slider
2023-11-17 16:04:10 +01:00
Alexandre Gravel-Raymond a3bf6975c4 Mark optional slider params 2023-11-17 15:33:53 +01:00
Felix Roos 08ebb52e9b Merge pull request #804 from kasparsj/highlight-active-line-opt
add option to disable active line highlighting in Code Settings
2023-11-17 14:42:58 +01:00
Felix Roos 47a6af2b25 Merge pull request #805 from tidalcycles/pq-functions
tidal style d1 ... d9 functions + more
2023-11-17 14:37:51 +01:00
Felix Roos a84cfb5677 bump superdough 2023-11-17 14:07:26 +01:00
Raphael Forment 6e92c4915a Run prettier 2023-11-17 13:37:16 +01:00
Raphael Forment 2a18df61cd Fix documentation 2023-11-17 13:23:54 +01:00
Raphael Forment fb28083ce6 Fixing density and adding documentation 2023-11-17 13:18:49 +01:00
Raphael Forment 476bda812e Initial work on crackle 2023-11-17 12:55:17 +01:00
Felix Roos 265f01eb06 add p1 .. p9 shortcuts as well 2023-11-17 10:50:45 +01:00
Felix Roos cb9ef3ee6a add q1 .. q9 shortcuts 2023-11-17 09:45:44 +01:00
Felix Roos a4487179a5 fix tests 2023-11-16 07:25:20 +01:00
Felix Roos f43f627037 + add hush
+ add the ability to evaluate without clearing
2023-11-16 07:17:59 +01:00
Felix Roos a7b799f154 p and q methods + all function 2023-11-16 06:52:47 +01:00
Felix Roos ee7cd8cd4c remove pseudo note variables 2023-11-16 06:51:51 +01:00
Kaspars 2d1fcf4a8d fix typo 2023-11-15 22:53:56 +01:00
Kaspars ef14074164 add option to disable active line highlighting in Code Settings 2023-11-15 22:38:00 +01:00
Felix Roos 49aa9cf6da Merge pull request #802 from kasparsj/fix-strudelTheme-outline
remove unwanted cm6 outline for strudelTheme
2023-11-15 20:12:23 +01:00
Kaspars 8d5ef45e2b fix codeformat 2023-11-15 19:22:52 +01:00
Kaspars 9ef177e735 Merge branch 'main' into fix-strudelTheme-outline 2023-11-14 16:33:06 +01:00
Kaspars 7f1919ebc6 move fix to Repl.css 2023-11-14 11:16:51 +01:00
Kaspars ff0af15ac7 remove unwanted cm6 outline for strudelTheme 2023-11-13 00:06:01 +01:00
Alexandre G.-Raymond 8a7ff9e01d Add snapshot for euclidLegatoRot 2023-11-11 17:24:18 +01:00
Alexandre G.-Raymond e52e257d9b Document euclidLegatoRot 2023-11-11 17:03:21 +01:00
Alexandre G.-Raymond 2d6654b234 Document slider 2023-11-11 16:24:09 +01:00
Alexandre G.-Raymond 1b0427e943 Document wordfall 2023-11-11 16:23:58 +01:00
Alexandre G.-Raymond 24e1881876 Ignore jsdoc-synonyms by eslint 2023-11-11 15:53:03 +01:00
Alexandre G.-Raymond bfff38a262 Fix code format of JSDoc synonym plugin 2023-11-11 15:44:15 +01:00
Alexandre G.-Raymond 2aff31fe06 Simplify JSDoc 2023-11-11 14:24:20 +01:00
Alexandre G.-Raymond 6ba2b767b0 Show synonyms in API reference 2023-11-11 14:23:55 +01:00
Alexandre G.-Raymond bbc292561f Use synonyms in Tooltip 2023-11-11 14:23:30 +01:00
Alexandre G.-Raymond e4b00117c3 Parse the synonyms tag in source documentation 2023-11-11 14:22:52 +01:00
Felix Roos 53160c638a half working user pattern management 2023-10-29 14:00:13 +01:00
Felix Roos a2077f7be1 fix logger import 2023-10-29 13:14:29 +01:00
Felix Roos b245d44220 hide patterns tab for now
+ add examples to welcome tab
2023-10-29 13:14:25 +01:00
Felix Roos b15f7bcf45 Merge branch 'main' into patterns-tab 2023-10-29 13:05:25 +01:00
Felix Roos dc254bd562 upstream changes 2023-09-17 17:28:25 +02:00
Felix Roos 6c3173f45b Merge branch 'main' into patterns-tab 2023-09-17 17:28:18 +02:00
Felix Roos c75c3f1ab1 basic pattern add function 2023-08-24 11:55:21 +02:00
Felix Roos 281ad5fac9 add nanFallback for better errors 2023-08-24 08:50:42 +02:00
Felix Roos eb0301d74e remove annoying logs 2023-08-24 08:50:18 +02:00
Felix Roos 4a76757dd2 Merge branch 'main' into patterns-tab 2023-08-23 22:56:12 +02:00
Felix Roos 1855dae35e add patterns tab with examples 2023-08-23 22:51:36 +02:00
Felix Roos 4e7e715f10 rename footer -> panel 2023-08-19 00:20:46 +02:00
Felix Roos 5be1004292 encapsulate panel tabs 2023-08-19 00:19:32 +02:00
327 changed files with 10395 additions and 12409 deletions
+2 -1
View File
@@ -20,4 +20,5 @@ vite.config.js
**/dist
/src-tauri/target/**/*
reverbGen.mjs
hydra.mjs
hydra.mjs
jsdoc-synonyms.js
+3 -3
View File
@@ -21,13 +21,13 @@ jobs:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 7
version: 8.11.0
- uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
cache: "pnpm"
- name: Install Dependencies
run: pnpm install
+3 -3
View File
@@ -7,13 +7,13 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18]
node-version: [20]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 7
version: 8.11.0
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
+84 -1
View File
@@ -43,4 +43,87 @@ dev-dist
Dirt-Samples
tidal-drum-machines
webaudiofontdata
src-tauri/target
src-tauri/target
# BEGIN JetBrains -> END JetBrains
# for JetBrains IDE users, e.g. WebStorm. Source: https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
# END JetBrains -> BEGIN JetBrains
+2 -1
View File
@@ -9,4 +9,5 @@ packages/xen/tunejs.js
paper
pnpm-lock.yaml
pnpm-workspace.yaml
**/dev-dist
**/dev-dist
website/.astro
+2 -2
View File
@@ -66,7 +66,7 @@ To get the project up and running for development, make sure you have installed:
- [git](https://git-scm.com/)
- [node](https://nodejs.org/en/) >= 18
- [pnpm](https://pnpm.io/) (`npm i pnpm -g`)
- [pnpm](https://pnpm.io/) (`curl -fsSL https://get.pnpm.io/install.sh | env PNPM_VERSION=8.11.0 sh -`)
then, do the following:
@@ -114,7 +114,7 @@ You can run the same check with `pnpm check`
## Package Workflow
The project is split into multiple [packages](https://github.com/tidalcycles/strudel/tree/main/packages) with independent versioning.
When you run `pnpm i` on the root folder, [pnpm workspaces](https://pnpm.io/workspaces) will install all dependencies of all subpackages. This will allow any js file to import `@strudel.cycles/<package-name>` to get the local version,
When you run `pnpm i` on the root folder, [pnpm workspaces](https://pnpm.io/workspaces) will install all dependencies of all subpackages. This will allow any js file to import `@strudel/<package-name>` to get the local version,
allowing to develop multiple packages at the same time.
## Package Publishing
-1
View File
@@ -30,7 +30,6 @@ There are multiple npm packages you can use to use strudel, or only parts of it,
- [`midi`](./packages/midi): webmidi bindings
- [`serial`](./packages/serial): webserial bindings
- [`tonal`](./packages/tonal): tonal functions
- [`xen`](./packages/xen): microtonal / xenharmonic functions
- ... [and there are more](./packages/)
Click on the package names to find out more about each one.
-1806
View File
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 150 KiB

+3
View File
@@ -0,0 +1,3 @@
# examples
This folder contains usage examples for different scenarios.
+5
View File
@@ -0,0 +1,5 @@
# buildless examples
These examples show you how strudel can be used in a regular html file, without the need for a build tool.
Most examples are using [skypack](https://www.skypack.dev/)
@@ -7,7 +7,7 @@
/>
<div id="output"></div>
<script type="module">
const strudel = await import('https://cdn.skypack.dev/@strudel.cycles/core@0.6.8');
const strudel = await import('https://cdn.skypack.dev/@strudel/core@0.6.8');
Object.assign(window, strudel); // assign all strudel functions to global scope to use with eval
const input = document.getElementById('text');
const getEvents = () => {
@@ -8,7 +8,7 @@
/>
<canvas id="canvas"></canvas>
<script type="module">
const strudel = await import('https://cdn.skypack.dev/@strudel.cycles/core@0.6.8');
const strudel = await import('https://cdn.skypack.dev/@strudel/core@0.6.8');
// this adds all strudel functions to the global scope, to be used by eval
Object.assign(window, strudel);
// setup elements
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<button id="play">play</button>
<button id="stop">stop</button>
<script type="module">
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<button id="a">A</button>
<button id="b">B</button>
<button id="c">C</button>
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@@ -0,0 +1,31 @@
<script src="https://unpkg.com/@strudel/repl@0.9.4"></script>
<strudel-editor>
<!--
// @date 23-08-15
// "golf rolf" @by froos @license CC BY-NC-SA 4.0
setcps(1)
stack(
s("bd*2, ~ rim*<1!3 2>, hh*4").bank('RolandTR909')
.off(-1/8, set(speed("1.5").gain(.25)))
.mask("<0!16 1!64>")
,
note("g1(3,8)")
.s("gm_synth_bass_2:<0 2>")
.delay(".8:.25:.25")
.clip("<.5!16 2!32>")
.off(1/8, add(note("12?0.7")))
.lpf(sine.range(500,2000).slow(32)).lpq(8)
.add(note("0,.05"))
.mask("<0!8 1!32>")
,
n("<0 1 2 3 4>*8").scale('G4 minor')
.s("gm_lead_6_voice")
.clip(sine.range(.2,.8).slow(8))
.jux(rev)
.room(2)
.sometimes(add(note("12")))
.lpf(perlin.range(200,20000).slow(4))
).reset("<x@15 x(5,8)>")
-->
</strudel-editor>
+8
View File
@@ -0,0 +1,8 @@
# codemirror-repl example
This folder demonstrates how to set up a full strudel repl with the `@strudel/codemirror` package. Run it using:
```sh
pnpm i
pnpm dev
```
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@@ -1,11 +1,11 @@
import { StrudelMirror } from '@strudel/codemirror';
import { funk42 } from './tunes';
import { drawPianoroll, evalScope, controls } from '@strudel.cycles/core';
import { drawPianoroll, evalScope, controls } from '@strudel/core';
import './style.css';
import { initAudioOnFirstClick } from '@strudel.cycles/webaudio';
import { transpiler } from '@strudel.cycles/transpiler';
import { getAudioContext, webaudioOutput, registerSynthSounds } from '@strudel.cycles/webaudio';
import { registerSoundfonts } from '@strudel.cycles/soundfonts';
import { initAudioOnFirstClick } from '@strudel/webaudio';
import { transpiler } from '@strudel/transpiler';
import { getAudioContext, webaudioOutput, registerSynthSounds } from '@strudel/webaudio';
import { registerSoundfonts } from '@strudel/soundfonts';
// init canvas
const canvas = document.getElementById('roll');
@@ -26,10 +26,10 @@ const editor = new StrudelMirror({
initAudioOnFirstClick(); // needed to make the browser happy (don't await this here..)
const loadModules = evalScope(
controls,
import('@strudel.cycles/core'),
import('@strudel.cycles/mini'),
import('@strudel.cycles/tonal'),
import('@strudel.cycles/webaudio'),
import('@strudel/core'),
import('@strudel/mini'),
import('@strudel/tonal'),
import('@strudel/webaudio'),
);
await Promise.all([loadModules, registerSynthSounds(), registerSoundfonts()]);
},
+23
View File
@@ -0,0 +1,23 @@
{
"name": "vite-vanilla-repl-cm6",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.0.10"
},
"dependencies": {
"@strudel/codemirror": "workspace:*",
"@strudel/core": "workspace:*",
"@strudel/mini": "workspace:*",
"@strudel/soundfonts": "workspace:*",
"@strudel/tonal": "workspace:*",
"@strudel/transpiler": "workspace:*",
"@strudel/webaudio": "workspace:*"
}
}
+13
View File
@@ -0,0 +1,13 @@
# headless-repl demo
This demo shows how to use strudel in "headless mode".
Buttons A / B / C will switch between different patterns.
It showcases the usage of the `@strudel/web` package, using [vite](https://vitejs.dev/) as the dev server.
## Running
```sh
pnpm i && cd examples/headless-repl
pnpm dev
# open http://localhost:5173/
```
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@@ -10,7 +10,7 @@
"preview": "vite preview"
},
"devDependencies": {
"vite": "^4.3.2"
"vite": "^5.0.10"
},
"dependencies": {
"@strudel/web": "workspace:*"
+1
View File
@@ -0,0 +1 @@
dist
+10
View File
@@ -0,0 +1,10 @@
# minimal repl
This folder demonstrates how to set up a minimal strudel repl using vite and vanilla JS. Run it using:
```sh
npm i
npm run dev
```
If you're looking for a more feature rich alternative, have a look at the [../codemirror-repl](codemirror-repl example)
@@ -1,4 +1,4 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
@@ -1,6 +1,6 @@
import { controls, repl, evalScope } from '@strudel.cycles/core';
import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel.cycles/webaudio';
import { transpiler } from '@strudel.cycles/transpiler';
import { controls, repl, evalScope } from '@strudel/core';
import { getAudioContext, webaudioOutput, initAudioOnFirstClick } from '@strudel/webaudio';
import { transpiler } from '@strudel/transpiler';
import tune from './tune.mjs';
const ctx = getAudioContext();
@@ -10,10 +10,10 @@ initAudioOnFirstClick();
evalScope(
controls,
import('@strudel.cycles/core'),
import('@strudel.cycles/mini'),
import('@strudel.cycles/webaudio'),
import('@strudel.cycles/tonal'),
import('@strudel/core'),
import('@strudel/mini'),
import('@strudel/webaudio'),
import('@strudel/tonal'),
);
const { evaluate } = repl({
@@ -10,13 +10,13 @@
"preview": "vite preview"
},
"devDependencies": {
"vite": "^4.3.3"
"vite": "^5.0.10"
},
"dependencies": {
"@strudel.cycles/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*",
"@strudel.cycles/tonal": "workspace:*"
"@strudel/core": "workspace:*",
"@strudel/mini": "workspace:*",
"@strudel/transpiler": "workspace:*",
"@strudel/webaudio": "workspace:*",
"@strudel/tonal": "workspace:*"
}
}
+11
View File
@@ -0,0 +1,11 @@
# superdough demo
This demo shows how to use [superdough](https://www.npmjs.com/package/superdough) with [vite](https://vitejs.dev/).
## Running
```sh
pnpm i && cd examples/headless-repl
pnpm dev
# open http://localhost:5173/
```
+38
View File
@@ -0,0 +1,38 @@
<!doctype html>
<html>
<head>
<title>Superdough Example</title>
<meta charset="UTF-8" />
</head>
<body>
<button id="play">PLAAAAAAAY</button>
<script type="module">
import { superdough, samples, initAudioOnFirstClick, registerSynthSounds } from 'superdough';
const init = Promise.all([
initAudioOnFirstClick(),
samples('github:tidalcycles/Dirt-Samples/master'),
registerSynthSounds(),
]);
const loop = (t = 0) => {
// superdough(value, time, duration)
superdough({ s: 'bd', delay: 0.5 }, t);
superdough({ note: 'g1', s: 'sawtooth', cutoff: 600, resonance: 8 }, t, 0.125);
superdough({ note: 'g2', s: 'sawtooth', cutoff: 600, resonance: 8 }, t + 0.25, 0.125);
superdough({ s: 'hh' }, t + 0.25);
superdough({ s: 'sd', room: 0.5 }, t + 0.5);
superdough({ s: 'hh' }, t + 0.75);
};
document.getElementById('play').addEventListener('click', async () => {
await init;
let t = 0.1;
while (t < 16) {
loop(t++);
}
});
</script>
</body>
</html>
@@ -12,6 +12,6 @@
"superdough": "workspace:*"
},
"devDependencies": {
"vite": "^4.4.5"
"vite": "^5.0.10"
}
}
@@ -1,12 +1,17 @@
/*
postcss.config.js - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/repl/postcss.config.js>
jsdoc-synonyms.js - Add support for @synonym tag
Copyright (C) 2023 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/midi/midi.mjs>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
function defineTags(dictionary) {
dictionary.defineTag('synonyms', {
mustHaveValue: true,
onTagged: function (doclet, tag) {
doclet.synonyms_text = tag.value;
doclet.synonyms = doclet.synonyms_text.split(/[ ,]+/);
},
});
}
module.exports = { defineTags: defineTags };
@@ -3,7 +3,7 @@
"includePattern": ".+\\.(js(doc|x)?|mjs)$",
"excludePattern": "node_modules|shift-parser|shift-reducer|shift-traverser|dist"
},
"plugins": ["plugins/markdown"],
"plugins": ["plugins/markdown", "jsdoc/jsdoc-synonyms"],
"opts": {
"destination": "./out/",
"recurse": true
+4 -2
View File
@@ -65,7 +65,7 @@ async function getUndocumented(path, docs) {
}
// read doc.json file
const { docs } = JSON.parse(await readFile(resolve(__dirname, 'doc.json'), 'utf8'));
const { docs } = JSON.parse(await readFile(resolve(__dirname, '..', 'doc.json'), 'utf8'));
const paths = dependencyTree.toList({
filename: 'index.mjs',
@@ -76,7 +76,9 @@ const paths = dependencyTree.toList({
// const paths = ['../packages/core/pattern.mjs', '../packages/core/hap.mjs'].map((rel) => resolve(__dirname, rel));
const undocumented = Object.fromEntries(
await Promise.all(paths.map(async (path) => [path, await getUndocumented(path, docs)])),
await Promise.all(
paths.map(async (path) => [path.replace(resolve(__dirname, '..'), ''), await getUndocumented(path, docs)]),
),
);
console.log(JSON.stringify(undocumented, null, 2));
+2 -4
View File
@@ -1,8 +1,6 @@
{
"packages": [
"packages/*"
],
"packages": ["packages/*"],
"version": "independent",
"npmClient": "pnpm",
"useWorkspaces": true
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+19 -20
View File
@@ -1,5 +1,5 @@
{
"name": "@strudel.cycles/monorepo",
"name": "@strudel/monorepo",
"version": "0.5.0",
"private": true,
"description": "Port of tidalcycles to javascript",
@@ -18,12 +18,12 @@
"build": "npm run prebuild && cd website && npm run build",
"preview": "cd website && npm run preview",
"osc": "cd packages/osc && npm run server",
"jsdoc": "jsdoc packages/ -c jsdoc.config.json",
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc.config.json",
"jsdoc": "jsdoc packages/ -c jsdoc/jsdoc.config.json",
"jsdoc-json": "jsdoc packages/ --template ./node_modules/jsdoc-json --destination doc.json -c jsdoc/jsdoc.config.json",
"lint": "eslint . --ext mjs,js --quiet",
"codeformat": "prettier --write .",
"format-check": "prettier --check .",
"report-undocumented": "npm run jsdoc-json && node undocumented.mjs > undocumented.json",
"report-undocumented": "npm run jsdoc-json && node jsdoc/undocumented.mjs > undocumented.json",
"check": "npm run format-check && npm run lint && npm run test",
"iclc": "cd paper && pandoc --template=pandoc/iclc.html --citeproc --number-sections iclc2023.md -o iclc2023.html && pandoc --template=pandoc/iclc.latex --citeproc --number-sections iclc2023.md -o iclc2023.pdf"
},
@@ -45,28 +45,27 @@
},
"homepage": "https://strudel.cc",
"dependencies": {
"@strudel.cycles/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*",
"@strudel.cycles/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*",
"@strudel.cycles/xen": "workspace:*",
"acorn": "^8.8.1",
"dependency-tree": "^9.0.0"
"@strudel/core": "workspace:*",
"@strudel/mini": "workspace:*",
"@strudel/tonal": "workspace:*",
"@strudel/transpiler": "workspace:*",
"@strudel/webaudio": "workspace:*",
"@strudel/xen": "workspace:*"
},
"devDependencies": {
"@tauri-apps/cli": "^1.4.0",
"@vitest/ui": "^0.28.0",
"dependency-tree": "^10.0.9",
"@tauri-apps/cli": "^1.5.9",
"@vitest/ui": "^1.1.0",
"canvas": "^2.11.2",
"eslint": "^8.39.0",
"eslint-plugin-import": "^2.27.5",
"eslint": "^8.56.0",
"eslint-plugin-import": "^2.29.1",
"events": "^3.3.0",
"jsdoc": "^4.0.2",
"jsdoc-json": "^2.0.2",
"jsdoc-to-markdown": "^8.0.0",
"lerna": "^6.6.1",
"prettier": "^2.8.8",
"rollup-plugin-visualizer": "^5.8.1",
"vitest": "^0.33.0"
"lerna": "^8.0.1",
"prettier": "^3.1.1",
"rollup-plugin-visualizer": "^5.12.0",
"vitest": "^1.1.0"
}
}
+1 -11
View File
@@ -1,15 +1,5 @@
# Packages
Each folder represents one of the @strudel.cycles/* packages [published to npm](https://www.npmjs.com/org/strudel.cycles).
Each folder represents one of the @strudel/* packages [published to npm](https://www.npmjs.com/org/strudel).
To understand how those pieces connect, refer to the [Technical Manual](https://github.com/tidalcycles/strudel/wiki/Technical-Manual) or the individual READMEs.
This is a graphical view of all the packages: [full screen](https://raw.githubusercontent.com/tidalcycles/strudel/main/dependencies.svg)
![dependencies](https://raw.githubusercontent.com/tidalcycles/strudel/main/dependencies.svg)
Generated with
```sh
npx depcruise --include-only "^packages" -X "node_modules" --output-type dot packages | dot -T svg > dependencygraph.svg
```
@@ -1,7 +1,13 @@
import { createRoot } from 'react-dom/client';
import jsdoc from '../../doc.json';
// import { javascriptLanguage } from '@codemirror/lang-javascript';
import { autocompletion } from '@codemirror/autocomplete';
import { h } from './html';
function plaintext(str) {
const div = document.createElement('div');
div.innerText = str;
return div.innerHTML;
}
const getDocLabel = (doc) => doc.name || doc.longname;
const getInnerText = (html) => {
@@ -10,36 +16,32 @@ const getInnerText = (html) => {
return div.textContent || div.innerText || '';
};
export function Autocomplete({ doc }) {
return (
<div className="prose dark:prose-invert max-h-[400px] overflow-auto">
<h3 className="pt-0 mt-0">{getDocLabel(doc)}</h3>
<div dangerouslySetInnerHTML={{ __html: doc.description }} />
<ul>
{doc.params?.map(({ name, type, description }, i) => (
<li key={i}>
{name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)}</> : ''}
</li>
))}
</ul>
<div>
{doc.examples?.map((example, i) => (
<div key={i}>
<pre
className="cursor-pointer"
onMouseDown={(e) => {
console.log('ola!');
navigator.clipboard.writeText(example);
e.stopPropagation();
}}
>
{example}
</pre>
</div>
))}
</div>
</div>
);
export function Autocomplete({ doc, label }) {
return h`<div class="prose dark:prose-invert max-h-[400px] overflow-auto p-2">
<h1 class="pt-0 mt-0">${label || getDocLabel(doc)}</h1>
${doc.description}
<ul>
${doc.params?.map(
({ name, type, description }) =>
`<li>${name} : ${type.names?.join(' | ')} ${description ? ` - ${getInnerText(description)}` : ''}</li>`,
)}
</ul>
<div>
${doc.examples?.map((example) => `<div><pre>${plaintext(example)}</pre></div>`)}
</div>
</div>`[0];
/*
<pre
className="cursor-pointer"
onMouseDown={(e) => {
console.log('ola!');
navigator.clipboard.writeText(example);
e.stopPropagation();
}}
>
{example}
</pre>
*/
}
const jsdocCompletions = jsdoc.docs
@@ -54,13 +56,7 @@ const jsdocCompletions = jsdoc.docs
.map((doc) /*: Completion */ => ({
label: getDocLabel(doc),
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
info: () => {
const node = document.createElement('div');
// if Autocomplete is non-interactive, it could also be rendered at build time..
// .. using renderToStaticMarkup
createRoot(node).render(<Autocomplete doc={doc} />);
return node;
},
info: () => Autocomplete({ doc }),
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
}));
+134 -37
View File
@@ -3,32 +3,64 @@ import { closeBrackets } from '@codemirror/autocomplete';
import { history } from '@codemirror/commands';
import { javascript } from '@codemirror/lang-javascript';
import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
import { Compartment, EditorState } from '@codemirror/state';
import { EditorView, highlightActiveLineGutter, highlightActiveLine, keymap, lineNumbers } from '@codemirror/view';
import { Pattern, Drawer, repl, cleanupDraw } from '@strudel.cycles/core';
import { isAutoCompletionEnabled } from './Autocomplete';
import { Compartment, EditorState, Prec } from '@codemirror/state';
import {
EditorView,
highlightActiveLineGutter,
highlightActiveLine,
keymap,
lineNumbers,
drawSelection,
} from '@codemirror/view';
import { Pattern, Drawer, repl, cleanupDraw } from '@strudel/core';
import { isAutoCompletionEnabled } from './autocomplete.mjs';
import { isTooltipEnabled } from './tooltip.mjs';
import { flash, isFlashEnabled } from './flash.mjs';
import { highlightMiniLocations, isPatternHighlightingEnabled, updateMiniLocations } from './highlight.mjs';
import { keybindings } from './keybindings.mjs';
import { theme } from './themes.mjs';
import { initTheme, activateTheme, theme } from './themes.mjs';
import { updateWidgets, sliderPlugin } from './slider.mjs';
import { persistentAtom } from '@nanostores/persistent';
const extensions = {
isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []),
isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
theme,
isAutoCompletionEnabled,
isTooltipEnabled,
isPatternHighlightingEnabled,
isActiveLineHighlighted: (on) => (on ? [highlightActiveLine(), highlightActiveLineGutter()] : []),
isFlashEnabled,
keybindings,
};
const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
export const defaultSettings = {
keybindings: 'codemirror',
isLineNumbersDisplayed: true,
isActiveLineHighlighted: false,
isAutoCompletionEnabled: false,
isPatternHighlightingEnabled: true,
isFlashEnabled: true,
isTooltipEnabled: false,
isLineWrappingEnabled: false,
theme: 'strudelTheme',
fontFamily: 'monospace',
fontSize: 18,
};
export const codemirrorSettings = persistentAtom('codemirror-settings', defaultSettings, {
encode: JSON.stringify,
decode: JSON.parse,
});
// https://codemirror.net/docs/guide/
export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, settings, root }) {
export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, root }) {
const settings = codemirrorSettings.get();
const initialSettings = Object.keys(compartments).map((key) =>
compartments[key].of(extensions[key](parseBooleans(settings[key]))),
);
initTheme(settings.theme);
let state = EditorState.create({
doc: initialCode,
extensions: [
@@ -40,32 +72,32 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, set
// indentOnInput(), // works without. already brought with javascript extension?
// bracketMatching(), // does not do anything
closeBrackets(),
highlightActiveLineGutter(),
highlightActiveLine(),
syntaxHighlighting(defaultHighlightStyle),
history(),
EditorView.updateListener.of((v) => onChange(v)),
keymap.of([
{
key: 'Ctrl-Enter',
run: () => onEvaluate?.(),
},
{
key: 'Alt-Enter',
run: () => onEvaluate?.(),
},
{
key: 'Ctrl-.',
run: () => onStop?.(),
},
{
key: 'Alt-.',
run: (_, e) => {
e.preventDefault();
onStop?.();
drawSelection({ cursorBlinkRate: 0 }),
Prec.highest(
keymap.of([
{
key: 'Ctrl-Enter',
run: () => onEvaluate?.(),
},
},
/* {
{
key: 'Alt-Enter',
run: () => onEvaluate?.(),
},
{
key: 'Ctrl-.',
run: () => onStop?.(),
},
{
key: 'Alt-.',
run: (_, e) => {
e.preventDefault();
onStop?.();
},
},
/* {
key: 'Ctrl-Shift-.',
run: () => (onPanic ? onPanic() : onStop?.()),
},
@@ -73,7 +105,8 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, set
key: 'Ctrl-Shift-Enter',
run: () => (onReEvaluate ? onReEvaluate() : onEvaluate?.()),
}, */
]),
]),
),
],
});
@@ -85,14 +118,26 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, set
export class StrudelMirror {
constructor(options) {
const { root, initialCode = '', onDraw, drawTime = [-2, 2], prebake, settings, ...replOptions } = options;
const {
root,
id,
initialCode = '',
onDraw,
drawTime = [0, 0],
autodraw,
prebake,
bgFill = true,
...replOptions
} = options;
this.code = initialCode;
this.root = root;
this.miniLocations = [];
this.widgets = [];
this.painters = [];
this.drawTime = drawTime;
this.onDraw = onDraw;
const self = this;
this.id = id || s4();
this.drawer = new Drawer((haps, time) => {
const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped);
@@ -100,21 +145,29 @@ export class StrudelMirror {
this.onDraw?.(haps, time, currentFrame, this.painters);
}, drawTime);
// this approach might not work with multiple repls on screen..
// this approach does not work with multiple repls on screen
// TODO: refactor onPaint usages + find fix, maybe remove painters here?
Pattern.prototype.onPaint = function (onPaint) {
self.painters.push(onPaint);
return this;
};
this.prebaked = prebake();
// this.drawFirstFrame();
autodraw && this.drawFirstFrame();
this.repl = repl({
...replOptions,
onToggle: (started) => {
replOptions?.onToggle?.(started);
if (started) {
this.adjustDrawTime();
this.drawer.start(this.repl.scheduler);
// stop other repls when this one is started
document.dispatchEvent(
new CustomEvent('start-repl', {
detail: this.id,
}),
);
} else {
this.drawer.stop();
updateMiniLocations(this.editor, []);
@@ -134,22 +187,46 @@ export class StrudelMirror {
updateWidgets(this.editor, this.widgets);
updateMiniLocations(this.editor, this.miniLocations);
replOptions?.afterEval?.(options);
this.adjustDrawTime();
this.drawer.invalidate();
},
});
this.editor = initEditor({
root,
settings,
initialCode,
onChange: (v) => {
if (v.docChanged) {
this.code = v.state.doc.toString();
this.repl.setCode(this.code);
this.repl.setCode?.(this.code);
}
},
onEvaluate: () => this.evaluate(),
onStop: () => this.stop(),
});
const cmEditor = this.root.querySelector('.cm-editor');
if (cmEditor) {
this.root.style.display = 'block';
if (bgFill) {
this.root.style.backgroundColor = 'var(--background)';
}
cmEditor.style.backgroundColor = 'transparent';
}
const settings = codemirrorSettings.get();
this.setFontSize(settings.fontSize);
this.setFontFamily(settings.fontFamily);
// stop this repl when another repl is started
this.onStartRepl = (e) => {
if (e.detail !== this.id) {
this.stop();
}
};
document.addEventListener('start-repl', this.onStartRepl);
}
// adjusts draw time depending on if there are painters
adjustDrawTime() {
// when no painters are set, [0,0] is enough (just highlighting)
this.drawer.setDrawTime(this.painters.length ? this.drawTime : [0, 0]);
}
async drawFirstFrame() {
if (!this.onDraw) {
@@ -159,8 +236,9 @@ export class StrudelMirror {
await this.prebaked;
try {
await this.repl.evaluate(this.code, false);
this.drawer.invalidate(this.repl.scheduler);
this.onDraw?.(this.drawer.visibleHaps, 0, []);
this.drawer.invalidate(this.repl.scheduler, -0.001);
// draw at -0.001 to avoid haps at 0 to be visualized as active
this.onDraw?.(this.drawer.visibleHaps, -0.001, [], this.painters);
} catch (err) {
console.warn('first frame could not be painted');
}
@@ -174,7 +252,7 @@ export class StrudelMirror {
}
async toggle() {
if (this.repl.scheduler.started) {
this.repl.scheduler.stop();
this.repl.stop();
} else {
this.evaluate();
}
@@ -190,6 +268,10 @@ export class StrudelMirror {
}
setFontFamily(family) {
this.root.style.fontFamily = family;
const scroller = this.root.querySelector('.cm-scroller');
if (scroller) {
scroller.style.fontFamily = family;
}
}
reconfigureExtension(key, value) {
if (!extensions[key]) {
@@ -201,6 +283,9 @@ export class StrudelMirror {
this.editor.dispatch({
effects: compartments[key].reconfigure(newValue),
});
if (key === 'theme') {
activateTheme(value);
}
}
setLineWrappingEnabled(enabled) {
this.reconfigureExtension('isLineWrappingEnabled', enabled);
@@ -220,6 +305,8 @@ export class StrudelMirror {
for (let key in extensions) {
this.reconfigureExtension(key, settings[key]);
}
const updated = { ...codemirrorSettings.get(), ...settings };
codemirrorSettings.set(updated);
}
changeSetting(key, value) {
if (extensions[key]) {
@@ -235,8 +322,18 @@ export class StrudelMirror {
const changes = { from: 0, to: this.editor.state.doc.length, insert: code };
this.editor.dispatch({ changes });
}
clear() {
this.onStartRepl && document.removeEventListener('start-repl', this.onStartRepl);
}
}
function parseBooleans(value) {
return { true: true, false: false }[value] ?? value;
}
// helper function to generate repl ids
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
+17
View File
@@ -0,0 +1,17 @@
const parser = typeof DOMParser !== 'undefined' ? new DOMParser() : null;
export let html = (string) => {
return parser?.parseFromString(string, 'text/html').querySelectorAll('*');
};
let parseChunk = (chunk) => {
if (Array.isArray(chunk)) return chunk.flat().join('');
if (chunk === undefined) return '';
return chunk;
};
export let h = (strings, ...vars) => {
let string = '';
for (let i in strings) {
string += parseChunk(strings[i]);
string += parseChunk(vars[i]);
}
return html(string);
};
+1
View File
@@ -2,3 +2,4 @@ export * from './codemirror.mjs';
export * from './highlight.mjs';
export * from './flash.mjs';
export * from './slider.mjs';
export * from './themes.mjs';
+16 -15
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel/codemirror",
"version": "0.9.0",
"version": "0.11.0",
"description": "Codemirror Extensions for Strudel",
"main": "index.mjs",
"publishConfig": {
@@ -33,23 +33,24 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@codemirror/autocomplete": "^6.6.0",
"@codemirror/commands": "^6.2.4",
"@codemirror/lang-javascript": "^6.1.7",
"@codemirror/language": "^6.6.0",
"@codemirror/search": "^6.0.0",
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.10.0",
"@lezer/highlight": "^1.1.4",
"@codemirror/autocomplete": "^6.11.1",
"@codemirror/commands": "^6.3.3",
"@codemirror/lang-javascript": "^6.2.1",
"@codemirror/language": "^6.10.0",
"@codemirror/search": "^6.5.5",
"@codemirror/state": "^6.4.0",
"@codemirror/view": "^6.23.0",
"@lezer/highlight": "^1.2.0",
"@nanostores/persistent": "^0.9.1",
"@replit/codemirror-emacs": "^6.0.1",
"@replit/codemirror-vim": "^6.0.14",
"@replit/codemirror-vim": "^6.1.0",
"@replit/codemirror-vscode-keymap": "^6.0.2",
"@strudel.cycles/core": "workspace:*",
"@uiw/codemirror-themes": "^4.19.16",
"@uiw/codemirror-themes-all": "^4.19.16",
"react-dom": "^18.2.0"
"@strudel/core": "workspace:*",
"@uiw/codemirror-themes": "^4.21.21",
"@uiw/codemirror-themes-all": "^4.21.21",
"nanostores": "^0.9.5"
},
"devDependencies": {
"vite": "^4.3.3"
"vite": "^5.0.10"
}
}
+10 -1
View File
@@ -1,4 +1,4 @@
import { ref, pure } from '@strudel.cycles/core';
import { ref, pure } from '@strudel/core';
import { WidgetType, ViewPlugin, Decoration } from '@codemirror/view';
import { StateEffect, StateField } from '@codemirror/state';
@@ -111,6 +111,15 @@ export const sliderPlugin = ViewPlugin.fromClass(
},
);
/**
* Displays a slider widget to allow the user manipulate a value
*
* @name slider
* @param {number} value Initial value
* @param {number} min Minimum value - optional, defaults to 0
* @param {number} max Maximum value - optional, defaults to 1
* @param {number} step Step size - optional
*/
export let slider = (value) => {
console.warn('slider will only work when the transpiler is used... passing value as is');
return pure(value);
+44 -1
View File
@@ -473,6 +473,9 @@ function stringifySafe(json) {
return JSON.stringify(json, getCircularReplacer());
}
export const theme = (theme) => themes[theme] || themes.strudelTheme;
// css style injection helpers
export function injectStyle(rule) {
const newStyle = document.createElement('style');
document.head.appendChild(newStyle);
@@ -481,4 +484,44 @@ export function injectStyle(rule) {
return () => styleSheet.deleteRule(ruleIndex);
}
export const theme = (theme) => themes[theme] || themes.strudelTheme;
let currentTheme,
resetThemeStyle,
themeStyle,
styleID = 'strudel-theme-vars';
export function initTheme(theme) {
if (!document.getElementById(styleID)) {
themeStyle = document.createElement('style');
themeStyle.id = styleID;
document.head.append(themeStyle);
}
activateTheme(theme);
}
export function activateTheme(name) {
if (currentTheme === name) {
return;
}
currentTheme = name;
if (!settings[name]) {
console.warn('theme', name, 'has no settings.. defaulting to strudelTheme settings');
}
const themeSettings = settings[name] || settings.strudelTheme;
// set css variables
themeStyle.innerHTML = `:root {
${Object.entries(themeSettings)
// important to override fallback
.map(([key, value]) => `--${key}: ${value} !important;`)
.join('\n')}
}`;
// tailwind dark mode
if (themeSettings.light) {
document.documentElement.classList.remove('dark');
} else {
document.documentElement.classList.add('dark');
}
resetThemeStyle?.();
resetThemeStyle = undefined;
if (themeSettings.customStyle) {
resetThemeStyle = injectStyle(themeSettings.customStyle);
}
}
@@ -1,36 +1,40 @@
import { createRoot } from 'react-dom/client';
import { hoverTooltip } from '@codemirror/view';
import jsdoc from '../../../../doc.json';
import { Autocomplete } from './Autocomplete';
import jsdoc from '../../doc.json';
import { Autocomplete } from './autocomplete.mjs';
const getDocLabel = (doc) => doc.name || doc.longname;
let ctrlDown = false;
// Record Control key event to trigger or block the tooltip depending on the state
window.addEventListener(
'keyup',
function (e) {
if (e.key == 'Control') {
ctrlDown = false;
}
},
true,
);
if (typeof window !== 'undefined') {
// Record Control key event to trigger or block the tooltip depending on the state
window.addEventListener(
'keyup',
function (e) {
if (e.key == 'Control') {
ctrlDown = false;
}
},
true,
);
window.addEventListener(
'keydown',
function (e) {
if (e.key == 'Control') {
ctrlDown = true;
}
},
true,
);
window.addEventListener(
'keydown',
function (e) {
if (e.key == 'Control') {
ctrlDown = true;
}
},
true,
);
}
export const strudelTooltip = hoverTooltip(
(view, pos, side) => {
// Word selection from CodeMirror Hover Tooltip example https://codemirror.net/examples/tooltip/#hover-tooltips
if (!ctrlDown) {
return null;
}
let { from, to, text } = view.state.doc.lineAt(pos);
let start = pos,
end = pos;
@@ -47,11 +51,13 @@ export const strudelTooltip = hoverTooltip(
// Get entry from Strudel documentation
let entry = jsdoc.docs.filter((doc) => getDocLabel(doc) === word)[0];
if (!entry) {
return null;
}
if (!ctrlDown) {
return null;
// Try for synonyms
entry = jsdoc.docs.filter((doc) => doc.synonyms && doc.synonyms.includes(word))[0];
if (!entry) {
return null;
}
}
return {
pos: start,
end,
@@ -60,10 +66,13 @@ export const strudelTooltip = hoverTooltip(
create(view) {
let dom = document.createElement('div');
dom.className = 'strudel-tooltip';
createRoot(dom).render(<Autocomplete doc={entry} />);
const ac = Autocomplete({ doc: entry, label: word });
dom.appendChild(ac);
return { dom };
},
};
},
{ hoverTime: 10 },
);
export const isTooltipEnabled = (on) => (on ? strudelTooltip : []);
+1 -1
View File
@@ -9,7 +9,7 @@ export default defineConfig({
lib: {
entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' }[ext]),
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
},
rollupOptions: {
external: [...Object.keys(dependencies)],
+4 -4
View File
@@ -1,17 +1,17 @@
# @strudel.cycles/core
# @strudel/core
This package contains the bare essence of strudel.
## Install
```sh
npm i @strudel.cycles/core --save
npm i @strudel/core --save
```
## Example
```js
import { sequence } from '@strudel.cycles/core';
import { sequence } from '@strudel/core';
const pattern = sequence('a', ['b', 'c']);
@@ -33,7 +33,7 @@ b: 3/2 - 7/4
c: 7/4 - 2
```
- [play with @strudel.cycles/core on codesandbox](https://codesandbox.io/s/strudel-core-test-forked-9ywhv7?file=/src/index.js).
- [play with @strudel/core on codesandbox](https://codesandbox.io/s/strudel-core-test-forked-9ywhv7?file=/src/index.js).
- [open color pattern example](https://raw.githack.com/tidalcycles/strudel/main/packages/core/examples/canvas.html)
- [open minimal repl example](https://raw.githack.com/tidalcycles/strudel/main/packages/core/examples/vanilla.html)
- [open minimal vite example](./examples/vite-vanilla-repl/)
+117 -8
View File
@@ -234,7 +234,7 @@ const generic_params = [
* note("c3 e3").decay("<.1 .2 .3 .4>").sustain(0)
*
*/
['decay'],
['decay', 'dec'],
/**
* Amplitude envelope sustain level: The level which is reached after attack / decay, being sustained until the offset.
*
@@ -270,7 +270,7 @@ const generic_params = [
* s("bd sd,hh*3").bpf("<1000 2000 4000 8000>")
*
*/
[['bandf', 'bandq'], 'bpf', 'bp'],
[['bandf', 'bandq', 'bpenv'], 'bpf', 'bp'],
// TODO: in tidal, it seems to be normalized
/**
* Sets the **b**and-**p**ass **q**-factor (resonance).
@@ -381,6 +381,19 @@ const generic_params = [
*/
['coarse'],
/**
* Allows you to set the output channels on the interface
*
* @name channels
* @synonyms ch
*
* @param {number | Pattern} channels pattern the output channels
* @example
* note("e a d b g").channels("3:4")
*
*/
['channels', 'ch'],
['phaserrate', 'phasr'], // superdirt only
/**
@@ -468,7 +481,7 @@ const generic_params = [
* s("bd*8").lpf("1000:0 1000:10 1000:20 1000:30")
*
*/
[['cutoff', 'resonance'], 'ctf', 'lpf', 'lp'],
[['cutoff', 'resonance', 'lpenv'], 'ctf', 'lpf', 'lp'],
/**
* Sets the lowpass filter envelope modulation depth.
@@ -745,7 +758,7 @@ const generic_params = [
* .vibmod("<.25 .5 1 2 12>:8")
*/
[['vibmod', 'vib'], 'vmod'],
[['hcutoff', 'hresonance'], 'hpf', 'hp'],
[['hcutoff', 'hresonance', 'hpenv'], 'hpf', 'hp'],
/**
* Controls the **h**igh-**p**ass **q**-value.
*
@@ -878,6 +891,82 @@ const generic_params = [
*
*/
['freq'],
// pitch envelope
/**
* Attack time of pitch envelope.
*
* @name pattack
* @synonyms patt
* @param {number | Pattern} time time in seconds
* @example
* note("<c eb g bb>").pattack("<0 .1 .25 .5>")
*
*/
['pattack', 'patt'],
/**
* Decay time of pitch envelope.
*
* @name pdecay
* @synonyms pdec
* @param {number | Pattern} time time in seconds
* @example
* note("<c eb g bb>").pdecay("<0 .1 .25 .5>")
*
*/
['pdecay', 'pdec'],
// TODO: how to use psustain?!
['psustain', 'psus'],
/**
* Release time of pitch envelope
*
* @name prelease
* @synonyms prel
* @param {number | Pattern} time time in seconds
* @example
* note("<c eb g bb> ~")
* .release(.5) // to hear the pitch release
* .prelease("<0 .1 .25 .5>")
*
*/
['prelease', 'prel'],
/**
* Amount of pitch envelope. Negative values will flip the envelope.
* If you don't set other pitch envelope controls, `pattack:.2` will be the default.
*
* @name penv
* @param {number | Pattern} semitones change in semitones
* @example
* note("c")
* .penv("<12 7 1 .5 0 -1 -7 -12>")
*
*/
['penv'],
/**
* Curve of envelope. Defaults to linear. exponential is good for kicks
*
* @name pcurve
* @param {number | Pattern} type 0 = linear, 1 = exponential
* @example
* note("g1*2")
* .s("sine").pdec(.5)
* .penv(32)
* .pcurve("<0 1>")
*
*/
['pcurve'],
/**
* Sets the range anchor of the envelope:
* - anchor 0: range = [note, note + penv]
* - anchor 1: range = [note - penv, note]
* If you don't set an anchor, the value will default to the psustain value.
*
* @name panchor
* @param {number | Pattern} anchor anchor offset
* @example
* note("c").penv(12).panchor("<0 .5 1 .5>")
*
*/
['panchor'],
// TODO: https://tidalcycles.org/docs/configuration/MIDIOSC/control-voltage/#gate
['gate', 'gat'],
// ['hatgrain'],
@@ -1196,7 +1285,7 @@ const generic_params = [
* Formant filter to make things sound like vowels.
*
* @name vowel
* @param {string | Pattern} vowel You can use a e i o u.
* @param {string | Pattern} vowel You can use a e i o u ae aa oe ue y uh un en an on, corresponding to [a] [e] [i] [o] [u] [æ] [ɑ] [ø] [y] [ɯ] [ʌ] [œ̃] [ɛ̃] [ɑ̃] [ɔ̃]. Aliases: aa = å = ɑ, oe = ø = ö, y = ı, ae = æ.
* @example
* note("c2 <eb2 <g2 g1>>").s('sawtooth')
* .vowel("<a e i <o u>>")
@@ -1214,6 +1303,16 @@ const generic_params = [
* @name waveloss
*/
['waveloss'],
/*
* Noise crackle density
*
* @name density
* @param {number | Pattern} density between 0 and x
* @example
* s("crackle*4").density("<0.01 0.04 0.2 0.5>".slow(4))
*
*/
['density'],
// TODO: midi effects?
['dur'],
// ['modwheel'],
@@ -1371,10 +1470,20 @@ controls.adsr = register('adsr', (adsr, pat) => {
const [attack, decay, sustain, release] = adsr;
return pat.set({ attack, decay, sustain, release });
});
controls.ds = register('ds', (ds, pat) => {
ds = !Array.isArray(ds) ? [ds] : ds;
const [decay, sustain] = ds;
controls.ad = register('ad', (t, pat) => {
t = !Array.isArray(t) ? [t] : t;
const [attack, decay = attack] = t;
return pat.attack(attack).decay(decay);
});
controls.ds = register('ds', (t, pat) => {
t = !Array.isArray(t) ? [t] : t;
const [decay, sustain = 0] = t;
return pat.set({ decay, sustain });
});
controls.ds = register('ar', (t, pat) => {
t = !Array.isArray(t) ? [t] : t;
const [attack, release = attack] = t;
return pat.set({ attack, release });
});
export default controls;
+20 -3
View File
@@ -11,13 +11,14 @@ export class Cyclist {
constructor({ interval, onTrigger, onToggle, onError, getTime, latency = 0.1 }) {
this.started = false;
this.cps = 1;
this.num_ticks_since_cps_change = 0;
this.lastTick = 0; // absolute time when last tick (clock callback) happened
this.lastBegin = 0; // query begin of last tick
this.lastEnd = 0; // query end of last tick
this.getTime = getTime; // get absolute time
this.num_cycles_since_last_cps_change = 0;
this.onToggle = onToggle;
this.latency = latency; // fixed trigger time offset
const round = (x) => Math.round(x * 1000) / 1000;
this.clock = createClock(
getTime,
// called slightly before each cycle
@@ -25,14 +26,24 @@ export class Cyclist {
if (tick === 0) {
this.origin = phase;
}
if (this.num_ticks_since_cps_change === 0) {
this.num_cycles_since_last_cps_change = this.lastEnd;
}
this.num_ticks_since_cps_change++;
try {
const time = getTime();
const begin = this.lastEnd;
this.lastBegin = begin;
const end = round(begin + duration * this.cps);
//convert ticks to cycles, so you can query the pattern for events
const eventLength = duration * this.cps;
const end = this.num_cycles_since_last_cps_change + this.num_ticks_since_cps_change * eventLength;
this.lastEnd = end;
// query the pattern for events
const haps = this.pattern.queryArc(begin, end);
const tickdeadline = phase - time; // time left till phase begins
const tickdeadline = phase - time; // time left until the phase is a whole number
this.lastTick = time + tickdeadline;
haps.forEach((hap) => {
@@ -59,6 +70,8 @@ export class Cyclist {
this.onToggle?.(v);
}
start() {
this.num_ticks_since_cps_change = 0;
this.num_cycles_since_last_cps_change = 0;
if (!this.pattern) {
throw new Error('Scheduler: no pattern set! call .setPattern first.');
}
@@ -84,7 +97,11 @@ export class Cyclist {
}
}
setCps(cps = 1) {
if (this.cps === cps) {
return;
}
this.cps = cps;
this.num_ticks_since_cps_change = 0;
}
log(begin, end, haps) {
const onsets = haps.filter((h) => h.hasOnset());
+9 -5
View File
@@ -111,8 +111,6 @@ export class Framer {
// see vite-vanilla-repl-cm6 for an example
export class Drawer {
constructor(onDraw, drawTime) {
let [lookbehind, lookahead] = drawTime; // e.g. [-2, 2]
lookbehind = Math.abs(lookbehind);
this.visibleHaps = [];
this.lastFrame = null;
this.drawTime = drawTime;
@@ -122,6 +120,8 @@ export class Drawer {
console.warn('Drawer: no scheduler');
return;
}
const lookbehind = Math.abs(this.drawTime[0]);
const lookahead = this.drawTime[1];
// calculate current frame time (think right side of screen for pianoroll)
const phase = this.scheduler.now() + lookahead;
// first frame just captures the phase
@@ -145,12 +145,16 @@ export class Drawer {
},
);
}
invalidate(scheduler = this.scheduler) {
if (!scheduler || !scheduler.pattern) {
setDrawTime(drawTime) {
this.drawTime = drawTime;
}
invalidate(scheduler = this.scheduler, t) {
if (!scheduler) {
return;
}
// TODO: scheduler.now() seems to move even when it's stopped, this hints at a bug...
t = t ?? scheduler.now();
this.scheduler = scheduler;
const t = scheduler.now();
let [_, lookahead] = this.drawTime;
const [begin, end] = [Math.max(t, 0), t + lookahead + 0.1];
// remove all future haps
+14
View File
@@ -145,6 +145,8 @@ export const { euclidrot, euclidRot } = register(['euclidrot', 'euclidRot'], fun
* so there will be no gaps.
* @name euclidLegato
* @memberof Pattern
* @param {number} pulses the number of onsets / beats
* @param {number} steps the number of steps to fill
* @example
* n("g2").decay(.1).sustain(.3).euclidLegato(3,8)
*/
@@ -166,6 +168,18 @@ export const euclidLegato = register(['euclidLegato'], function (pulses, steps,
return _euclidLegato(pulses, steps, 0, pat);
});
/**
* Similar to `euclid`, but each pulse is held until the next pulse,
* so there will be no gaps, and has an additional parameter for 'rotating'
* the resulting sequence
* @name euclidLegatoRot
* @memberof Pattern
* @param {number} pulses the number of onsets / beats
* @param {number} steps the number of steps to fill
* @param {number} rotation offset in steps
* @example
* note("c3").euclidLegatoRot(3,5,2)
*/
export const euclidLegatoRot = register(['euclidLegatoRot'], function (pulses, steps, rotation, pat) {
return _euclidLegato(pulses, steps, rotation, pat);
});
-5
View File
@@ -47,10 +47,5 @@ export const evaluate = async (code, transpiler) => {
// if no transpiler is given, we expect a single instruction (!wrapExpression)
const options = { wrapExpression: !!transpiler };
let evaluated = await safeEval(code, options);
if (!isPattern(evaluated)) {
console.log('evaluated', evaluated);
const message = `got "${typeof evaluated}" instead of pattern`;
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
}
return { mode: 'javascript', pattern: evaluated, meta };
};
@@ -1,8 +0,0 @@
# vite-vanilla-repl-cm6
This folder demonstrates how to set up a strudel repl using vite and vanilla JS + codemirror. Run it using:
```sh
pnpm i
pnpm dev
```
@@ -1,23 +0,0 @@
{
"name": "vite-vanilla-repl-cm6",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^4.3.2"
},
"dependencies": {
"@strudel/codemirror": "workspace:*",
"@strudel.cycles/core": "workspace:*",
"@strudel.cycles/mini": "workspace:*",
"@strudel.cycles/soundfonts": "workspace:*",
"@strudel.cycles/tonal": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*"
}
}
@@ -1 +0,0 @@
!dist
@@ -1,8 +0,0 @@
# vite-vanilla-repl
This folder demonstrates how to set up a strudel repl using vite and vanilla JS. Run it using:
```sh
npm i
npm run dev
```
@@ -1 +0,0 @@
import{b as s,h as i,m,a as n,c as p,p as t}from"./index.4cbc0a10.js";export{s as SyntaxError,i as h,m as mini,n as minify,p as parse,t as patternifyAST};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
import{g as s,f as d,i as t,n as r,l as u,j as o,d as f,k as p,r as g,s as i,w as l,e as m}from"./index.4cbc0a10.js";export{s as getAudioContext,d as getCachedBuffer,t as getLoadedBuffer,r as getLoadedSamples,u as loadBuffer,o as loadGithubSamples,f as panic,p as resetLoadedSamples,g as reverseBuffer,i as samples,l as webaudioOutput,m as webaudioOutputTrigger};
@@ -1,36 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite Vanilla Strudel REPL</title>
<script type="module" crossorigin src="/tidalcycles/strudel/use-acorn/packages/core/examples/vite-vanilla-repl/dist/assets/index.4cbc0a10.js"></script>
</head>
<body style="margin: 0; background: #222">
<div style="display: grid; height: 100vh">
<textarea
id="text"
style="font-size: 2em; border: 0; color: white; background: transparent; outline: none; padding: 20px"
spellcheck="false"
></textarea>
</div>
<button
id="start"
style="
position: absolute;
border-radius: 10px;
top: 20px;
right: 20px;
padding: 20px;
border: 2px solid white;
background: transparent;
color: white;
cursor: pointer;
"
>
evaluate
</button>
<div id="output"></div>
</body>
</html>
-12
View File
@@ -1,12 +0,0 @@
/*
gist.js - <short description TODO>
Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/strudel/blob/main/packages/core/gist.js>
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// this is a shortcut to eval code from a gist
// why? to be able to shorten strudel code + e.g. be able to change instruments after links have been generated
export default (route, cache = true) =>
fetch(`https://gist.githubusercontent.com/${route}?cachebust=${cache ? '' : Date.now()}`)
.then((res) => res.text())
.then((code) => eval(code));
+3 -4
View File
@@ -27,16 +27,15 @@ export * from './pianoroll.mjs';
export * from './spiral.mjs';
export * from './ui.mjs';
export { default as drawLine } from './drawLine.mjs';
export { default as gist } from './gist.js';
// below won't work with runtime.mjs (json import fails)
/* import * as p from './package.json';
export const version = p.version; */
logger('🌀 @strudel.cycles/core loaded 🌀');
logger('🌀 @strudel/core loaded 🌀');
if (globalThis._strudelLoaded) {
console.warn(
`@strudel.cycles/core was loaded more than once...
`@strudel/core was loaded more than once...
This might happen when you have multiple versions of strudel installed.
Please check with "npm ls @strudel.cycles/core".`,
Please check with "npm ls @strudel/core".`,
);
}
globalThis._strudelLoaded = true;
+5 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/core",
"version": "0.9.0",
"name": "@strudel/core",
"version": "0.11.0",
"description": "Port of Tidal Cycles to JavaScript",
"main": "index.mjs",
"type": "module",
@@ -31,12 +31,11 @@
},
"homepage": "https://strudel.cc",
"dependencies": {
"fraction.js": "^4.2.0",
"nanostores": "^0.8.1"
"fraction.js": "^4.3.7"
},
"gitHead": "0e26d4e741500f5bae35b023608f062a794905c2",
"devDependencies": {
"vite": "^4.3.3",
"vitest": "^0.33.0"
"vite": "^5.0.10",
"vitest": "^1.1.0"
}
}
+18 -10
View File
@@ -1154,8 +1154,8 @@ export function isPattern(thing) {
/* if (!thing instanceof Pattern) {
console.warn(
`Found Pattern that fails "instanceof Pattern" check.
This may happen if you are using multiple versions of @strudel.cycles/core.
Please check by running "npm ls @strudel.cycles/core".`,
This may happen if you are using multiple versions of @strudel/core.
Please check by running "npm ls @strudel/core".`,
);
console.log(thing);
} */
@@ -1178,7 +1178,7 @@ export function reify(thing) {
* @return {Pattern}
* @synonyms polyrhythm, pr
* @example
* stack(g3, b3, [e4, d4]).note() // "g3,b3,[e4,d4]".note()
* stack("g3", "b3", ["e4", "d4"]).note() // "g3,b3,[e4,d4]".note()
*/
export function stack(...pats) {
// Array test here is to avoid infinite recursions..
@@ -1193,7 +1193,7 @@ export function stack(...pats) {
*
* @return {Pattern}
* @example
* slowcat(e5, b4, [d5, c5])
* slowcat("e5", "b4", ["d5", "c5"])
*
*/
export function slowcat(...pats) {
@@ -1237,7 +1237,7 @@ export function slowcatPrime(...pats) {
* @synonyms slowcat
* @return {Pattern}
* @example
* cat(e5, b4, [d5, c5]).note() // "<e5 b4 [d5 c5]>".note()
* cat("e5", "b4", ["d5", "c5"]).note() // "<e5 b4 [d5 c5]>".note()
*
*/
export function cat(...pats) {
@@ -1247,7 +1247,7 @@ export function cat(...pats) {
/** Like {@link Pattern.seq}, but each step has a length, relative to the whole.
* @return {Pattern}
* @example
* timeCat([3,e3],[1, g3]).note() // "e3@3 g3".note()
* timeCat([3,"e3"],[1, "g3"]).note() // "e3@3 g3".note()
*/
export function timeCat(...timepats) {
const total = timepats.map((a) => a[0]).reduce((a, b) => a.add(b), Fraction(0));
@@ -1287,7 +1287,7 @@ export function sequence(...pats) {
/** Like **cat**, but the items are crammed into one cycle.
* @synonyms fastcat, sequence
* @example
* seq(e5, b4, [d5, c5]).note() // "e5 b4 [d5 c5]".note()
* seq("e5", "b4", ["d5", "c5"]).note() // "e5 b4 [d5 c5]".note()
*
*/
export function seq(...pats) {
@@ -1975,9 +1975,9 @@ export const press = register('press', function (pat) {
* s("hh*3")
* )
*/
export const hush = register('hush', function (pat) {
Pattern.prototype.hush = function () {
return silence;
});
};
/**
* Applies `rev` to a pattern every other cycle, so that the pattern alternates between forwards and backwards.
@@ -1985,7 +1985,7 @@ export const hush = register('hush', function (pat) {
* note("c d e g").palindrome()
*/
export const palindrome = register('palindrome', function (pat) {
return pat.every(2, rev);
return pat.lastOf(2, rev);
});
/**
@@ -2189,6 +2189,14 @@ export const duration = register('duration', function (value, pat) {
return pat.withHapSpan((span) => new TimeSpan(span.begin, span.begin.add(value)));
});
export const hsla = register('hsla', (h, s, l, a, pat) => {
return pat.color(`hsla(${h}turn,${s * 100}%,${l * 100}%,${a})`);
});
export const hsl = register('hsl', (h, s, l, pat) => {
return pat.color(`hsl(${h}turn,${s * 100}%,${l * 100}%)`);
});
/**
* Sets the color of the hap in visualizations like pianoroll or highlighting.
* @name color
+13 -5
View File
@@ -120,7 +120,6 @@ export function pianoroll({
hideInactive = 0,
colorizeInactive = 1,
fontFamily,
clear = true,
ctx,
} = {}) {
const w = ctx.canvas.width;
@@ -166,7 +165,7 @@ export function pianoroll({
barThickness = fold ? valueAxis / foldValues.length : valueAxis / valueExtent;
ctx.fillStyle = background;
ctx.globalAlpha = 1; // reset!
if (clear && !smear) {
if (!smear) {
ctx.clearRect(0, 0, w, h);
ctx.fillRect(0, 0, w, h);
}
@@ -257,12 +256,21 @@ export function getDrawOptions(drawTime, options = {}) {
return { fold: 1, ...options, cycles, playhead };
}
export const getPunchcardPainter =
(options = {}) =>
(ctx, time, haps, drawTime, paintOptions = {}) =>
pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) });
Pattern.prototype.punchcard = function (options) {
return this.onPaint((ctx, time, haps, drawTime, paintOptions = {}) =>
pianoroll({ ctx, time, haps, ...getDrawOptions(drawTime, { ...paintOptions, ...options }) }),
);
return this.onPaint(getPunchcardPainter(options));
};
/**
* Displays a vertical pianoroll with event labels.
* Supports all the same options as pianoroll.
*
* @name wordfall
*/
Pattern.prototype.wordfall = function (options) {
return this.punchcard({ vertical: 1, labels: 1, stroke: 0, fillActive: 1, active: 'white', ...options });
};
+86 -42
View File
@@ -3,23 +3,7 @@ import { evaluate as _evaluate } from './evaluate.mjs';
import { logger } from './logger.mjs';
import { setTime } from './time.mjs';
import { evalScope } from './evaluate.mjs';
import { register } from './pattern.mjs';
import { atom, computed } from 'nanostores';
export const $replstate = atom({
schedulerError: undefined,
evalError: undefined,
code: '// LOADING',
activeCode: '// LOADING',
pattern: undefined,
miniLocations: [],
widgets: [],
pending: true,
started: false,
});
export const $repldirty = computed($replstate, (s) => s.code !== s.activeCode);
export const setReplState = (key, value) => $replstate.set({ ...$replstate.get(), [key]: value });
import { register, Pattern, isPattern, silence, stack } from './pattern.mjs';
export function repl({
interval,
@@ -32,52 +16,87 @@ export function repl({
transpiler,
onToggle,
editPattern,
onUpdateState,
}) {
const state = {
schedulerError: undefined,
evalError: undefined,
code: '// LOADING',
activeCode: '// LOADING',
pattern: undefined,
miniLocations: [],
widgets: [],
pending: false,
started: false,
};
const updateState = (update) => {
Object.assign(state, update);
state.isDirty = state.code !== state.activeCode;
state.error = state.evalError || state.schedulerError;
onUpdateState?.(state);
};
const scheduler = new Cyclist({
interval,
onTrigger: getTrigger({ defaultOutput, getTime }),
onError: onSchedulerError,
getTime,
onToggle: (started) => {
setReplState('started', started);
updateState({ started });
onToggle?.(started);
},
});
let playPatterns = [];
let pPatterns = {};
let allTransform;
const hush = function () {
pPatterns = {};
allTransform = undefined;
return silence;
};
const setPattern = (pattern, autostart = true) => {
pattern = editPattern?.(pattern) || pattern;
scheduler.setPattern(pattern, autostart);
};
setTime(() => scheduler.now()); // TODO: refactor?
const evaluate = async (code, autostart = true) => {
const evaluate = async (code, autostart = true, shouldHush = true) => {
if (!code) {
throw new Error('no code to evaluate');
}
try {
setReplState('code', code);
setReplState('pending', true);
updateState({ code, pending: true });
await beforeEval?.({ code });
playPatterns = [];
shouldHush && hush();
let { pattern, meta } = await _evaluate(code, transpiler);
if (playPatterns.length) {
pattern = pattern.stack(...playPatterns);
if (Object.keys(pPatterns).length) {
pattern = stack(...Object.values(pPatterns));
}
if (allTransform) {
pattern = allTransform(pattern);
}
if (!isPattern(pattern)) {
const message = `got "${typeof evaluated}" instead of pattern`;
throw new Error(message + (typeof evaluated === 'function' ? ', did you forget to call a function?' : '.'));
}
logger(`[eval] code updated`);
setPattern(pattern, autostart);
setReplState('miniLocations', meta?.miniLocations || []);
setReplState('widgets', meta?.widgets || []);
setReplState('activeCode', code);
setReplState('pattern', pattern);
setReplState('evalError', undefined);
setReplState('schedulerError', undefined);
setReplState('pending', false);
updateState({
miniLocations: meta?.miniLocations || [],
widgets: meta?.widgets || [],
activeCode: code,
pattern,
evalError: undefined,
schedulerError: undefined,
pending: false,
});
afterEval?.({ code, pattern, meta });
return pattern;
} catch (err) {
// console.warn(`[repl] eval error: ${err.message}`);
logger(`[eval] error: ${err.message}`, 'error');
setReplState('evalError', err);
setReplState('pending', false);
updateState({ evalError: err, pending: false });
onEvalError?.(err);
}
};
@@ -93,10 +112,35 @@ export function repl({
return pat.loopAtCps(cycles, scheduler.cps);
});
const play = register('play', (pat) => {
playPatterns.push(pat);
return pat;
});
Pattern.prototype.p = function (id) {
pPatterns[id] = this;
return this;
};
Pattern.prototype.q = function (id) {
return silence;
};
const all = function (transform) {
allTransform = transform;
return silence;
};
try {
for (let i = 1; i < 10; ++i) {
Object.defineProperty(Pattern.prototype, `d${i}`, {
get() {
return this.p(i);
},
});
Object.defineProperty(Pattern.prototype, `p${i}`, {
get() {
return this.p(i);
},
});
Pattern.prototype[`q${i}`] = silence;
}
} catch (err) {
// already defined..
}
const fit = register('fit', (pat) =>
pat.withHap((hap) =>
@@ -111,15 +155,15 @@ export function repl({
evalScope({
loopAt,
fit,
play,
all,
hush,
setCps,
setcps: setCps,
setCpm,
setcpm: setCpm,
});
const setCode = (c) => setReplState('code', c);
return { scheduler, evaluate, start, stop, pause, setCps, setPattern, setCode, toggle };
const setCode = (code) => updateState({ code });
return { scheduler, evaluate, start, stop, pause, setCps, setPattern, setCode, toggle, state };
}
export const getTrigger =
+1
View File
@@ -101,6 +101,7 @@ const timeToRand = (x) => Math.abs(intSeedToRand(timeToIntSeed(x)));
const timeToRandsPrime = (seed, n) => {
const result = [];
// eslint-disable-next-line
for (let i = 0; i < n; ++n) {
result.push(intSeedToRand(seed));
seed = xorwise(seed);
+3 -3
View File
@@ -67,9 +67,9 @@ Pattern.prototype.spiral = function (options = {}) {
// logSpiral = true,
} = options;
function spiral({ ctx, time, haps, drawTime, clear }) {
function spiral({ ctx, time, haps, drawTime }) {
const [w, h] = [ctx.canvas.width, ctx.canvas.height];
clear && ctx.clearRect(0, 0, w * 2, h * 2);
ctx.clearRect(0, 0, w * 2, h * 2);
const [cx, cy] = [w / 2, h / 2];
const settings = {
margin: size / stretch,
@@ -114,5 +114,5 @@ Pattern.prototype.spiral = function (options = {}) {
});
}
return this.onPaint((ctx, time, haps, drawTime, options) => spiral({ ctx, time, haps, drawTime, ...options }));
return this.onPaint((ctx, time, haps, drawTime) => spiral({ ctx, time, haps, drawTime }));
};
+46 -11
View File
@@ -20,6 +20,7 @@ import {
slowcat,
cat,
sequence,
palindrome,
polymeter,
polymeterSteps,
polyrhythm,
@@ -182,13 +183,17 @@ describe('Pattern', () => {
});
it('can Trig() structure', () => {
sameFirst(
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10).add.trig(20, 30).early(2),
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10)
.add.trig(20, 30)
.early(2),
sequence(26, 27, 36, 37),
);
});
it('can Trigzero() structure', () => {
sameFirst(
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10).add.trigzero(20, 30).early(2),
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10)
.add.trigzero(20, 30)
.early(2),
sequence(21, 22, 31, 32),
);
});
@@ -230,13 +235,17 @@ describe('Pattern', () => {
});
it('can Trig() structure', () => {
sameFirst(
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10).keep.trig(20, 30).early(2),
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10)
.keep.trig(20, 30)
.early(2),
sequence(6, 7, 6, 7),
);
});
it('can Trigzero() structure', () => {
sameFirst(
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10).keep.trigzero(20, 30).early(2),
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10)
.keep.trigzero(20, 30)
.early(2),
sequence(1, 2, 1, 2),
);
});
@@ -272,13 +281,17 @@ describe('Pattern', () => {
});
it('can Trig() structure', () => {
sameFirst(
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10).keepif.trig(false, true).early(2),
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10)
.keepif.trig(false, true)
.early(2),
sequence(silence, silence, 6, 7),
);
});
it('can Trigzero() structure', () => {
sameFirst(
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10).keepif.trigzero(false, true).early(2),
slowcat(sequence(1, 2, 3, 4), 5, sequence(6, 7, 8, 9), 10)
.keepif.trigzero(false, true)
.early(2),
sequence(silence, silence, 1, 2),
);
});
@@ -571,6 +584,18 @@ describe('Pattern', () => {
expect(sequence(1, 2, 3).firstCycle()).toStrictEqual(fastcat(1, 2, 3).firstCycle());
});
});
describe('palindrome()', () => {
it('Can create palindrome', () => {
expect(
fastcat('a', 'b', 'c')
.palindrome()
.fast(2)
.firstCycle()
.sort((a, b) => a.part.begin.sub(b.part.begin))
.map((a) => a.value),
).toStrictEqual(['a', 'b', 'c', 'c', 'b', 'a']);
});
});
describe('polyrhythm()', () => {
it('Can layer up cycles', () => {
expect(polyrhythm(['a', 'b'], ['c']).firstCycle()).toStrictEqual(
@@ -638,7 +663,11 @@ describe('Pattern', () => {
});
describe('struct()', () => {
it('Can restructure a discrete pattern', () => {
expect(sequence('a', 'b').struct(sequence(true, true, true)).firstCycle()).toStrictEqual([
expect(
sequence('a', 'b')
.struct(sequence(true, true, true))
.firstCycle(),
).toStrictEqual([
hap(ts(0, third), ts(0, third), 'a'),
hap(ts(third, twothirds), ts(third, 0.5), 'a'),
hap(ts(third, twothirds), ts(0.5, twothirds), 'b'),
@@ -669,7 +698,11 @@ describe('Pattern', () => {
});
describe('mask()', () => {
it('Can fragment a pattern', () => {
expect(sequence('a', 'b').mask(sequence(true, true, true)).firstCycle()).toStrictEqual([
expect(
sequence('a', 'b')
.mask(sequence(true, true, true))
.firstCycle(),
).toStrictEqual([
hap(ts(0, 0.5), ts(0, third), 'a'),
hap(ts(0, 0.5), ts(third, 0.5), 'a'),
hap(ts(0.5, 1), ts(0.5, twothirds), 'b'),
@@ -938,9 +971,11 @@ describe('Pattern', () => {
expect(stack(pure('a').mask(1, 0), pure('a').mask(0, 1)).defragmentHaps().firstCycle().length).toStrictEqual(1);
});
it('Doesnt merge two overlapping haps', () => {
expect(stack(pure('a').mask(1, 1, 0), pure('a').mask(0, 1)).defragmentHaps().firstCycle().length).toStrictEqual(
2,
);
expect(
stack(pure('a').mask(1, 1, 0), pure('a').mask(0, 1))
.defragmentHaps()
.firstCycle().length,
).toStrictEqual(2);
});
it('Doesnt merge two touching haps with different values', () => {
expect(stack(pure('a').mask(1, 0), pure('b').mask(0, 1)).defragmentHaps().firstCycle().length).toStrictEqual(2);
+50 -8
View File
@@ -4,6 +4,8 @@ Copyright (C) 2022 Strudel contributors - see <https://github.com/tidalcycles/st
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { logger } from './logger.mjs';
// returns true if the given string is a note
export const isNoteWithOctave = (name) => /^[a-gA-G][#bs]*[0-9]$/.test(name);
export const isNote = (name) => /^[a-gA-G][#bsf]*[0-9]?$/.test(name);
@@ -84,6 +86,18 @@ export const midi2note = (n) => {
// modulo that works with negative numbers e.g. _mod(-1, 3) = 2. Works on numbers (rather than patterns of numbers, as @mod@ from pattern.mjs does)
export const _mod = (n, m) => ((n % m) + m) % m;
export function nanFallback(value, fallback = 0) {
if (isNaN(Number(value))) {
logger(`"${value}" is not a number, falling back to ${fallback}`, 'warning');
return fallback;
}
return value;
}
// round to nearest int, negative numbers will output a subtracted index
export const getSoundIndex = (n, numSounds) => {
return _mod(Math.round(nanFallback(n ?? 0, 0)), numSounds);
};
export const getPlayableNoteValue = (hap) => {
let { value, context } = hap;
let note = value;
@@ -262,15 +276,43 @@ export const sol2note = (n, notation = 'letters') => {
notation === 'solfeggio'
? solfeggio /*check if its is any of the following*/
: notation === 'indian'
? indian
: notation === 'german'
? german
: notation === 'byzantine'
? byzantine
: notation === 'japanese'
? japanese
: english; /*if not use standard version*/
? indian
: notation === 'german'
? german
: notation === 'byzantine'
? byzantine
: notation === 'japanese'
? japanese
: english; /*if not use standard version*/
const note = pc[n % 12]; /*calculating the midi value to the note*/
const oct = Math.floor(n / 12) - 1;
return note + oct;
};
// code hashing helpers
export function unicodeToBase64(text) {
const utf8Bytes = new TextEncoder().encode(text);
const base64String = btoa(String.fromCharCode(...utf8Bytes));
return base64String;
}
export function base64ToUnicode(base64String) {
const utf8Bytes = new Uint8Array(
atob(base64String)
.split('')
.map((char) => char.charCodeAt(0)),
);
const decodedText = new TextDecoder().decode(utf8Bytes);
return decodedText;
}
export function code2hash(code) {
return encodeURIComponent(unicodeToBase64(code));
//return '#' + encodeURIComponent(btoa(code));
}
export function hash2code(hash) {
return base64ToUnicode(decodeURIComponent(hash));
//return atob(decodeURIComponent(codeParam || ''));
}
+1 -1
View File
@@ -9,7 +9,7 @@ export default defineConfig({
lib: {
entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' }[ext]),
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
},
rollupOptions: {
external: [...Object.keys(dependencies)],
+1
View File
@@ -0,0 +1 @@
# @strudel/csound
+2 -2
View File
@@ -1,5 +1,5 @@
import { getFrequency, logger, register } from '@strudel.cycles/core';
import { getAudioContext } from '@strudel.cycles/webaudio';
import { getFrequency, logger, register } from '@strudel/core';
import { getAudioContext } from '@strudel/webaudio';
import csd from './project.csd?raw';
// import livecodeOrc from './livecode.orc?raw';
import presetsOrc from './presets.orc?raw';
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/csound",
"version": "0.9.0",
"name": "@strudel/csound",
"version": "0.11.0",
"description": "csound bindings for strudel",
"main": "index.mjs",
"publishConfig": {
@@ -33,10 +33,10 @@
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@csound/browser": "6.18.7",
"@strudel.cycles/core": "workspace:*",
"@strudel.cycles/webaudio": "workspace:*"
"@strudel/core": "workspace:*",
"@strudel/webaudio": "workspace:*"
},
"devDependencies": {
"vite": "^4.3.3"
"vite": "^5.0.10"
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ export default defineConfig({
lib: {
entry: resolve(__dirname, 'index.mjs'),
formats: ['es', 'cjs'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' }[ext]),
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
},
rollupOptions: {
external: [...Object.keys(dependencies)],
+1 -1
View File
@@ -1,5 +1,5 @@
import { Invoke } from './utils.mjs';
import { Pattern, noteToMidi } from '@strudel.cycles/core';
import { Pattern, noteToMidi } from '@strudel/core';
const ON_MESSAGE = 0x90;
const OFF_MESSAGE = 0x80;
+1 -1
View File
@@ -1,4 +1,4 @@
import { parseNumeral, Pattern } from '@strudel.cycles/core';
import { parseNumeral, Pattern } from '@strudel/core';
import { Invoke } from './utils.mjs';
Pattern.prototype.osc = function () {
+2 -2
View File
@@ -22,8 +22,8 @@
"url": "https://github.com/tidalcycles/strudel/issues"
},
"dependencies": {
"@strudel.cycles/core": "workspace:*",
"@tauri-apps/api": "^1.4.0"
"@strudel/core": "workspace:*",
"@tauri-apps/api": "^1.5.3"
},
"homepage": "https://github.com/tidalcycles/strudel#readme"
}
+3 -3
View File
@@ -1,13 +1,13 @@
# @strudel.cycles/embed
# @strudel/embed
This package contains a embeddable web component for the Strudel REPL.
## Usage
Either install with `npm i @strudel.cycles/embed` or just use a cdn to import the script:
Either install with `npm i @strudel/embed` or just use a cdn to import the script:
```html
<script src="https://unpkg.com/@strudel.cycles/embed@latest"></script>
<script src="https://unpkg.com/@strudel/embed@latest"></script>
<strudel-repl>
<!--
note(`[[e5 [b4 c5] d5 [c5 b4]]
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel.cycles/embed",
"version": "0.2.0",
"name": "@strudel/embed",
"version": "0.11.0",
"description": "Embeddable Web Component to load a Strudel REPL into an iframe",
"main": "embed.js",
"type": "module",
+7 -1
View File
@@ -12,6 +12,12 @@ await initHydra();
Then you can use hydra below!
### options
You can also pass options to the `initHydra` function. These can be used to set [hydra options](https://github.com/hydra-synth/hydra-synth#api) + these strudel specific options:
- `feedStrudel`: sends the strudel canvas to `s0`. The strudel canvas is used to draw `pianoroll`, `spiral`, `scope` etc..
## Usage via npm
```sh
@@ -21,7 +27,7 @@ npm i @strudel/hydra
Then add the import to your evalScope:
```js
import { evalScope } from '@strudel.cycles/core';
import { evalScope } from '@strudel/core';
evalScope(
import('@strudel/hydra')
+34 -9
View File
@@ -1,14 +1,39 @@
import { getDrawContext } from '@strudel.cycles/core';
import { getDrawContext } from '@strudel/core';
export async function initHydra() {
let latestOptions;
function appendCanvas(c) {
const { canvas: testCanvas } = getDrawContext();
c.canvas.id = 'hydra-canvas';
c.canvas.style.position = 'fixed';
c.canvas.style.top = '0px';
testCanvas.after(c.canvas);
return testCanvas;
}
export async function initHydra(options = {}) {
// reset if options have changed since last init
if (latestOptions && JSON.stringify(latestOptions) !== JSON.stringify(options)) {
document.getElementById('hydra-canvas').remove();
}
latestOptions = options;
//load and init hydra
if (!document.getElementById('hydra-canvas')) {
const { canvas: testCanvas } = getDrawContext();
await import('https://unpkg.com/hydra-synth');
const hydraCanvas = testCanvas.cloneNode(true);
hydraCanvas.id = 'hydra-canvas';
testCanvas.after(hydraCanvas);
new Hydra({ canvas: hydraCanvas, detectAudio: false });
s0.init({ src: testCanvas });
console.log('reinit..');
const {
src = 'https://unpkg.com/hydra-synth',
feedStrudel = false,
...hydraConfig
} = { detectAudio: false, ...options };
await import(/* @vite-ignore */ src);
const hydra = new Hydra(hydraConfig);
if (feedStrudel) {
const { canvas } = getDrawContext();
canvas.style.display = 'none';
hydra.synth.s0.init({ src: canvas });
}
appendCanvas(hydra);
}
}
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@strudel/hydra",
"version": "0.9.0",
"version": "0.11.0",
"description": "Hydra integration for strudel",
"main": "hydra.mjs",
"publishConfig": {
@@ -33,11 +33,11 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
"@strudel.cycles/core": "workspace:*",
"@strudel/core": "workspace:*",
"hydra-synth": "^1.3.29"
},
"devDependencies": {
"pkg": "^5.8.1",
"vite": "^4.3.3"
"vite": "^5.0.10"
}
}
+1 -1
View File
@@ -9,7 +9,7 @@ export default defineConfig({
lib: {
entry: resolve(__dirname, 'hydra.mjs'),
formats: ['es', 'cjs'],
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' }[ext]),
fileName: (ext) => ({ es: 'index.mjs', cjs: 'index.js' })[ext],
},
rollupOptions: {
external: [...Object.keys(dependencies)],
+2 -2
View File
@@ -1,9 +1,9 @@
# @strudel.cycles/midi
# @strudel/midi
This package adds midi functionality to strudel Patterns.
## Install
```sh
npm i @strudel.cycles/midi --save
npm i @strudel/midi --save
```

Some files were not shown because too many files have changed in this diff Show More