diff --git a/iclc2023/slides/src/EventEditor.jsx b/iclc2023/slides/src/EventEditor.jsx index 45ad97114..bbb31cbec 100644 --- a/iclc2023/slides/src/EventEditor.jsx +++ b/iclc2023/slides/src/EventEditor.jsx @@ -28,7 +28,7 @@ function EventEditor({ code: initialCode }) { await initAudio; json.forEach((value) => { const hap = new Hap(new TimeSpan(0, 1), new TimeSpan(0, 1), value); - webaudioOutput(hap, 0.1, 1, 1); + webaudioOutput(hap, 0.01, 1, 1); }); } else if (e.key === '.') { stop(); diff --git a/iclc2023/slides/src/EventsDemo.jsx b/iclc2023/slides/src/EventsDemo.jsx index 1bdb4e322..50aa72ccd 100644 --- a/iclc2023/slides/src/EventsDemo.jsx +++ b/iclc2023/slides/src/EventsDemo.jsx @@ -1,8 +1,8 @@ import EventEditor from './EventEditor.jsx'; -import { useState } from 'react'; +import Stepper from './Stepper.jsx'; const snippets = [ - [`{ "s": "cp" }`, 'Samples'], + [`{ "s": "cp", "crush": 4 }`, 'Samples'], [`{ "s": "sawtooth", "note": "e3" }`, 'Oscillators'], [ `[ @@ -24,21 +24,15 @@ const snippets = [ ]; function EventsDemo() { - const [step, setStep] = useState(1); - return ( -
- {snippets.slice(0, step).map(([code, label], i) => { - const isActive = i === step - 1; - return ( -
-

{label}

- -
- ); - })} - {step < snippets.length && } -
+ ( + <> +

{label}

+ + + ))} + /> ); } diff --git a/iclc2023/slides/src/Highlight.jsx b/iclc2023/slides/src/Highlight.jsx index 0e9ac75ec..51415bd31 100644 --- a/iclc2023/slides/src/Highlight.jsx +++ b/iclc2023/slides/src/Highlight.jsx @@ -1,12 +1,17 @@ -import SyntaxHighlighter from 'react-syntax-highlighter'; +//import {Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; +//import { atomDark } from 'react-syntax-highlighter/dist/esm/styles/prism'; +//import SyntaxHighlighter from 'react-syntax-highlighter'; import { atomOneDark } from 'react-syntax-highlighter/dist/esm/styles/hljs'; - -Object.assign(atomOneDark.hljs, { padding: '10px' }); +import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'; +import js from 'react-syntax-highlighter/dist/esm/languages/hljs/javascript'; +import hs from 'react-syntax-highlighter/dist/esm/languages/hljs/haskell'; +SyntaxHighlighter.registerLanguage('javascript', js); +SyntaxHighlighter.registerLanguage('haskell', hs); function Highlight({ code, language }) { return (
- + {code}
diff --git a/iclc2023/slides/src/MiniComparison.jsx b/iclc2023/slides/src/MiniComparison.jsx index 1196681d3..a9d2e5dcb 100644 --- a/iclc2023/slides/src/MiniComparison.jsx +++ b/iclc2023/slides/src/MiniComparison.jsx @@ -1,5 +1,5 @@ -import { useState } from 'react'; import { SlideRepl } from './SlideRepl.jsx'; +import Stepper from './Stepper.jsx'; const snippets = [ [`sound("bd [hh sd]")`, `sound(seq("bd", ["hh", "sd"]))`, 'Nested Sequences'], // @@ -11,7 +11,6 @@ const snippets = [ ]; function MiniComparison() { - const [step, setStep] = useState(1); return ( <>

@@ -19,25 +18,21 @@ function MiniComparison() {
External DSL

-
- {snippets.slice(0, step).map(([a, b, label], i) => { - const isActive = i === step - 1; - return ( -
-

{label}

-
- - -
-
- - -
+ ( + <> +

{label}

+
+ +
- ); - })} -
- {step < snippets.length && } +
+ + +
+ + ))} + /> ); } diff --git a/iclc2023/slides/src/QueryDemo.jsx b/iclc2023/slides/src/QueryDemo.jsx index 9a55fe0b1..d71178e41 100644 --- a/iclc2023/slides/src/QueryDemo.jsx +++ b/iclc2023/slides/src/QueryDemo.jsx @@ -1,22 +1,23 @@ import { SlideRepl } from './SlideRepl.jsx'; import Highlight from './Highlight.jsx'; -import { useState } from 'react'; +import Stepper from './Stepper.jsx'; const snippets = [ - [, 'Logging Events'], + [, 'Logging Events'], [ <> e.show()))`} language="javascript" /> 1/2 | sound:bd", - "1/2 -> 3/4 | sound:hh", - "3/4 -> 1/1 | sound:sd" + "0/1 -> 1/2 | s:bd crush:4", + "1/2 -> 3/4 | s:hh crush:4", + "3/4 -> 1/1 | s:sd crush:4" ]`} /> , @@ -25,20 +26,15 @@ const snippets = [ ]; function QueryDemo() { - const [step, setStep] = useState(1); return ( -
- {snippets.slice(0, step).map(([snippet, label], i) => { - const isActive = i === step - 1; - return ( -
-

{label}

- {snippet} -
- ); - })} - {step < snippets.length && } -
+ ( + <> +

{label}

+ {snippet} + + ))} + /> ); } diff --git a/iclc2023/slides/src/Slides.jsx b/iclc2023/slides/src/Slides.jsx index e6794eb96..73d41bd9f 100644 --- a/iclc2023/slides/src/Slides.jsx +++ b/iclc2023/slides/src/Slides.jsx @@ -16,7 +16,18 @@ const loadedMDXFiles = await Promise.all( }), ); -const order = ['01', '02-0', '02-1', '02-2', 'mini-comparison', 'patterns-events', 'events-audio', '04']; +const order = [ + 'cover', + 'whatIsStrudel', + 'history', + 'hs2js', + 'mini-comparison', + 'patterns-events', + 'events-audio', + 'transpilation', + 'replflow', + 'systems', +]; const slideEntries = order.map((name) => loadedMDXFiles.find(([file]) => file === name)); diff --git a/iclc2023/slides/src/Stepper.jsx b/iclc2023/slides/src/Stepper.jsx new file mode 100644 index 000000000..f3427d602 --- /dev/null +++ b/iclc2023/slides/src/Stepper.jsx @@ -0,0 +1,20 @@ +import { useState } from 'react'; + +function Stepper({ steps }) { + const [step, setStep] = useState(1); + return ( +
+ {steps.slice(0, step).map((snippet, i) => { + const isActive = i === step - 1; + return ( +
+ {snippet} +
+ ); + })} + {step < steps.length && } +
+ ); +} + +export default Stepper; diff --git a/iclc2023/slides/src/SyntaxComparison.jsx b/iclc2023/slides/src/SyntaxComparison.jsx index 623323d9b..93d7bca59 100644 --- a/iclc2023/slides/src/SyntaxComparison.jsx +++ b/iclc2023/slides/src/SyntaxComparison.jsx @@ -1,6 +1,6 @@ -import { useState } from 'react'; import { SlideRepl } from './SlideRepl.jsx'; import Highlight from './Highlight.jsx'; +import Stepper from './Stepper.jsx'; const snippets = [ [`sound "bd ~ [sd cp]"`, [`sound("bd ~ [sd cp]")`], 'Mini Notation'], // @@ -40,7 +40,6 @@ const snippets = [ ]; function SyntaxComparison() { - const [step, setStep] = useState(1); return ( <>

@@ -48,35 +47,27 @@ function SyntaxComparison() {
Internal DSL / Fluent Interface

-
- {/*
-
Tidal
-
Strudel
-
*/} - {snippets.slice(0, step).map(([hs, js, label], i) => { - const isActive = i === step - 1; - return ( -
-

{label}

+ ( + <> +

{label}

+
+
+ + +
-
- - -
-
- {js.map((c, j) => ( -
- - -
- ))} -
+ {js.map((c, j) => ( +
+ + +
+ ))}
- ); - })} -
- {step < snippets.length && } + + ))} + /> ); } diff --git a/iclc2023/slides/src/TranspilationDemo.jsx b/iclc2023/slides/src/TranspilationDemo.jsx new file mode 100644 index 000000000..36ce41c28 --- /dev/null +++ b/iclc2023/slides/src/TranspilationDemo.jsx @@ -0,0 +1,91 @@ +import { useState, useCallback } from 'react'; +import { atomone } from '@uiw/codemirror-themes-all'; +import { CodeMirror, flash, useKeydown } from '@strudel.cycles/react'; +import { transpiler } from '@strudel.cycles/transpiler'; +import Highlight from './Highlight'; +import Stepper from './Stepper'; +import escodegen from 'escodegen'; + +function getTranspiled(code) { + return transpiler(code, { + addReturn: false, + codegenOptions: { + format: escodegen.FORMAT_MINIFY, + }, + }); +} + +function TranspilationEditor({ code: initialCode }) { + const [code, setCode] = useState(initialCode); + const [transpiled, setTranspiled] = useState(getTranspiled(initialCode)); + const [view, setView] = useState(); + useKeydown( + useCallback( + async (e) => { + if (view?.hasFocus) { + if (e.ctrlKey || e.altKey) { + if (e.code === 'Enter') { + /* if (getAudioContext().state !== 'running') { + alert('please click play to initialize the audio. you can use shortcuts after that!'); + return; + } */ + e.preventDefault(); + flash(view); + const t = getTranspiled(code); + setTranspiled(t); + console.log('transpiled', t); + } else if (e.key === '.') { + stop(); + e.preventDefault(); + } + } + } + }, + [code, view], + ), + ); + return ( + <> + { + setCode(v); + }} + theme={atomone} + onViewChanged={(v) => setView(v)} + fontSize={32} + /> + + ⬇️ transpiles to ⬇️ via acorn / estree-walker / escodegen + + + + ); +} + +function TranspilationDemo() { + return ( +
+ , + <> + ⬇️ calls ⬇️ via peggy + + ➡️ location can be used for highlighting + , + ]} + /> +
+ ); +} + +export default TranspilationDemo; diff --git a/iclc2023/slides/src/slides/01.mdx b/iclc2023/slides/src/slides/cover.mdx similarity index 100% rename from iclc2023/slides/src/slides/01.mdx rename to iclc2023/slides/src/slides/cover.mdx diff --git a/iclc2023/slides/src/slides/02-1.mdx b/iclc2023/slides/src/slides/history.mdx similarity index 100% rename from iclc2023/slides/src/slides/02-1.mdx rename to iclc2023/slides/src/slides/history.mdx diff --git a/iclc2023/slides/src/slides/02-2.mdx b/iclc2023/slides/src/slides/hs2js.mdx similarity index 100% rename from iclc2023/slides/src/slides/02-2.mdx rename to iclc2023/slides/src/slides/hs2js.mdx diff --git a/iclc2023/slides/src/slides/04.mdx b/iclc2023/slides/src/slides/replflow.mdx similarity index 100% rename from iclc2023/slides/src/slides/04.mdx rename to iclc2023/slides/src/slides/replflow.mdx diff --git a/iclc2023/slides/src/slides/02-3.mdx b/iclc2023/slides/src/slides/systems.mdx similarity index 100% rename from iclc2023/slides/src/slides/02-3.mdx rename to iclc2023/slides/src/slides/systems.mdx diff --git a/iclc2023/slides/src/slides/transpilation.mdx b/iclc2023/slides/src/slides/transpilation.mdx new file mode 100644 index 000000000..3e101aefa --- /dev/null +++ b/iclc2023/slides/src/slides/transpilation.mdx @@ -0,0 +1,5 @@ +import TranspilationDemo from '../TranspilationDemo'; + +# Transpilation + + diff --git a/iclc2023/slides/src/slides/02-0.mdx b/iclc2023/slides/src/slides/whatIsStrudel.mdx similarity index 100% rename from iclc2023/slides/src/slides/02-0.mdx rename to iclc2023/slides/src/slides/whatIsStrudel.mdx diff --git a/packages/transpiler/transpiler.mjs b/packages/transpiler/transpiler.mjs index fee9d542e..18f87bd3d 100644 --- a/packages/transpiler/transpiler.mjs +++ b/packages/transpiler/transpiler.mjs @@ -4,7 +4,7 @@ import { walk } from 'estree-walker'; import { isNoteWithOctave } from '@strudel.cycles/core'; export function transpiler(input, options = {}) { - const { wrapAsync = false, addReturn = true, simpleLocs = false } = options; + const { wrapAsync = false, addReturn = true, simpleLocs = false, codegenOptions = {} } = options; let ast = parse(input, { ecmaVersion: 2022, @@ -47,7 +47,7 @@ export function transpiler(input, options = {}) { argument: expression, }; } - const output = escodegen.generate(ast); + const output = escodegen.generate(ast, codegenOptions); if (wrapAsync) { return `(async ()=>{${output}})()`; }