diff --git a/doc.json b/doc.json index af56ea59..9f5f2f29 100644 --- a/doc.json +++ b/doc.json @@ -1354,7 +1354,7 @@ "meta": { "range": [ 1178, - 31915 + 31622 ], "filename": "pattern.mjs", "lineno": 17, @@ -2876,61 +2876,11 @@ "___id": "T000002R000651", "___s": true }, - { - "comment": "/**\n *\n * @param {...any} funcs\n * @returns Pattern\n * @example\n * \"<[0 1 2 0]!2 [2 3 4 ~]!2 [[4 5] [4 3] 2 [0 ~]]!2 [0 -3 0 ~]!2>\"\n * .layer(\n * x=>x,\n * x=>x.add(7).late(2),\n * x=>x.add(14).late(4),\n * x=>x.add(21).late(6),\n * )\n * .slow(3)\n * .scale('C2 major')\n * .tone((await piano()).toDestination())\n */", - "meta": { - "range": [ - 21980, - 22055 - ], - "filename": "pattern.mjs", - "lineno": 700, - "columnno": 2, - "path": "/home/felix/projects/strudel/packages/core", - "code": { - "id": "astnode100007825", - "name": "Pattern#layer", - "type": "MethodDefinition", - "paramnames": [ - "funcs" - ] - }, - "vars": { - "": null - } - }, - "params": [ - { - "type": { - "names": [ - "any" - ] - }, - "variable": true, - "name": "funcs" - } - ], - "returns": [ - { - "description": "

Pattern

" - } - ], - "examples": [ - "\"<[0 1 2 0]!2 [2 3 4 ~]!2 [[4 5] [4 3] 2 [0 ~]]!2 [0 -3 0 ~]!2>\"\n.layer(\n x=>x,\n x=>x.add(7).late(2),\n x=>x.add(14).late(4),\n x=>x.add(21).late(6),\n)\n.slow(3)\n.scale('C2 major')\n.tone((await piano()).toDestination())" - ], - "name": "layer", - "longname": "Pattern#layer", - "kind": "function", - "memberof": "Pattern", - "scope": "instance", - "___id": "T000002R000683", - "___s": true - }, { "comment": "/**\n * Speed up a pattern by the given factor.\n *\n * @name fast\n * @memberof Pattern\n * @param {number | Pattern} factor speed up factor\n * @returns Pattern\n * @example\n * seq(e5, b4, d5, c5).fast(2)\n */", "meta": { "filename": "pattern.mjs", - "lineno": 750, + "lineno": 735, "columnno": 2, "path": "/home/felix/projects/strudel/packages/core", "code": {} @@ -2968,7 +2918,7 @@ "comment": "/**\n * Slow down a pattern over the given number of cycles.\n *\n * @name slow\n * @memberof Pattern\n * @param {number | Pattern} factor slow down factor\n * @returns Pattern\n * @example\n * seq(e5, b4, d5, c5).slow(2)\n */", "meta": { "filename": "pattern.mjs", - "lineno": 765, + "lineno": 750, "columnno": 2, "path": "/home/felix/projects/strudel/packages/core", "code": {} @@ -3006,11 +2956,11 @@ "comment": "/**\n * Returns a new pattern where every other cycle is played once, twice as\n * fast, and offset in time by one quarter of a cycle. Creates a kind of\n * breakbeat feel.\n * @returns Pattern\n */", "meta": { "range": [ - 28139, - 28235 + 27788, + 27884 ], "filename": "pattern.mjs", - "lineno": 919, + "lineno": 904, "columnno": 2, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3042,11 +2992,11 @@ "comment": "/** A discrete value that repeats once per cycle:\n *\n * @param {any} value - The value to repeat\n * @returns {Pattern}\n * @example\n * pure('e4')\n */", "meta": { "range": [ - 35996, - 36200 + 35703, + 35907 ], "filename": "pattern.mjs", - "lineno": 1217, + "lineno": 1203, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3093,11 +3043,11 @@ "comment": "/** The given items are played at the same time at the same length:\n *\n * @param {...any} items - The items to stack\n * @return {Pattern}\n * @example\n * stack(g3, b3, [e4, d4])\n */", "meta": { "range": [ - 36713, - 36986 + 36420, + 36693 ], "filename": "pattern.mjs", - "lineno": 1244, + "lineno": 1230, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3145,11 +3095,11 @@ "comment": "/** Concatenation: combines a list of patterns, switching between them successively, one per cycle:\n *\n * synonyms: {@link cat}\n *\n * @param {...any} items - The items to concatenate\n * @return {Pattern}\n * @example\n * slowcat(e5, b4, [d5, c5])\n *\n */", "meta": { "range": [ - 37240, - 38151 + 36947, + 37858 ], "filename": "pattern.mjs", - "lineno": 1261, + "lineno": 1247, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3197,11 +3147,11 @@ "comment": "/** Concatenation: combines a list of patterns, switching between them successively, one per cycle. Unlike slowcat, this version will skip cycles.\n * @param {...any} items - The items to concatenate\n * @return {Pattern}\n */", "meta": { "range": [ - 38377, - 38649 + 38084, + 38356 ], "filename": "pattern.mjs", - "lineno": 1286, + "lineno": 1272, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3246,11 +3196,11 @@ "comment": "/** Concatenation: as with {@link slowcat}, but squashes a cycle from each pattern into one cycle\n *\n * Synonyms: {@link seq}, {@link sequence}\n *\n * @param {...any} items - The items to concatenate\n * @return {Pattern}\n * @example\n * fastcat(e5, b4, [d5, c5])\n * // sequence(e5, b4, [d5, c5])\n * // seq(e5, b4, [d5, c5])\n */", "meta": { "range": [ - 38977, - 39059 + 38684, + 38766 ], "filename": "pattern.mjs", - "lineno": 1307, + "lineno": 1293, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3298,11 +3248,11 @@ "comment": "/** See {@link slowcat} */", "meta": { "range": [ - 39088, - 39147 + 38795, + 38854 ], "filename": "pattern.mjs", - "lineno": 1312, + "lineno": 1298, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3326,11 +3276,11 @@ "comment": "/** Like {@link fastcat}, but where each step has a temporal weight:\n * @param {...Array} items - The items to concatenate\n * @return {Pattern}\n * @example\n * timeCat([3,e3],[1, g3])\n */", "meta": { "range": [ - 39336, - 39695 + 39043, + 39402 ], "filename": "pattern.mjs", - "lineno": 1322, + "lineno": 1308, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3378,11 +3328,11 @@ "comment": "/** See {@link fastcat} */", "meta": { "range": [ - 39724, - 39788 + 39431, + 39495 ], "filename": "pattern.mjs", - "lineno": 1335, + "lineno": 1321, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3406,11 +3356,11 @@ "comment": "/** See {@link fastcat} */", "meta": { "range": [ - 39817, - 39876 + 39524, + 39583 ], "filename": "pattern.mjs", - "lineno": 1340, + "lineno": 1326, "columnno": 0, "path": "/home/felix/projects/strudel/packages/core", "code": { @@ -3643,7 +3593,7 @@ "comment": "/**\n * Change the pitch of each value by the given amount. Expects numbers or note strings as values.\n * The amount can be given as a number of semitones or as a string in interval short notation.\n * If you don't care about enharmonic correctness, just use numbers. Otherwise, pass the interval of\n * the form: ST where S is the degree number and T the type of interval with\n *\n * - M = major\n * - m = minor\n * - P = perfect\n * - A = augmented\n * - d = diminished\n *\n * Examples intervals:\n *\n * - 1P = unison\n * - 3M = major third\n * - 3m = minor third\n * - 4P = perfect fourth\n * - 4A = augmented fourth\n * - 5P = perfect fifth\n * - 5d = diminished fifth\n *\n * @param {string | number} amount Either number of semitones or interval string.\n * @returns Pattern\n * @memberof Pattern\n * @name transpose\n * @example\n * \"c2 c3\".fast(2).transpose(\"<0 -2 5 3>\".slow(2)).transpose(0)\n * @example\n * \"c2 c3\".fast(2).transpose(\"<1P -2M 4P 3m>\".slow(2)).transpose(0)\n */", "meta": { "filename": "tonal.mjs", - "lineno": 46, + "lineno": 45, "columnno": 0, "path": "/home/felix/projects/strudel/packages/tonal", "code": {} @@ -3675,14 +3625,14 @@ "scope": "static", "longname": "Pattern.transpose", "kind": "member", - "___id": "T000002R003717", + "___id": "T000002R003716", "___s": true }, { "comment": "/**\n * Transposes notes inside the scale by the number of steps.\n * Expected to be called on a Pattern which already has a {@link Pattern#scale}\n *\n * @memberof Pattern\n * @name scaleTranspose\n * @param {offset} offset number of steps inside the scale\n * @returns Pattern\n * @example\n * \"-8 [2,4,6]\"\n * .scale('C4 bebop major')\n * .scaleTranspose(\"<0 -1 -2 -3 -4 -5 -6 -4>\")\n */", "meta": { "filename": "tonal.mjs", - "lineno": 99, + "lineno": 98, "columnno": 0, "path": "/home/felix/projects/strudel/packages/tonal", "code": {} @@ -3712,14 +3662,14 @@ "scope": "static", "longname": "Pattern.scaleTranspose", "kind": "member", - "___id": "T000002R003721", + "___id": "T000002R003720", "___s": true }, { "comment": "/**\n * Turns numbers into notes in the scale (zero indexed). Also sets scale for other scale operations, like {@link Pattern#scaleTranspose}.\n *\n * The scale name has the form \"TO? N\" wher\n *\n * - T = Tonic\n * - O = Octave (optional, defaults to 3)\n * - N = Name of scale, available names can be found [here](https://github.com/tonaljs/tonal/blob/main/packages/scale-type/data.ts).\n *\n * @memberof Pattern\n * @name scale\n * @param {string} scale Name of scale\n * @returns Pattern\n * @example \n * \"0 2 4 6 4 2\"\n * .scale(seq('C2 major', 'C2 minor').slow(2))\n */", "meta": { "filename": "tonal.mjs", - "lineno": 125, + "lineno": 124, "columnno": 0, "path": "/home/felix/projects/strudel/packages/tonal", "code": {} @@ -3749,7 +3699,7 @@ "scope": "static", "longname": "Pattern.scale", "kind": "member", - "___id": "T000002R003723", + "___id": "T000002R003722", "___s": true }, { @@ -3786,7 +3736,33 @@ "scope": "static", "longname": "Pattern.voicings", "kind": "member", - "___id": "T000002R003748", + "___id": "T000002R003747", + "___s": true + }, + { + "comment": "/**\n *\n * Uses [webdirt](https://github.com/dktr0/WebDirt) as output.\n *\n *
\n * show supported Webdirt controls\n *\n * - s :: String, -- name of sample bank\n * - n :: Int, -- number of sample within a bank\n * - {@link gain} :: Number, -- clamped from 0 to 2; 1 is default and full-scale\n * - overgain :: Number, -- additional gain added to gain to go past clamp at 2\n * - {@link pan} :: Number, -- range: 0 to 1\n * - nudge :: Number, -- nudge the time of the sample forwards/backwards in seconds\n * - {@link speed} :: Number, -- speed / pitch of the sample\n * - {@link unit} :: String\n * - note :: Number, -- pitch offset in semitones\n * - {@link begin} :: Number, -- cut from sample start, normalized\n * - {@link end} :: Number, -- cut from sample end, normalized\n * - {@link cut} :: Int, -- samples with same cut number will interupt each other\n * - {@link cutoff} :: Number, -- lowpass filter frequency\n * - {@link resonance} :: Number, -- lowpass filter resonance\n * - {@link hcutoff} :: Number, -- highpass filter frequency\n * - {@link hresonance} :: Number, -- highpass filter resonance\n * - {@link bandf} :: Number, -- bandpass filter frequency\n * - {@link bandq} :: Number, -- bandpass filter resonance\n * - {@link vowel} :: String, -- name of vowel ('a' | 'e' | 'i' | 'o' | 'u')\n * - delay :: Number, -- delay wet/dry mix\n * - delaytime :: Number, -- delay time in seconds\n * - delayfeedback :: Number, -- delay feedback\n * - {@link loop} :: Number, -- loop sample n times (relative to sample length)\n * - {@link crush} :: Number, -- bitcrusher (currently not working)\n * - {@link coarse} :: Number, -- coarse effect (currently not working)\n * - {@link shape} :: Number, -- (currently not working)\n\n *\n *
\n *\n * @name webdirt\n * @memberof Pattern\n * @returns Pattern\n * @example\n * s(\"bd*2 hh sd hh\").n(\"<0 1>\").webdirt()\n */", + "meta": { + "filename": "webdirt.mjs", + "lineno": 20, + "columnno": 0, + "path": "/home/felix/projects/strudel/packages/webdirt", + "code": {} + }, + "description": "

Uses webdirt as output.

\n
\nshow supported Webdirt controls\n\n
", + "name": "webdirt", + "memberof": "Pattern", + "returns": [ + { + "description": "

Pattern

" + } + ], + "examples": [ + "s(\"bd*2 hh sd hh\").n(\"<0 1>\").webdirt()" + ], + "scope": "static", + "longname": "Pattern.webdirt", + "kind": "member", + "___id": "T000002R004040", "___s": true }, { @@ -3862,13 +3838,16 @@ "/home/felix/projects/strudel/packages/webaudio/index.mjs", "/home/felix/projects/strudel/packages/webaudio/scheduler.mjs", "/home/felix/projects/strudel/packages/webaudio/webaudio.mjs", + "/home/felix/projects/strudel/packages/webdirt/index.mjs", + "/home/felix/projects/strudel/packages/webdirt/sampler.mjs", + "/home/felix/projects/strudel/packages/webdirt/webdirt.mjs", "/home/felix/projects/strudel/packages/xen/index.mjs", "/home/felix/projects/strudel/packages/xen/test/xen.test.mjs", "/home/felix/projects/strudel/packages/xen/tune.mjs", "/home/felix/projects/strudel/packages/xen/tunejs.js", "/home/felix/projects/strudel/packages/xen/xen.mjs" ], - "___id": "T000002R014017", + "___id": "T000002R014063", "___s": true } ] diff --git a/package-lock.json b/package-lock.json index 0d4ff7b1..0e700319 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2255,6 +2255,10 @@ "resolved": "packages/webaudio", "link": true }, + "node_modules/@strudel.cycles/webdirt": { + "resolved": "packages/webdirt", + "link": true + }, "node_modules/@strudel.cycles/xen": { "resolved": "packages/xen", "link": true @@ -10815,6 +10819,11 @@ "defaults": "^1.0.3" } }, + "node_modules/WebDirt": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/dktr0/WebDirt.git#c3aee2c933c4889ee664a836db8c6436af9e867b", + "license": "ISC" + }, "node_modules/webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", @@ -11271,7 +11280,7 @@ }, "packages/eval": { "name": "@strudel.cycles/eval", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "^0.1.0", @@ -11298,22 +11307,22 @@ }, "packages/midi": { "name": "@strudel.cycles/midi", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { - "@strudel.cycles/tone": "^0.1.0", + "@strudel.cycles/tone": "^0.1.1", "tone": "^14.7.77", "webmidi": "^2.5.2" } }, "packages/mini": { "name": "@strudel.cycles/mini", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "^0.1.0", - "@strudel.cycles/eval": "^0.1.0", - "@strudel.cycles/tone": "^0.1.0" + "@strudel.cycles/eval": "^0.1.1", + "@strudel.cycles/tone": "^0.1.1" } }, "packages/osc": { @@ -11326,14 +11335,14 @@ }, "packages/react": { "name": "@strudel.cycles/react", - "version": "0.1.1", + "version": "0.1.2", "license": "AGPL-3.0-or-later", "peer": true, "dependencies": { "@codemirror/lang-javascript": "^0.19.0", "@strudel.cycles/core": "*", - "@strudel.cycles/eval": "^0.1.0", - "@strudel.cycles/tone": "^0.1.0", + "@strudel.cycles/eval": "^0.1.1", + "@strudel.cycles/tone": "^0.1.1", "react-codemirror6": "^1.1.0", "react-hook-inview": "^4.5.0" }, @@ -11407,7 +11416,7 @@ }, "packages/tonal": { "name": "@strudel.cycles/tonal", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "^0.1.0", @@ -11432,7 +11441,7 @@ }, "packages/tone": { "name": "@strudel.cycles/tone", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "^0.1.0", @@ -11443,15 +11452,24 @@ }, "packages/webaudio": { "name": "@strudel.cycles/webaudio", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "^0.1.0" } }, + "packages/webdirt": { + "name": "@strudel.cycles/webdirt", + "version": "0.1.0", + "license": "AGPL-3.0-or-later", + "dependencies": { + "@strudel.cycles/core": "^0.1.0", + "WebDirt": "github:dktr0/WebDirt" + } + }, "packages/xen": { "name": "@strudel.cycles/xen", - "version": "0.1.0", + "version": "0.1.1", "license": "AGPL-3.0-or-later", "dependencies": { "@strudel.cycles/core": "^0.1.0" @@ -13281,7 +13299,7 @@ "@strudel.cycles/midi": { "version": "file:packages/midi", "requires": { - "@strudel.cycles/tone": "^0.1.0", + "@strudel.cycles/tone": "^0.1.1", "tone": "^14.7.77", "webmidi": "^2.5.2" } @@ -13290,8 +13308,8 @@ "version": "file:packages/mini", "requires": { "@strudel.cycles/core": "^0.1.0", - "@strudel.cycles/eval": "^0.1.0", - "@strudel.cycles/tone": "^0.1.0" + "@strudel.cycles/eval": "^0.1.1", + "@strudel.cycles/tone": "^0.1.1" } }, "@strudel.cycles/osc": { @@ -13305,8 +13323,8 @@ "requires": { "@codemirror/lang-javascript": "^0.19.0", "@strudel.cycles/core": "*", - "@strudel.cycles/eval": "^0.1.0", - "@strudel.cycles/tone": "^0.1.0", + "@strudel.cycles/eval": "^0.1.1", + "@strudel.cycles/tone": "^0.1.1", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", "@vitejs/plugin-react": "^1.3.0", @@ -13401,6 +13419,13 @@ "@strudel.cycles/core": "^0.1.0" } }, + "@strudel.cycles/webdirt": { + "version": "file:packages/webdirt", + "requires": { + "@strudel.cycles/core": "^0.1.0", + "WebDirt": "github:dktr0/WebDirt" + } + }, "@strudel.cycles/xen": { "version": "file:packages/xen", "requires": { @@ -18362,8 +18387,8 @@ "requires": { "@codemirror/lang-javascript": "^0.19.0", "@strudel.cycles/core": "*", - "@strudel.cycles/eval": "^0.1.0", - "@strudel.cycles/tone": "^0.1.0", + "@strudel.cycles/eval": "^0.1.1", + "@strudel.cycles/tone": "^0.1.1", "@types/react": "^17.0.2", "@types/react-dom": "^17.0.2", "@vitejs/plugin-react": "^1.3.0", @@ -20004,6 +20029,10 @@ "defaults": "^1.0.3" } }, + "WebDirt": { + "version": "git+ssh://git@github.com/dktr0/WebDirt.git#c3aee2c933c4889ee664a836db8c6436af9e867b", + "from": "WebDirt@github:dktr0/WebDirt" + }, "webidl-conversions": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", diff --git a/packages/react/dist/index.cjs.js b/packages/react/dist/index.cjs.js index f296723f..284fa75f 100644 --- a/packages/react/dist/index.cjs.js +++ b/packages/react/dist/index.cjs.js @@ -1,3 +1,3 @@ -"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var o=require("react"),te=require("react-codemirror6"),D=require("@codemirror/view"),I=require("@codemirror/state"),oe=require("@codemirror/lang-javascript"),s=require("@codemirror/highlight"),ae=require("react-hook-inview"),re=require("@strudel.cycles/eval"),ne=require("@strudel.cycles/core/util.mjs"),p=require("@strudel.cycles/tone"),z=require("@strudel.cycles/core"),v=require("@strudel.cycles/midi");function se(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var f=se(o);const ce="#abb2bf",le="#7d8799",ie="#ffffff",ue="#21252b",P="rgba(0, 0, 0, 0.5)",de="transparent",W="#353a42",fe="rgba(128, 203, 196, 0.2)",F="#ffcc00",ge=D.EditorView.theme({"&":{color:"#ffffff",backgroundColor:de,fontSize:"15px","z-index":11},".cm-content":{caretColor:F,lineHeight:"22px"},".cm-line":{background:"#2C323699"},"&.cm-focused .cm-cursor":{borderLeftColor:F},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":{backgroundColor:fe},".cm-panels":{backgroundColor:ue,color:"#ffffff"},".cm-panels.cm-panels-top":{borderBottom:"2px solid black"},".cm-panels.cm-panels-bottom":{borderTop:"2px solid black"},".cm-searchMatch":{backgroundColor:"#72a1ff59",outline:"1px solid #457dff"},".cm-searchMatch.cm-searchMatch-selected":{backgroundColor:"#6199ff2f"},".cm-activeLine":{backgroundColor:P},".cm-selectionMatch":{backgroundColor:"#aafe661a"},"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket":{backgroundColor:"#bad0f847",outline:"1px solid #515a6b"},".cm-gutters":{background:"#2C323699",color:"#676e95",border:"none"},".cm-activeLineGutter":{backgroundColor:P},".cm-foldPlaceholder":{backgroundColor:"transparent",border:"none",color:"#ddd"},".cm-tooltip":{border:"none",backgroundColor:W},".cm-tooltip .cm-tooltip-arrow:before":{borderTopColor:"transparent",borderBottomColor:"transparent"},".cm-tooltip .cm-tooltip-arrow:after":{borderTopColor:W,borderBottomColor:W},".cm-tooltip-autocomplete":{"& > ul > li[aria-selected]":{backgroundColor:P,color:ce}}},{dark:!0}),me=s.HighlightStyle.define([{tag:s.tags.keyword,color:"#c792ea"},{tag:s.tags.operator,color:"#89ddff"},{tag:s.tags.special(s.tags.variableName),color:"#eeffff"},{tag:s.tags.typeName,color:"#f07178"},{tag:s.tags.atom,color:"#f78c6c"},{tag:s.tags.number,color:"#ff5370"},{tag:s.tags.definition(s.tags.variableName),color:"#82aaff"},{tag:s.tags.string,color:"#c3e88d"},{tag:s.tags.special(s.tags.string),color:"#f07178"},{tag:s.tags.comment,color:le},{tag:s.tags.variableName,color:"#f07178"},{tag:s.tags.tagName,color:"#ff5370"},{tag:s.tags.bracket,color:"#a2a1a4"},{tag:s.tags.meta,color:"#ffcb6b"},{tag:s.tags.attributeName,color:"#c792ea"},{tag:s.tags.propertyName,color:"#c792ea"},{tag:s.tags.className,color:"#decb6b"},{tag:s.tags.invalid,color:ie}]),be=[ge,me],B=I.StateEffect.define(),pe=I.StateField.define({create(){return D.Decoration.none},update(e,a){try{for(let l of a.effects)l.is(B)&&(e=D.Decoration.set(l.value.flatMap(u=>(u.context.locations||[]).map(({start:g,end:c})=>{const i=u.context.color||"#FFCA28";let m=a.newDoc.line(g.line).from+g.column,n=a.newDoc.line(c.line).from+c.column;const r=a.newDoc.length;return m>r||n>r?void 0:D.Decoration.mark({attributes:{style:`outline: 1px solid ${i}`}}).range(m,n)})).filter(Boolean),!0));return e}catch{return e}},provide:e=>D.EditorView.decorations.from(e)});function $({value:e,onChange:a,onViewChanged:l,onCursor:u,options:g,editorDidMount:c}){return f.default.createElement(f.default.Fragment,null,f.default.createElement(te.CodeMirror,{onViewChange:l,style:{display:"flex",flexDirection:"column",flex:"1 0 auto"},value:e,onChange:a,extensions:[oe.javascript(),be,pe]}))}function Q(e){const{onEvent:a,onQuery:l,onSchedule:u,ready:g=!0,onDraw:c}=e,[i,m]=o.useState(!1),n=1,r=()=>Math.floor(p.Tone.getTransport().seconds/n),y=(b=r())=>{const w=new z.TimeSpan(b,b+1),S=l?.(new z.State(w))||[];u?.(S,b);const H=w.begin.valueOf();p.Tone.getTransport().cancel(H);const N=(b+1)*n-.5,R=Math.max(p.Tone.getTransport().seconds,N)+.1;p.Tone.getTransport().schedule(()=>{y(b+1)},R),S?.filter(h=>h.part.begin.equals(h.whole?.begin)).forEach(h=>{p.Tone.getTransport().schedule(M=>{a(M,h,p.Tone.getContext().currentTime),p.Tone.Draw.schedule(()=>{c?.(M,h)},M)},h.part.begin.valueOf())})};o.useEffect(()=>{g&&y()},[a,u,l,c,g]);const x=async()=>{m(!0),await p.Tone.start(),p.Tone.getTransport().start("+0.1")},C=()=>{p.Tone.getTransport().pause(),m(!1)};return{start:x,stop:C,onEvent:a,started:i,setStarted:m,toggle:()=>i?C():x(),query:y,activeCycle:r}}function U(e){return o.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),o.useCallback(a=>window.postMessage(a,"*"),[])}let he=()=>Math.floor((1+Math.random())*65536).toString(16).substring(1);const ve=e=>encodeURIComponent(btoa(e));function G({tune:e,defaultSynth:a,autolink:l=!0,onEvent:u,onDraw:g}){const c=o.useMemo(()=>he(),[]),[i,m]=o.useState(e),[n,r]=o.useState(),[y,x]=o.useState(""),[C,E]=o.useState(),[b,w]=o.useState(!1),[S,H]=o.useState(""),[N,R]=o.useState(),h=o.useMemo(()=>i!==n||C,[i,n,C]),M=o.useCallback(d=>x(t=>t+`${t?` +"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var o=require("react"),te=require("react-codemirror6"),D=require("@codemirror/view"),I=require("@codemirror/state"),oe=require("@codemirror/lang-javascript"),s=require("@codemirror/highlight"),ae=require("react-hook-inview"),re=require("@strudel.cycles/eval"),ne=require("@strudel.cycles/core/util.mjs"),p=require("@strudel.cycles/tone"),z=require("@strudel.cycles/core"),v=require("@strudel.cycles/midi");function se(e){return e&&typeof e=="object"&&"default"in e?e:{default:e}}var g=se(o);const ce="#abb2bf",le="#7d8799",ie="#ffffff",ue="#21252b",P="rgba(0, 0, 0, 0.5)",de="transparent",W="#353a42",ge="rgba(128, 203, 196, 0.5)",F="#ffcc00",fe=D.EditorView.theme({"&":{color:"#ffffff",backgroundColor:de,fontSize:"15px","z-index":11},".cm-content":{caretColor:F,lineHeight:"22px"},".cm-line":{background:"#2C323699"},"&.cm-focused .cm-cursor":{backgroundColor:F,width:"3px"},"&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection":{backgroundColor:ge},".cm-panels":{backgroundColor:ue,color:"#ffffff"},".cm-panels.cm-panels-top":{borderBottom:"2px solid black"},".cm-panels.cm-panels-bottom":{borderTop:"2px solid black"},".cm-searchMatch":{backgroundColor:"#72a1ff59",outline:"1px solid #457dff"},".cm-searchMatch.cm-searchMatch-selected":{backgroundColor:"#6199ff2f"},".cm-activeLine":{backgroundColor:P},".cm-selectionMatch":{backgroundColor:"#aafe661a"},"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket":{backgroundColor:"#bad0f847",outline:"1px solid #515a6b"},".cm-gutters":{background:"transparent",color:"#676e95",border:"none"},".cm-activeLineGutter":{backgroundColor:P},".cm-foldPlaceholder":{backgroundColor:"transparent",border:"none",color:"#ddd"},".cm-tooltip":{border:"none",backgroundColor:W},".cm-tooltip .cm-tooltip-arrow:before":{borderTopColor:"transparent",borderBottomColor:"transparent"},".cm-tooltip .cm-tooltip-arrow:after":{borderTopColor:W,borderBottomColor:W},".cm-tooltip-autocomplete":{"& > ul > li[aria-selected]":{backgroundColor:P,color:ce}}},{dark:!0}),me=s.HighlightStyle.define([{tag:s.tags.keyword,color:"#c792ea"},{tag:s.tags.operator,color:"#89ddff"},{tag:s.tags.special(s.tags.variableName),color:"#eeffff"},{tag:s.tags.typeName,color:"#f07178"},{tag:s.tags.atom,color:"#f78c6c"},{tag:s.tags.number,color:"#ff5370"},{tag:s.tags.definition(s.tags.variableName),color:"#82aaff"},{tag:s.tags.string,color:"#c3e88d"},{tag:s.tags.special(s.tags.string),color:"#f07178"},{tag:s.tags.comment,color:le},{tag:s.tags.variableName,color:"#f07178"},{tag:s.tags.tagName,color:"#ff5370"},{tag:s.tags.bracket,color:"#a2a1a4"},{tag:s.tags.meta,color:"#ffcb6b"},{tag:s.tags.attributeName,color:"#c792ea"},{tag:s.tags.propertyName,color:"#c792ea"},{tag:s.tags.className,color:"#decb6b"},{tag:s.tags.invalid,color:ie}]),be=[fe,me],B=I.StateEffect.define(),pe=I.StateField.define({create(){return D.Decoration.none},update(e,a){try{for(let l of a.effects)l.is(B)&&(e=D.Decoration.set(l.value.flatMap(u=>(u.context.locations||[]).map(({start:f,end:c})=>{const i=u.context.color||"#FFCA28";let m=a.newDoc.line(f.line).from+f.column,n=a.newDoc.line(c.line).from+c.column;const r=a.newDoc.length;return m>r||n>r?void 0:D.Decoration.mark({attributes:{style:`outline: 1px solid ${i}`}}).range(m,n)})).filter(Boolean),!0));return e}catch{return e}},provide:e=>D.EditorView.decorations.from(e)});function $({value:e,onChange:a,onViewChanged:l,onCursor:u,options:f,editorDidMount:c}){return g.default.createElement(g.default.Fragment,null,g.default.createElement(te.CodeMirror,{onViewChange:l,style:{display:"flex",flexDirection:"column",flex:"1 0 auto"},value:e,onChange:a,extensions:[oe.javascript(),be,pe]}))}function Q(e){const{onEvent:a,onQuery:l,onSchedule:u,ready:f=!0,onDraw:c}=e,[i,m]=o.useState(!1),n=1,r=()=>Math.floor(p.Tone.getTransport().seconds/n),y=(b=r())=>{const w=new z.TimeSpan(b,b+1),S=l?.(new z.State(w))||[];u?.(S,b);const H=w.begin.valueOf();p.Tone.getTransport().cancel(H);const N=(b+1)*n-.5,R=Math.max(p.Tone.getTransport().seconds,N)+.1;p.Tone.getTransport().schedule(()=>{y(b+1)},R),S?.filter(h=>h.part.begin.equals(h.whole?.begin)).forEach(h=>{p.Tone.getTransport().schedule(k=>{a(k,h,p.Tone.getContext().currentTime),p.Tone.Draw.schedule(()=>{c?.(k,h)},k)},h.part.begin.valueOf())})};o.useEffect(()=>{f&&y()},[a,u,l,c,f]);const _=async()=>{m(!0),await p.Tone.start(),p.Tone.getTransport().start("+0.1")},C=()=>{p.Tone.getTransport().pause(),m(!1)};return{start:_,stop:C,onEvent:a,started:i,setStarted:m,toggle:()=>i?C():_(),query:y,activeCycle:r}}function U(e){return o.useEffect(()=>(window.addEventListener("message",e),()=>window.removeEventListener("message",e)),[e]),o.useCallback(a=>window.postMessage(a,"*"),[])}let he=()=>Math.floor((1+Math.random())*65536).toString(16).substring(1);const ve=e=>encodeURIComponent(btoa(e));function G({tune:e,defaultSynth:a,autolink:l=!0,onEvent:u,onDraw:f}){const c=o.useMemo(()=>he(),[]),[i,m]=o.useState(e),[n,r]=o.useState(),[y,_]=o.useState(""),[C,E]=o.useState(),[b,w]=o.useState(!1),[S,H]=o.useState(""),[N,R]=o.useState(),h=o.useMemo(()=>i!==n||C,[i,n,C]),k=o.useCallback(d=>_(t=>t+`${t?` -`:""}${d}`),[]),K=o.useMemo(()=>{if(n&&!n.includes("strudel disable-highlighting"))return(d,t)=>g?.(d,t,n)},[n,g]),T=Q({onDraw:K,onEvent:o.useCallback((d,t,Y)=>{try{u?.(t),t.context.logs?.length&&t.context.logs.forEach(M);const{onTrigger:_,velocity:Z}=t.context;if(_)_(d,t,Y,1,t.wholeOrPart().begin.valueOf(),t.duration.valueOf());else if(a){const ee=ne.getPlayableNoteValue(t);a.triggerAttackRelease(ee,t.duration.valueOf(),d,Z)}else throw new Error("no defaultSynth passed to useRepl.")}catch(_){console.warn(_),_.message="unplayable event: "+_?.message,M(_.message)}},[u,M,a]),onQuery:o.useCallback(d=>{try{return N?.query(d)||[]}catch(t){return console.warn(t),t.message="query error: "+t.message,E(t),[]}},[N]),onSchedule:o.useCallback((d,t)=>X(d,t),[]),ready:!!N&&!!n}),V=U(({data:{from:d,type:t}})=>{t==="start"&&d!==c&&(T.setStarted(!1),r(void 0))}),A=o.useCallback(async(d=i)=>{if(n&&!h){E(void 0),T.start();return}try{w(!0);const t=await re.evaluate(d);T.start(),V({type:"start",from:c}),R(()=>t.pattern),l&&(window.location.hash="#"+encodeURIComponent(btoa(i))),H(ve(i)),E(void 0),r(d),w(!1)}catch(t){t.message="evaluation error: "+t.message,console.warn(t),E(t)}},[n,h,i,T,l,c,V]),X=(d,t)=>{d.length};return{pending:b,code:i,setCode:m,pattern:N,error:C,cycle:T,setPattern:R,dirty:h,log:y,togglePlay:()=>{T.started?T.stop():A()},setActiveCode:r,activateCode:A,activeCode:n,pushLog:M,hash:S}}function L(...e){return e.filter(Boolean).join(" ")}let q=[],O;function J({view:e,pattern:a,active:l}){o.useEffect(()=>{if(e)if(a&&l){let g=function(){try{const c=p.Tone.getTransport().seconds,m=[Math.max(O||c,c-1/10),c+1/60];O=c+1/60,q=q.filter(r=>r.whole.end>c);const n=a.queryArc(...m).filter(r=>r.hasOnset());q=q.concat(n),e.dispatch({effects:B.of(q)})}catch{e.dispatch({effects:B.of([])})}u=requestAnimationFrame(g)},u=requestAnimationFrame(g);return()=>{cancelAnimationFrame(u)}}else q=[],e.dispatch({effects:B.of([])})},[a,l,e])}const ye="_container_10e1g_1",Ce="_header_10e1g_5",we="_buttons_10e1g_9",Me="_button_10e1g_9",ke="_buttonDisabled_10e1g_17",Ee="_error_10e1g_21",Te="_body_10e1g_25";var k={container:ye,header:Ce,buttons:we,button:Me,buttonDisabled:ke,error:Ee,body:Te};function j({type:e}){return f.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",className:"sc-h-5 sc-w-5",viewBox:"0 0 20 20",fill:"currentColor"},{refresh:f.default.createElement("path",{fillRule:"evenodd",d:"M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z",clipRule:"evenodd"}),play:f.default.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z",clipRule:"evenodd"}),pause:f.default.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z",clipRule:"evenodd"})}[e])}function _e({tune:e,defaultSynth:a,hideOutsideView:l=!1}){const{code:u,setCode:g,pattern:c,activateCode:i,error:m,cycle:n,dirty:r,togglePlay:y}=G({tune:e,defaultSynth:a,autolink:!1}),[x,C]=o.useState(),[E,b]=ae.useInView({threshold:.01}),w=o.useRef(),S=o.useMemo(()=>((b||!l)&&(w.current=!0),b||w.current),[b,l]);return J({view:x,pattern:c,active:n.started}),f.default.createElement("div",{className:k.container,ref:E},f.default.createElement("div",{className:k.header},f.default.createElement("div",{className:k.buttons},f.default.createElement("button",{className:L(k.button,n.started?"sc-animate-pulse":""),onClick:()=>y()},f.default.createElement(j,{type:n.started?"pause":"play"})),f.default.createElement("button",{className:L(r?k.button:k.buttonDisabled),onClick:()=>i()},f.default.createElement(j,{type:"refresh"}))),m&&f.default.createElement("div",{className:k.error},m.message)),f.default.createElement("div",{className:k.body},S&&f.default.createElement($,{value:u,onChange:g,onViewChanged:C})))}function xe(e){const{ready:a,connected:l,disconnected:u}=e,[g,c]=o.useState(!0),[i,m]=o.useState(v.WebMidi?.outputs||[]);return o.useEffect(()=>{v.enableWebMidi().then(()=>{v.WebMidi.addListener("connected",r=>{m([...v.WebMidi.outputs]),l?.(v.WebMidi,r)}),v.WebMidi.addListener("disconnected",r=>{m([...v.WebMidi.outputs]),u?.(v.WebMidi,r)}),a?.(v.WebMidi),c(!1)}).catch(r=>{if(r){console.error(r),console.warn("Web Midi could not be enabled..");return}})},[a,l,u,i]),{loading:g,outputs:i,outputByName:r=>v.WebMidi.getOutputByName(r)}}exports.CodeMirror=$;exports.MiniRepl=_e;exports.cx=L;exports.useCycle=Q;exports.useHighlighting=J;exports.usePostMessage=U;exports.useRepl=G;exports.useWebMidi=xe; +`:""}${d}`),[]),K=o.useMemo(()=>{if(n&&!n.includes("strudel disable-highlighting"))return(d,t)=>f?.(d,t,n)},[n,f]),T=Q({onDraw:K,onEvent:o.useCallback((d,t,Y)=>{try{u?.(t),t.context.logs?.length&&t.context.logs.forEach(k);const{onTrigger:x,velocity:Z}=t.context;if(x)x(d,t,Y,1,t.wholeOrPart().begin.valueOf(),t.duration.valueOf());else if(a){const ee=ne.getPlayableNoteValue(t);a.triggerAttackRelease(ee,t.duration.valueOf(),d,Z)}else throw new Error("no defaultSynth passed to useRepl.")}catch(x){console.warn(x),x.message="unplayable event: "+x?.message,k(x.message)}},[u,k,a]),onQuery:o.useCallback(d=>{try{return N?.query(d)||[]}catch(t){return console.warn(t),t.message="query error: "+t.message,E(t),[]}},[N]),onSchedule:o.useCallback((d,t)=>X(d,t),[]),ready:!!N&&!!n}),A=U(({data:{from:d,type:t}})=>{t==="start"&&d!==c&&(T.setStarted(!1),r(void 0))}),L=o.useCallback(async(d=i)=>{if(n&&!h){E(void 0),T.start();return}try{w(!0);const t=await re.evaluate(d);T.start(),A({type:"start",from:c}),R(()=>t.pattern),l&&(window.location.hash="#"+encodeURIComponent(btoa(i))),H(ve(i)),E(void 0),r(d),w(!1)}catch(t){t.message="evaluation error: "+t.message,console.warn(t),E(t)}},[n,h,i,T,l,c,A]),X=(d,t)=>{d.length};return{pending:b,code:i,setCode:m,pattern:N,error:C,cycle:T,setPattern:R,dirty:h,log:y,togglePlay:()=>{T.started?T.stop():L()},setActiveCode:r,activateCode:L,activeCode:n,pushLog:k,hash:S}}function V(...e){return e.filter(Boolean).join(" ")}let q=[],O;function J({view:e,pattern:a,active:l}){o.useEffect(()=>{if(e)if(a&&l){let f=function(){try{const c=p.Tone.getTransport().seconds,m=[Math.max(O||c,c-1/10),c+1/60];O=c+1/60,q=q.filter(r=>r.whole.end>c);const n=a.queryArc(...m).filter(r=>r.hasOnset());q=q.concat(n),e.dispatch({effects:B.of(q)})}catch{e.dispatch({effects:B.of([])})}u=requestAnimationFrame(f)},u=requestAnimationFrame(f);return()=>{cancelAnimationFrame(u)}}else q=[],e.dispatch({effects:B.of([])})},[a,l,e])}const ye="_container_10e1g_1",Ce="_header_10e1g_5",we="_buttons_10e1g_9",ke="_button_10e1g_9",Me="_buttonDisabled_10e1g_17",Ee="_error_10e1g_21",Te="_body_10e1g_25";var M={container:ye,header:Ce,buttons:we,button:ke,buttonDisabled:Me,error:Ee,body:Te};function j({type:e}){return g.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",className:"sc-h-5 sc-w-5",viewBox:"0 0 20 20",fill:"currentColor"},{refresh:g.default.createElement("path",{fillRule:"evenodd",d:"M4 2a1 1 0 011 1v2.101a7.002 7.002 0 0111.601 2.566 1 1 0 11-1.885.666A5.002 5.002 0 005.999 7H9a1 1 0 010 2H4a1 1 0 01-1-1V3a1 1 0 011-1zm.008 9.057a1 1 0 011.276.61A5.002 5.002 0 0014.001 13H11a1 1 0 110-2h5a1 1 0 011 1v5a1 1 0 11-2 0v-2.101a7.002 7.002 0 01-11.601-2.566 1 1 0 01.61-1.276z",clipRule:"evenodd"}),play:g.default.createElement("path",{fillRule:"evenodd",d:"M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z",clipRule:"evenodd"}),pause:g.default.createElement("path",{fillRule:"evenodd",d:"M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z",clipRule:"evenodd"})}[e])}function xe({tune:e,defaultSynth:a,hideOutsideView:l=!1}){const{code:u,setCode:f,pattern:c,activateCode:i,error:m,cycle:n,dirty:r,togglePlay:y}=G({tune:e,defaultSynth:a,autolink:!1}),[_,C]=o.useState(),[E,b]=ae.useInView({threshold:.01}),w=o.useRef(),S=o.useMemo(()=>((b||!l)&&(w.current=!0),b||w.current),[b,l]);return J({view:_,pattern:c,active:n.started}),g.default.createElement("div",{className:M.container,ref:E},g.default.createElement("div",{className:M.header},g.default.createElement("div",{className:M.buttons},g.default.createElement("button",{className:V(M.button,n.started?"sc-animate-pulse":""),onClick:()=>y()},g.default.createElement(j,{type:n.started?"pause":"play"})),g.default.createElement("button",{className:V(r?M.button:M.buttonDisabled),onClick:()=>i()},g.default.createElement(j,{type:"refresh"}))),m&&g.default.createElement("div",{className:M.error},m.message)),g.default.createElement("div",{className:M.body},S&&g.default.createElement($,{value:u,onChange:f,onViewChanged:C})))}function _e(e){const{ready:a,connected:l,disconnected:u}=e,[f,c]=o.useState(!0),[i,m]=o.useState(v.WebMidi?.outputs||[]);return o.useEffect(()=>{v.enableWebMidi().then(()=>{v.WebMidi.addListener("connected",r=>{m([...v.WebMidi.outputs]),l?.(v.WebMidi,r)}),v.WebMidi.addListener("disconnected",r=>{m([...v.WebMidi.outputs]),u?.(v.WebMidi,r)}),a?.(v.WebMidi),c(!1)}).catch(r=>{if(r){console.error(r),console.warn("Web Midi could not be enabled..");return}})},[a,l,u,i]),{loading:f,outputs:i,outputByName:r=>v.WebMidi.getOutputByName(r)}}exports.CodeMirror=$;exports.MiniRepl=xe;exports.cx=V;exports.useCycle=Q;exports.useHighlighting=J;exports.usePostMessage=U;exports.useRepl=G;exports.useWebMidi=_e; diff --git a/packages/react/dist/index.es.js b/packages/react/dist/index.es.js index 66c39d0d..77ae32c9 100644 --- a/packages/react/dist/index.es.js +++ b/packages/react/dist/index.es.js @@ -26,7 +26,7 @@ const ivory = '#abb2bf', // background = '#292d3e', background = 'transparent', tooltipBackground = '#353a42', - selection = 'rgba(128, 203, 196, 0.2)', + selection = 'rgba(128, 203, 196, 0.5)', cursor = '#ffcc00'; /// The editor theme styles for Material Palenight. @@ -50,7 +50,8 @@ const materialPalenightTheme = EditorView.theme( }, // done '&.cm-focused .cm-cursor': { - borderLeftColor: cursor, + backgroundColor: cursor, + width: '3px', }, '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': { @@ -80,7 +81,7 @@ const materialPalenightTheme = EditorView.theme( // done '.cm-gutters': { - background: '#2C323699', + background: 'transparent', color: '#676e95', border: 'none', }, diff --git a/packages/react/src/themes/material-palenight.js b/packages/react/src/themes/material-palenight.js index 5ee559c9..59117ec5 100644 --- a/packages/react/src/themes/material-palenight.js +++ b/packages/react/src/themes/material-palenight.js @@ -16,7 +16,7 @@ const ivory = '#abb2bf', // background = '#292d3e', background = 'transparent', tooltipBackground = '#353a42', - selection = 'rgba(128, 203, 196, 0.2)', + selection = 'rgba(128, 203, 196, 0.5)', cursor = '#ffcc00'; /// The editor theme styles for Material Palenight. @@ -40,7 +40,8 @@ export const materialPalenightTheme = EditorView.theme( }, // done '&.cm-focused .cm-cursor': { - borderLeftColor: cursor, + backgroundColor: cursor, + width: '3px', }, '&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': { @@ -70,7 +71,7 @@ export const materialPalenightTheme = EditorView.theme( // done '.cm-gutters': { - background: '#2C323699', + background: 'transparent', color: '#676e95', border: 'none', }, diff --git a/packages/webdirt/README.md b/packages/webdirt/README.md new file mode 100644 index 00000000..26faed99 --- /dev/null +++ b/packages/webdirt/README.md @@ -0,0 +1,11 @@ +# @strudel.cycles/webdirt + +This package adds [webdirt](https://github.com/dktr0/WebDirt) support to strudel! + +## Dev Notes + +Add default samples to repl: + +1. move samples to `repl/public` folder. the samples folder is expected to have subfolders, with samples in it. the subfolders will be the names of the samples. +2. run `./makeSampleMap.sh ../../repl/public/EmuSP12 > ../../repl/public/EmuSP12.json` +3. adapt `loadWebDirt` in App.jsx + MiniRepl.jsx to use the generated json file diff --git a/packages/webdirt/index.mjs b/packages/webdirt/index.mjs new file mode 100644 index 00000000..46a6887f --- /dev/null +++ b/packages/webdirt/index.mjs @@ -0,0 +1,2 @@ +export * from './webdirt.mjs'; +export * from './sampler.mjs'; diff --git a/packages/webdirt/makeSampleMap.sh b/packages/webdirt/makeSampleMap.sh new file mode 100755 index 00000000..7b399b6e --- /dev/null +++ b/packages/webdirt/makeSampleMap.sh @@ -0,0 +1,32 @@ +#/bin/sh +printf "{\n" +dircount=0 +# for d in $searchRoot/*; do +find $1 -mindepth 1 -maxdepth 1 -iname "*" | sort | while read d; do + if [ -d "$d" ] + then + if [ $dircount -ne 0 ] + then + printf ",\n" + fi + (( dircount++ )) + dirname=`basename $d` + printf "\"%s\": [" "$dirname" + search2=$searchRoot/$dirname/*.WAV + filecount=0 + find "$d" -iname "*.wav" | sort | while read f; do + # for f in $search2; do + filename=$(printf %q "$f") + basename=${f##*/} + if [[ ${basename:0:1} != "." ]]; then + if [ $filecount -ne 0 ]; then + printf "," + fi + (( filecount++ )) + printf "\"%s/%s\"" "$dirname" "$basename" + fi + done + printf "]" + fi +done +printf "\n}\n" diff --git a/packages/webdirt/package.json b/packages/webdirt/package.json new file mode 100644 index 00000000..62cb55bc --- /dev/null +++ b/packages/webdirt/package.json @@ -0,0 +1,28 @@ +{ + "name": "@strudel.cycles/webdirt", + "version": "0.1.0", + "description": "WebDirt integration for Strudel", + "main": "index.mjs", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/tidalcycles/strudel.git" + }, + "keywords": [ + "tidalcycles", + "strudel", + "pattern", + "livecoding", + "algorave" + ], + "author": "Felix Roos ", + "license": "AGPL-3.0-or-later", + "bugs": { + "url": "https://github.com/tidalcycles/strudel/issues" + }, + "homepage": "https://github.com/tidalcycles/strudel#readme", + "dependencies": { + "@strudel.cycles/core": "^0.1.0", + "WebDirt": "github:dktr0/WebDirt" + } +} diff --git a/packages/webdirt/sampler.mjs b/packages/webdirt/sampler.mjs new file mode 100644 index 00000000..39a15fea --- /dev/null +++ b/packages/webdirt/sampler.mjs @@ -0,0 +1,112 @@ +const bufferCache = {}; // string: Promise +const loadCache = {}; // string: Promise + +export const loadBuffer = (url, ac) => { + if (!loadCache[url]) { + loadCache[url] = fetch(url) + .then((res) => res.arrayBuffer()) + .then(async (res) => { + const decoded = await ac.decodeAudioData(res); + bufferCache[url] = decoded; + return decoded; + }); + } + return loadCache[url]; +}; + +export const getLoadedBuffer = (url) => { + return bufferCache[url]; +}; + +/* export const playBuffer = (buffer, time = ac.currentTime, destination = ac.destination) => { + const src = ac.createBufferSource(); + src.buffer = buffer; + src.connect(destination); + src.start(time); +}; + +export const playSample = async (url) => playBuffer(await loadBuffer(url)); */ + +// https://estuary.mcmaster.ca/samples/resources.json +// Array<{ "url":string, "bank": string, "n": number}> +// ritchse/tidal-drum-machines/tree/main/machines/AkaiLinn +const githubCache = {}; +let sampleCache = { current: undefined }; +export const loadGithubSamples = async (path, nameFn) => { + const storageKey = 'loadGithubSamples ' + path; + const stored = localStorage.getItem(storageKey); + if (stored) { + console.log('[sampler]: loaded sample list from localstorage', path); + githubCache[path] = JSON.parse(stored); + } + if (githubCache[path]) { + sampleCache.current = githubCache[path]; + return githubCache[path]; + } + console.log('[sampler]: fetching sample list from github', path); + try { + const [user, repo, ...folders] = path.split('/'); + const baseUrl = `https://api.github.com/repos/${user}/${repo}/contents`; + const banks = await fetch(`${baseUrl}/${folders.join('/')}`).then((res) => res.json()); + // fetch each subfolder + githubCache[path] = ( + await Promise.all( + banks.map(async ({ name, path }) => ({ + name, + content: await fetch(`${baseUrl}/${path}`) + .then((res) => res.json()) + .catch((err) => { + console.error('could not load path', err); + }), + })), + ) + ) + .filter(({ content }) => !!content) + .reduce( + (acc, { name, content }) => ({ + ...acc, + [nameFn?.(name) || name]: content.map(({ download_url }) => download_url), + }), + {}, + ); + } catch (err) { + console.error('[sampler]: failed to fetch sample list from github', err); + return; + } + sampleCache.current = githubCache[path]; + localStorage.setItem(storageKey, JSON.stringify(sampleCache.current)); + console.log('[sampler]: loaded samples:', sampleCache.current); + return githubCache[path]; +}; + +/** + * load the given sample map for webdirt + * + * @example + * loadSamples({ + * bd: '808bd/BD0000.WAV', + * sd: ['808sd/SD0000.WAV','808sd/SD0010.WAV','808sd/SD0050.WAV'] + * }, 'https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master/'); + * s("bd ").n(2).webdirt() + * + */ + +export const samples = (sampleMap, baseUrl = '') => { + sampleCache.current = { + ...sampleCache.current, + ...Object.fromEntries( + Object.entries(sampleMap).map(([key, value]) => [ + key, + (typeof value === 'string' ? [value] : value).map((v) => + (baseUrl + v).replace('github:', 'https://raw.githubusercontent.com/'), + ), + ]), + ), + }; +}; + +export const resetLoadedSamples = () => { + sampleCache.current = undefined; +}; + +export const getLoadedSamples = () => sampleCache.current; diff --git a/packages/webdirt/webdirt.mjs b/packages/webdirt/webdirt.mjs new file mode 100644 index 00000000..36637818 --- /dev/null +++ b/packages/webdirt/webdirt.mjs @@ -0,0 +1,98 @@ +import * as strudel from '@strudel.cycles/core'; +const { Pattern } = strudel; +import * as WebDirt from 'WebDirt'; +import { getLoadedSamples, loadBuffer, getLoadedBuffer } from './sampler.mjs'; + +let webDirt; + +/* +example config: +{ + sampleMapUrl: 'EmuSP12.json', + sampleFolder: 'EmuSP12', +} +*/ +export function loadWebDirt(config) { + webDirt = new WebDirt.WebDirt(config); + webDirt.initializeWebAudio(); +} + +/** + * + * Uses [webdirt](https://github.com/dktr0/WebDirt) as output. + * + *
+ * show supported Webdirt controls + * + * - s :: String, -- name of sample bank + * - n :: Int, -- number of sample within a bank + * - {@link gain} :: Number, -- clamped from 0 to 2; 1 is default and full-scale + * - overgain :: Number, -- additional gain added to gain to go past clamp at 2 + * - {@link pan} :: Number, -- range: 0 to 1 + * - nudge :: Number, -- nudge the time of the sample forwards/backwards in seconds + * - {@link speed} :: Number, -- speed / pitch of the sample + * - {@link unit} :: String + * - note :: Number, -- pitch offset in semitones + * - {@link begin} :: Number, -- cut from sample start, normalized + * - {@link end} :: Number, -- cut from sample end, normalized + * - {@link cut} :: Int, -- samples with same cut number will interupt each other + * - {@link cutoff} :: Number, -- lowpass filter frequency + * - {@link resonance} :: Number, -- lowpass filter resonance + * - {@link hcutoff} :: Number, -- highpass filter frequency + * - {@link hresonance} :: Number, -- highpass filter resonance + * - {@link bandf} :: Number, -- bandpass filter frequency + * - {@link bandq} :: Number, -- bandpass filter resonance + * - {@link vowel} :: String, -- name of vowel ('a' | 'e' | 'i' | 'o' | 'u') + * - delay :: Number, -- delay wet/dry mix + * - delaytime :: Number, -- delay time in seconds + * - delayfeedback :: Number, -- delay feedback + * - {@link loop} :: Number, -- loop sample n times (relative to sample length) + * - {@link crush} :: Number, -- bitcrusher (currently not working) + * - {@link coarse} :: Number, -- coarse effect (currently not working) + * - {@link shape} :: Number, -- (currently not working) + + * + *
+ * + * @name webdirt + * @memberof Pattern + * @returns Pattern + * @example + * s("bd*2 hh sd hh").n("<0 1>").webdirt() + */ +Pattern.prototype.webdirt = function () { + // create a WebDirt object and initialize Web Audio context + return this._withHap((hap) => { + const onTrigger = async (time, e, currentTime) => { + if (!webDirt) { + throw new Error('WebDirt not initialized!'); + } + const deadline = time - currentTime; + const { s, n = 0, ...rest } = e.value || {}; + if (!s) { + console.warn('Pattern.webdirt: no "s" was set!'); + } + const samples = getLoadedSamples(); + if (!samples?.[s]) { + // try default samples + webDirt.playSample({ s, n, ...rest }, deadline); + return; + } + if (!samples?.[s]) { + console.warn(`Pattern.webdirt: sample "${s}" not found in loaded samples`, samples); + } else { + const bank = samples[s]; + const sampleUrl = bank[n % bank.length]; + const buffer = getLoadedBuffer(sampleUrl); + if (!buffer) { + console.log(`Pattern.webdirt: load ${s}:${n} from ${sampleUrl}`); + loadBuffer(sampleUrl, webDirt.ac); + } else { + const msg = { buffer: { buffer }, ...rest }; + webDirt.playSample(msg, deadline); + } + } + }; + return hap.setContext({ ...hap.context, onTrigger }); + }); +}; diff --git a/repl/public/EmuSP12.json b/repl/public/EmuSP12.json new file mode 100644 index 00000000..69746bed --- /dev/null +++ b/repl/public/EmuSP12.json @@ -0,0 +1,16 @@ +{ +"bd": ["bd/Bassdrum-01.wav","bd/Bassdrum-02.wav","bd/Bassdrum-03.wav","bd/Bassdrum-04.wav","bd/Bassdrum-05.wav","bd/Bassdrum-06.wav","bd/Bassdrum-07.wav","bd/Bassdrum-08.wav","bd/Bassdrum-09.wav","bd/Bassdrum-10.wav","bd/Bassdrum-11.wav","bd/Bassdrum-12.wav","bd/Bassdrum-13.wav","bd/Bassdrum-14.wav"], +"cb": ["cb/Cowbell.wav"], +"cp": ["cp/Clap.wav"], +"cr": ["cr/Crash.wav"], +"hh": ["hh/Hat Closed-01.wav","hh/Hat Closed-02.wav"], +"ht": ["ht/Tom H-01.wav","ht/Tom H-02.wav","ht/Tom H-03.wav","ht/Tom H-04.wav","ht/Tom H-05.wav","ht/Tom H-06.wav"], +"lt": ["lt/Tom L-01.wav","lt/Tom L-02.wav","lt/Tom L-03.wav","lt/Tom L-04.wav","lt/Tom L-05.wav","lt/Tom L-06.wav"], +"misc": ["misc/Metal-01.wav","misc/Metal-02.wav","misc/Metal-03.wav","misc/Scratch.wav","misc/Shot-01.wav","misc/Shot-02.wav","misc/Shot-03.wav"], +"mt": ["mt/Tom M-01.wav","mt/Tom M-02.wav","mt/Tom M-03.wav","mt/Tom M-05.wav"], +"oh": ["oh/Hhopen1.wav"], +"perc": ["perc/Blow1.wav"], +"rd": ["rd/Ride.wav"], +"rim": ["rim/zRim Shot-01.wav","rim/zRim Shot-02.wav"], +"sd": ["sd/Snaredrum-01.wav","sd/Snaredrum-02.wav","sd/Snaredrum-03.wav","sd/Snaredrum-04.wav","sd/Snaredrum-05.wav","sd/Snaredrum-06.wav","sd/Snaredrum-07.wav","sd/Snaredrum-08.wav","sd/Snaredrum-09.wav","sd/Snaredrum-10.wav","sd/Snaredrum-11.wav","sd/Snaredrum-12.wav","sd/Snaredrum-13.wav","sd/Snaredrum-14.wav","sd/Snaredrum-15.wav","sd/Snaredrum-16.wav","sd/Snaredrum-17.wav","sd/Snaredrum-18.wav","sd/Snaredrum-19.wav","sd/Snaredrum-20.wav","sd/Snaredrum-21.wav"] +} diff --git a/repl/public/EmuSP12/bd/Bassdrum-01.wav b/repl/public/EmuSP12/bd/Bassdrum-01.wav new file mode 100644 index 00000000..48e93676 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-01.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-02.wav b/repl/public/EmuSP12/bd/Bassdrum-02.wav new file mode 100644 index 00000000..52cd0afc Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-02.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-03.wav b/repl/public/EmuSP12/bd/Bassdrum-03.wav new file mode 100644 index 00000000..5c524ad7 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-03.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-04.wav b/repl/public/EmuSP12/bd/Bassdrum-04.wav new file mode 100644 index 00000000..9f9365d4 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-04.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-05.wav b/repl/public/EmuSP12/bd/Bassdrum-05.wav new file mode 100644 index 00000000..a4c80945 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-05.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-06.wav b/repl/public/EmuSP12/bd/Bassdrum-06.wav new file mode 100644 index 00000000..283d2f76 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-06.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-07.wav b/repl/public/EmuSP12/bd/Bassdrum-07.wav new file mode 100644 index 00000000..24f26186 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-07.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-08.wav b/repl/public/EmuSP12/bd/Bassdrum-08.wav new file mode 100644 index 00000000..51661252 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-08.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-09.wav b/repl/public/EmuSP12/bd/Bassdrum-09.wav new file mode 100644 index 00000000..3c6487c3 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-09.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-10.wav b/repl/public/EmuSP12/bd/Bassdrum-10.wav new file mode 100644 index 00000000..34a9b924 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-10.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-11.wav b/repl/public/EmuSP12/bd/Bassdrum-11.wav new file mode 100644 index 00000000..256555c2 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-11.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-12.wav b/repl/public/EmuSP12/bd/Bassdrum-12.wav new file mode 100644 index 00000000..8c29f046 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-12.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-13.wav b/repl/public/EmuSP12/bd/Bassdrum-13.wav new file mode 100644 index 00000000..a0291102 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-13.wav differ diff --git a/repl/public/EmuSP12/bd/Bassdrum-14.wav b/repl/public/EmuSP12/bd/Bassdrum-14.wav new file mode 100644 index 00000000..eecea2f1 Binary files /dev/null and b/repl/public/EmuSP12/bd/Bassdrum-14.wav differ diff --git a/repl/public/EmuSP12/cb/Cowbell.wav b/repl/public/EmuSP12/cb/Cowbell.wav new file mode 100644 index 00000000..470763c6 Binary files /dev/null and b/repl/public/EmuSP12/cb/Cowbell.wav differ diff --git a/repl/public/EmuSP12/cp/Clap.wav b/repl/public/EmuSP12/cp/Clap.wav new file mode 100644 index 00000000..27517d79 Binary files /dev/null and b/repl/public/EmuSP12/cp/Clap.wav differ diff --git a/repl/public/EmuSP12/cr/Crash.wav b/repl/public/EmuSP12/cr/Crash.wav new file mode 100644 index 00000000..6d1e2939 Binary files /dev/null and b/repl/public/EmuSP12/cr/Crash.wav differ diff --git a/repl/public/EmuSP12/hh/Hat Closed-01.wav b/repl/public/EmuSP12/hh/Hat Closed-01.wav new file mode 100644 index 00000000..1f18ccac Binary files /dev/null and b/repl/public/EmuSP12/hh/Hat Closed-01.wav differ diff --git a/repl/public/EmuSP12/hh/Hat Closed-02.wav b/repl/public/EmuSP12/hh/Hat Closed-02.wav new file mode 100644 index 00000000..cc40c03f Binary files /dev/null and b/repl/public/EmuSP12/hh/Hat Closed-02.wav differ diff --git a/repl/public/EmuSP12/ht/Tom H-01.wav b/repl/public/EmuSP12/ht/Tom H-01.wav new file mode 100644 index 00000000..82706785 Binary files /dev/null and b/repl/public/EmuSP12/ht/Tom H-01.wav differ diff --git a/repl/public/EmuSP12/ht/Tom H-02.wav b/repl/public/EmuSP12/ht/Tom H-02.wav new file mode 100644 index 00000000..9cfe221c Binary files /dev/null and b/repl/public/EmuSP12/ht/Tom H-02.wav differ diff --git a/repl/public/EmuSP12/ht/Tom H-03.wav b/repl/public/EmuSP12/ht/Tom H-03.wav new file mode 100644 index 00000000..a6eef5cd Binary files /dev/null and b/repl/public/EmuSP12/ht/Tom H-03.wav differ diff --git a/repl/public/EmuSP12/ht/Tom H-04.wav b/repl/public/EmuSP12/ht/Tom H-04.wav new file mode 100644 index 00000000..8c38b3b1 Binary files /dev/null and b/repl/public/EmuSP12/ht/Tom H-04.wav differ diff --git a/repl/public/EmuSP12/ht/Tom H-05.wav b/repl/public/EmuSP12/ht/Tom H-05.wav new file mode 100644 index 00000000..2e0899d2 Binary files /dev/null and b/repl/public/EmuSP12/ht/Tom H-05.wav differ diff --git a/repl/public/EmuSP12/ht/Tom H-06.wav b/repl/public/EmuSP12/ht/Tom H-06.wav new file mode 100644 index 00000000..9dccec23 Binary files /dev/null and b/repl/public/EmuSP12/ht/Tom H-06.wav differ diff --git a/repl/public/EmuSP12/lt/Tom L-01.wav b/repl/public/EmuSP12/lt/Tom L-01.wav new file mode 100644 index 00000000..cfa4067f Binary files /dev/null and b/repl/public/EmuSP12/lt/Tom L-01.wav differ diff --git a/repl/public/EmuSP12/lt/Tom L-02.wav b/repl/public/EmuSP12/lt/Tom L-02.wav new file mode 100644 index 00000000..68624f5f Binary files /dev/null and b/repl/public/EmuSP12/lt/Tom L-02.wav differ diff --git a/repl/public/EmuSP12/lt/Tom L-03.wav b/repl/public/EmuSP12/lt/Tom L-03.wav new file mode 100644 index 00000000..f1439d8c Binary files /dev/null and b/repl/public/EmuSP12/lt/Tom L-03.wav differ diff --git a/repl/public/EmuSP12/lt/Tom L-04.wav b/repl/public/EmuSP12/lt/Tom L-04.wav new file mode 100644 index 00000000..46d614a0 Binary files /dev/null and b/repl/public/EmuSP12/lt/Tom L-04.wav differ diff --git a/repl/public/EmuSP12/lt/Tom L-05.wav b/repl/public/EmuSP12/lt/Tom L-05.wav new file mode 100644 index 00000000..c9566585 Binary files /dev/null and b/repl/public/EmuSP12/lt/Tom L-05.wav differ diff --git a/repl/public/EmuSP12/lt/Tom L-06.wav b/repl/public/EmuSP12/lt/Tom L-06.wav new file mode 100644 index 00000000..c1edf374 Binary files /dev/null and b/repl/public/EmuSP12/lt/Tom L-06.wav differ diff --git a/repl/public/EmuSP12/misc/Metal-01.wav b/repl/public/EmuSP12/misc/Metal-01.wav new file mode 100644 index 00000000..0f306e70 Binary files /dev/null and b/repl/public/EmuSP12/misc/Metal-01.wav differ diff --git a/repl/public/EmuSP12/misc/Metal-02.wav b/repl/public/EmuSP12/misc/Metal-02.wav new file mode 100644 index 00000000..8a05af0e Binary files /dev/null and b/repl/public/EmuSP12/misc/Metal-02.wav differ diff --git a/repl/public/EmuSP12/misc/Metal-03.wav b/repl/public/EmuSP12/misc/Metal-03.wav new file mode 100644 index 00000000..0ae2ba80 Binary files /dev/null and b/repl/public/EmuSP12/misc/Metal-03.wav differ diff --git a/repl/public/EmuSP12/misc/Scratch.wav b/repl/public/EmuSP12/misc/Scratch.wav new file mode 100644 index 00000000..11bde1a5 Binary files /dev/null and b/repl/public/EmuSP12/misc/Scratch.wav differ diff --git a/repl/public/EmuSP12/misc/Shot-01.wav b/repl/public/EmuSP12/misc/Shot-01.wav new file mode 100644 index 00000000..e4ecfef3 Binary files /dev/null and b/repl/public/EmuSP12/misc/Shot-01.wav differ diff --git a/repl/public/EmuSP12/misc/Shot-02.wav b/repl/public/EmuSP12/misc/Shot-02.wav new file mode 100644 index 00000000..80f67cb2 Binary files /dev/null and b/repl/public/EmuSP12/misc/Shot-02.wav differ diff --git a/repl/public/EmuSP12/misc/Shot-03.wav b/repl/public/EmuSP12/misc/Shot-03.wav new file mode 100644 index 00000000..0cc84c28 Binary files /dev/null and b/repl/public/EmuSP12/misc/Shot-03.wav differ diff --git a/repl/public/EmuSP12/mt/Tom M-01.wav b/repl/public/EmuSP12/mt/Tom M-01.wav new file mode 100644 index 00000000..a650caf5 Binary files /dev/null and b/repl/public/EmuSP12/mt/Tom M-01.wav differ diff --git a/repl/public/EmuSP12/mt/Tom M-02.wav b/repl/public/EmuSP12/mt/Tom M-02.wav new file mode 100644 index 00000000..cbd7d16c Binary files /dev/null and b/repl/public/EmuSP12/mt/Tom M-02.wav differ diff --git a/repl/public/EmuSP12/mt/Tom M-03.wav b/repl/public/EmuSP12/mt/Tom M-03.wav new file mode 100644 index 00000000..e5c4b133 Binary files /dev/null and b/repl/public/EmuSP12/mt/Tom M-03.wav differ diff --git a/repl/public/EmuSP12/mt/Tom M-05.wav b/repl/public/EmuSP12/mt/Tom M-05.wav new file mode 100644 index 00000000..841cac02 Binary files /dev/null and b/repl/public/EmuSP12/mt/Tom M-05.wav differ diff --git a/repl/public/EmuSP12/oh/Hhopen1.wav b/repl/public/EmuSP12/oh/Hhopen1.wav new file mode 100644 index 00000000..73811991 Binary files /dev/null and b/repl/public/EmuSP12/oh/Hhopen1.wav differ diff --git a/repl/public/EmuSP12/perc/Blow1.wav b/repl/public/EmuSP12/perc/Blow1.wav new file mode 100644 index 00000000..8021d0d1 Binary files /dev/null and b/repl/public/EmuSP12/perc/Blow1.wav differ diff --git a/repl/public/EmuSP12/rd/Ride.wav b/repl/public/EmuSP12/rd/Ride.wav new file mode 100644 index 00000000..da0e33eb Binary files /dev/null and b/repl/public/EmuSP12/rd/Ride.wav differ diff --git a/repl/public/EmuSP12/rim/zRim Shot-01.wav b/repl/public/EmuSP12/rim/zRim Shot-01.wav new file mode 100644 index 00000000..98088cf2 Binary files /dev/null and b/repl/public/EmuSP12/rim/zRim Shot-01.wav differ diff --git a/repl/public/EmuSP12/rim/zRim Shot-02.wav b/repl/public/EmuSP12/rim/zRim Shot-02.wav new file mode 100644 index 00000000..c0f1a12d Binary files /dev/null and b/repl/public/EmuSP12/rim/zRim Shot-02.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-01.wav b/repl/public/EmuSP12/sd/Snaredrum-01.wav new file mode 100644 index 00000000..008bbf1d Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-01.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-02.wav b/repl/public/EmuSP12/sd/Snaredrum-02.wav new file mode 100644 index 00000000..4711ff70 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-02.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-03.wav b/repl/public/EmuSP12/sd/Snaredrum-03.wav new file mode 100644 index 00000000..643cf237 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-03.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-04.wav b/repl/public/EmuSP12/sd/Snaredrum-04.wav new file mode 100644 index 00000000..bb8c4c34 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-04.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-05.wav b/repl/public/EmuSP12/sd/Snaredrum-05.wav new file mode 100644 index 00000000..678db12e Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-05.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-06.wav b/repl/public/EmuSP12/sd/Snaredrum-06.wav new file mode 100644 index 00000000..a89a1d60 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-06.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-07.wav b/repl/public/EmuSP12/sd/Snaredrum-07.wav new file mode 100644 index 00000000..fdc1fb03 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-07.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-08.wav b/repl/public/EmuSP12/sd/Snaredrum-08.wav new file mode 100644 index 00000000..324eafac Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-08.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-09.wav b/repl/public/EmuSP12/sd/Snaredrum-09.wav new file mode 100644 index 00000000..35b617d7 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-09.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-10.wav b/repl/public/EmuSP12/sd/Snaredrum-10.wav new file mode 100644 index 00000000..85d13e91 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-10.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-11.wav b/repl/public/EmuSP12/sd/Snaredrum-11.wav new file mode 100644 index 00000000..d296fea5 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-11.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-12.wav b/repl/public/EmuSP12/sd/Snaredrum-12.wav new file mode 100644 index 00000000..b4fc9ca4 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-12.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-13.wav b/repl/public/EmuSP12/sd/Snaredrum-13.wav new file mode 100644 index 00000000..fbe745f9 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-13.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-14.wav b/repl/public/EmuSP12/sd/Snaredrum-14.wav new file mode 100644 index 00000000..fd321482 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-14.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-15.wav b/repl/public/EmuSP12/sd/Snaredrum-15.wav new file mode 100644 index 00000000..703a23cd Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-15.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-16.wav b/repl/public/EmuSP12/sd/Snaredrum-16.wav new file mode 100644 index 00000000..ef6c1f9c Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-16.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-17.wav b/repl/public/EmuSP12/sd/Snaredrum-17.wav new file mode 100644 index 00000000..df7e282e Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-17.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-18.wav b/repl/public/EmuSP12/sd/Snaredrum-18.wav new file mode 100644 index 00000000..0950c300 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-18.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-19.wav b/repl/public/EmuSP12/sd/Snaredrum-19.wav new file mode 100644 index 00000000..46b8e0d8 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-19.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-20.wav b/repl/public/EmuSP12/sd/Snaredrum-20.wav new file mode 100644 index 00000000..4c211a7c Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-20.wav differ diff --git a/repl/public/EmuSP12/sd/Snaredrum-21.wav b/repl/public/EmuSP12/sd/Snaredrum-21.wav new file mode 100644 index 00000000..246ea401 Binary files /dev/null and b/repl/public/EmuSP12/sd/Snaredrum-21.wav differ diff --git a/repl/src/App.jsx b/repl/src/App.jsx index 0c5e90a6..5113844e 100644 --- a/repl/src/App.jsx +++ b/repl/src/App.jsx @@ -12,9 +12,13 @@ import React, { useCallback, useLayoutEffect, useRef, useState } from 'react'; import './App.css'; import logo from './logo.svg'; import * as tunes from './tunes.mjs'; +import * as WebDirt from 'WebDirt'; +import { loadWebDirt, resetLoadedSamples } from '@strudel.cycles/webdirt'; + evalScope( Tone, controls, + { WebDirt }, import('@strudel.cycles/core'), import('@strudel.cycles/tone'), import('@strudel.cycles/tonal'), @@ -23,8 +27,14 @@ evalScope( import('@strudel.cycles/xen'), import('@strudel.cycles/webaudio'), import('@strudel.cycles/osc'), + import('@strudel.cycles/webdirt'), ); +loadWebDirt({ + sampleMapUrl: 'EmuSP12.json', + sampleFolder: 'EmuSP12', +}); + const initialUrl = window.location.href; const codeParam = window.location.href.split('#')[1]; let decoded; @@ -163,6 +173,7 @@ function App() { setCode(_code); cleanupDraw(); cleanupUi(); + resetLoadedSamples(); const parsed = await evaluate(_code); setPattern(parsed.pattern); setActiveCode(_code); diff --git a/tutorial/MiniRepl.jsx b/tutorial/MiniRepl.jsx index a01a2f8b..af21f362 100644 --- a/tutorial/MiniRepl.jsx +++ b/tutorial/MiniRepl.jsx @@ -2,6 +2,8 @@ import { Tone } from '@strudel.cycles/tone'; import { evalScope } from '@strudel.cycles/eval'; import { MiniRepl as _MiniRepl } from '@strudel.cycles/react'; import controls from '@strudel.cycles/core/controls.mjs'; +import * as WebDirt from 'WebDirt'; +import { loadWebDirt } from '@strudel.cycles/webdirt'; export const defaultSynth = new Tone.PolySynth().chain(new Tone.Gain(0.5), Tone.Destination).set({ oscillator: { type: 'triangle' }, @@ -21,8 +23,14 @@ evalScope( import('@strudel.cycles/xen'), import('@strudel.cycles/webaudio'), import('@strudel.cycles/osc'), + import('@strudel.cycles/webdirt'), ); +loadWebDirt({ + sampleMapUrl: '../EmuSP12.json', + sampleFolder: '../EmuSP12', +}); + export function MiniRepl({ tune }) { return <_MiniRepl tune={tune} defaultSynth={defaultSynth} hideOutsideView={true} />; } diff --git a/tutorial/tutorial.mdx b/tutorial/tutorial.mdx index 077d6f6d..d39c6259 100644 --- a/tutorial/tutorial.mdx +++ b/tutorial/tutorial.mdx @@ -758,6 +758,12 @@ They can provide streams of numbers that can be sampled at discrete points in ti {{ 'square2' | jsdoc }} +## Using Samples with Webdirt + +You can use the powerful sampling engine [Webdirt](https://github.com/dktr0/WebDirt) with Strudel. + +{{ 'Pattern.webdirt' | jsdoc }} + ## Using Superdirt via OSC In mainline tidal, the actual sound is generated via Superdirt, which runs inside Supercollider.