From cff3da3fd098492c74f71132b0c540bca5969ac5 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 10 Feb 2022 14:50:51 +0100 Subject: [PATCH 01/51] save code as base64 in url --- repl/src/App.tsx | 31 +++++++++++++++++++++---------- repl/src/midi.ts | 2 +- repl/src/tunes.ts | 4 +++- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/repl/src/App.tsx b/repl/src/App.tsx index 375e29cdf..d894ce699 100644 --- a/repl/src/App.tsx +++ b/repl/src/App.tsx @@ -4,16 +4,17 @@ import cx from './cx'; import * as Tone from 'tone'; import useCycle from './useCycle'; import type { Pattern } from './types'; -import * as tunes from './tunes'; +import defaultTune from './tunes'; import * as parser from './parse'; import CodeMirror from './CodeMirror'; import hot from '../public/hot'; import { isNote } from 'tone'; import { useWebMidi } from './midi'; - -const { tetris, tetrisRev, shapeShifted } = tunes; const { parse } = parser; +const [_, codeParam] = window.location.href.split('#'); +const decoded = atob(codeParam || ''); + const getHotCode = async () => { return fetch('/hot.js') .then((res) => res.text()) @@ -32,12 +33,17 @@ defaultSynth.set({ function App() { const [mode, setMode] = useState('javascript'); - const [code, setCode] = useState(shapeShifted); + const [code, setCode] = useState(decoded || defaultTune); const [log, setLog] = useState(''); const logBox = useRef(); const [error, setError] = useState(); const [pattern, setPattern] = useState(); const [activePattern, setActivePattern] = useState(); + const activatePattern = (_pattern = pattern) => { + setActivePattern(() => _pattern); + window.location.hash = '#' + btoa(code); + !cycle.started && cycle.start(); + }; const [isHot, setIsHot] = useState(false); // set to true to enable live coding in hot.js, using dev server const pushLog = (message: string) => setLog((log) => log + `${log ? '\n\n' : ''}${message}`); // logs events of cycle @@ -86,8 +92,7 @@ function App() { useLayoutEffect(() => { const handleKeyPress = (e: any) => { if (e.ctrlKey && e.code === 'Enter') { - setActivePattern(() => pattern); - !cycle.started && cycle.start(); + activatePattern(); } }; document.addEventListener('keypress', handleKeyPress); @@ -104,7 +109,7 @@ function App() { setCode(_code); setMode('javascript'); }); // if using HMR, just use changed file - setActivePattern(hot); + activatePattern(hot); return; } else { _code = hot; @@ -117,8 +122,8 @@ function App() { // need arrow function here! otherwise if user returns a function, react will think it's a state reducer // only first time, then need ctrl+enter setPattern(() => parsed.pattern); - if (!activePattern || isHot) { - setActivePattern(() => parsed.pattern); + if (isHot) { + activatePattern(parsed.pattern); } setMode(parsed.mode); setError(undefined); @@ -196,7 +201,13 @@ function App() { diff --git a/repl/src/midi.ts b/repl/src/midi.ts index d27165b3a..66a0af51f 100644 --- a/repl/src/midi.ts +++ b/repl/src/midi.ts @@ -52,7 +52,7 @@ Pattern.prototype.midi = function (output: string, channel = 1) { // await enableWebMidi() device.playNote(value, channel, { time, - duration: event.duration * 1000, + duration: event.duration * 1000 - 5, // velocity: velocity ?? 0.5, velocity: 0.9, }); diff --git a/repl/src/tunes.ts b/repl/src/tunes.ts index 0d3b03d43..e0c1d2fb2 100644 --- a/repl/src/tunes.ts +++ b/repl/src/tunes.ts @@ -34,7 +34,7 @@ export const shapeShifted = `stack( b1, b2, b1, b2, e2, e3, e2, e3, a1, a2, a1, a2, a1, a2, a1, a2, ).rev() -).slow(16).rev()`; +).slow(16)`; export const tetrisMidi = `${shapeShifted}.midi('IAC-Treiber Bus 1')`; @@ -192,3 +192,5 @@ export const whirlyStrudel = `mini("[e4 [b2 b3] c4]") .every(3, x => x.slow(1.5)) .fast(slowcat(1.25,1,1.5)) .every(2, _ => mini("e4 ~ e3 d4 ~"))`; + +export default shapeShifted; From 89863997368da1aac0783a5c17bb15a1451e2f6a Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Thu, 10 Feb 2022 14:53:25 +0100 Subject: [PATCH 02/51] build --- docs/dist/App.js | 31 +++++++++++++++++++++---------- docs/dist/midi.js | 2 +- docs/dist/tunes.js | 3 ++- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/docs/dist/App.js b/docs/dist/App.js index 937b4d063..e6a28405c 100644 --- a/docs/dist/App.js +++ b/docs/dist/App.js @@ -3,14 +3,15 @@ import logo from "./logo.svg.proxy.js"; import cx from "./cx.js"; import * as Tone from "../_snowpack/pkg/tone.js"; import useCycle from "./useCycle.js"; -import * as tunes from "./tunes.js"; +import defaultTune from "./tunes.js"; import * as parser from "./parse.js"; import CodeMirror from "./CodeMirror.js"; import hot from "../hot.js"; import {isNote} from "../_snowpack/pkg/tone.js"; import {useWebMidi} from "./midi.js"; -const {tetris, tetrisRev, shapeShifted} = tunes; const {parse} = parser; +const [_, codeParam] = window.location.href.split("#"); +const decoded = atob(codeParam || ""); const getHotCode = async () => { return fetch("/hot.js").then((res) => res.text()).then((src) => { return src.split("export default").slice(-1)[0].trim(); @@ -25,12 +26,17 @@ defaultSynth.set({ }); function App() { const [mode, setMode] = useState("javascript"); - const [code, setCode] = useState(shapeShifted); + const [code, setCode] = useState(decoded || defaultTune); const [log, setLog] = useState(""); const logBox = useRef(); const [error, setError] = useState(); const [pattern, setPattern] = useState(); const [activePattern, setActivePattern] = useState(); + const activatePattern = (_pattern = pattern) => { + setActivePattern(() => _pattern); + window.location.hash = "#" + btoa(code); + !cycle.started && cycle.start(); + }; const [isHot, setIsHot] = useState(false); const pushLog = (message) => setLog((log2) => log2 + `${log2 ? "\n\n" : ""}${message}`); const logCycle = (_events, cycle2) => { @@ -71,8 +77,7 @@ function App() { useLayoutEffect(() => { const handleKeyPress = (e) => { if (e.ctrlKey && e.code === "Enter") { - setActivePattern(() => pattern); - !cycle.started && cycle.start(); + activatePattern(); } }; document.addEventListener("keypress", handleKeyPress); @@ -86,7 +91,7 @@ function App() { setCode(_code2); setMode("javascript"); }); - setActivePattern(hot); + activatePattern(hot); return; } else { _code = hot; @@ -96,8 +101,8 @@ function App() { try { const parsed = parse(_code); setPattern(() => parsed.pattern); - if (!activePattern || isHot) { - setActivePattern(() => parsed.pattern); + if (isHot) { + activatePattern(parsed.pattern); } setMode(parsed.mode); setError(void 0); @@ -152,7 +157,7 @@ function App() { theme: "material", lineNumbers: true }, - onChange: (_, __, value) => { + onChange: (_2, __, value) => { if (!isHot) { setCode(value); } @@ -165,7 +170,13 @@ function App() { className: "absolute right-2 bottom-2 text-red-500" }, error?.message || "unknown error")), /* @__PURE__ */ React.createElement("button", { className: "flex-none w-full border border-gray-700 p-2 bg-slate-700 hover:bg-slate-500", - onClick: () => cycle.toggle() + onClick: () => { + if (!cycle.started) { + activatePattern(); + } else { + cycle.stop(); + } + } }, cycle.started ? "pause" : "play"), /* @__PURE__ */ React.createElement("textarea", { className: "grow bg-[#283237] border-0 text-xs", value: log, diff --git a/docs/dist/midi.js b/docs/dist/midi.js index 5294c81ca..3cf46f888 100644 --- a/docs/dist/midi.js +++ b/docs/dist/midi.js @@ -41,7 +41,7 @@ Pattern.prototype.midi = function(output, channel = 1) { time = time * 1e3 + timingOffset; device.playNote(value, channel, { time, - duration: event.duration * 1e3, + duration: event.duration * 1e3 - 5, velocity: 0.9 }); } diff --git a/docs/dist/tunes.js b/docs/dist/tunes.js index 33ada3c50..c9c9cfeaf 100644 --- a/docs/dist/tunes.js +++ b/docs/dist/tunes.js @@ -32,7 +32,7 @@ export const shapeShifted = `stack( b1, b2, b1, b2, e2, e3, e2, e3, a1, a2, a1, a2, a1, a2, a1, a2, ).rev() -).slow(16).rev()`; +).slow(16)`; export const tetrisMidi = `${shapeShifted}.midi('IAC-Treiber Bus 1')`; export const tetrisWithFunctions = `stack(sequence( 'e5', sequence('b4', 'c5'), 'd5', sequence('c5', 'b4'), @@ -171,3 +171,4 @@ export const whirlyStrudel = `mini("[e4 [b2 b3] c4]") .every(3, x => x.slow(1.5)) .fast(slowcat(1.25,1,1.5)) .every(2, _ => mini("e4 ~ e3 d4 ~"))`; +export default shapeShifted; From 4c15cab048496a8e82b17869055891894d4584a1 Mon Sep 17 00:00:00 2001 From: Felix Roos Date: Fri, 11 Feb 2022 01:09:46 +0100 Subject: [PATCH 03/51] style fixes --- repl/src/App.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/repl/src/App.tsx b/repl/src/App.tsx index d894ce699..7882df99a 100644 --- a/repl/src/App.tsx +++ b/repl/src/App.tsx @@ -151,7 +151,7 @@ function App() { }); return ( -
+
logo @@ -169,9 +169,9 @@ function App() { )}
-
+
-
+
- + {!cycle.started ? `press ctrl+enter to play\n` : !isHot && activePattern !== pattern @@ -212,7 +212,7 @@ function App() { {cycle.started ? 'pause' : 'play'}