move draw stuff from tone to core + fix getPhase

This commit is contained in:
Felix Roos 2022-11-13 01:42:00 +01:00
parent c722904831
commit e769ed2fd8
17 changed files with 259 additions and 5684 deletions

9
package-lock.json generated
View File

@ -12545,8 +12545,9 @@
"dependencies": { "dependencies": {
"@codemirror/lang-javascript": "^6.1.1", "@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.2", "@strudel.cycles/core": "^0.3.2",
"@strudel.cycles/eval": "^0.3.2",
"@strudel.cycles/tone": "^0.3.3", "@strudel.cycles/tone": "^0.3.3",
"@strudel.cycles/transpiler": "^0.3.2",
"@strudel.cycles/webaudio": "^0.3.3",
"@uiw/codemirror-themes": "^4.12.4", "@uiw/codemirror-themes": "^4.12.4",
"@uiw/react-codemirror": "^4.12.4", "@uiw/react-codemirror": "^4.12.4",
"react-hook-inview": "^4.5.0" "react-hook-inview": "^4.5.0"
@ -14463,8 +14464,9 @@
"requires": { "requires": {
"@codemirror/lang-javascript": "^6.1.1", "@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.2", "@strudel.cycles/core": "^0.3.2",
"@strudel.cycles/eval": "^0.3.2",
"@strudel.cycles/tone": "^0.3.3", "@strudel.cycles/tone": "^0.3.3",
"@strudel.cycles/transpiler": "^0.3.2",
"@strudel.cycles/webaudio": "^0.3.3",
"@types/react": "^17.0.2", "@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2", "@types/react-dom": "^17.0.2",
"@uiw/codemirror-themes": "^4.12.4", "@uiw/codemirror-themes": "^4.12.4",
@ -20343,8 +20345,9 @@
"requires": { "requires": {
"@codemirror/lang-javascript": "^6.1.1", "@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.2", "@strudel.cycles/core": "^0.3.2",
"@strudel.cycles/eval": "^0.3.2",
"@strudel.cycles/tone": "^0.3.3", "@strudel.cycles/tone": "^0.3.3",
"@strudel.cycles/transpiler": "^0.3.2",
"@strudel.cycles/webaudio": "^0.3.3",
"@types/react": "^17.0.2", "@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2", "@types/react-dom": "^17.0.2",
"@uiw/codemirror-themes": "^4.12.4", "@uiw/codemirror-themes": "^4.12.4",

View File

@ -46,8 +46,8 @@ export class Cyclist {
interval, // duration of each cycle interval, // duration of each cycle
); );
} }
getPhase(latencyCompensation = true) { getPhase() {
return this.phase - (latencyCompensation ? this.latency : 0); return this.getTime() - this.origin;
} }
setStarted(v) { setStarted(v) {
this.started = v; this.started = v;

View File

@ -4,8 +4,7 @@ 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/>. 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 { Tone } from './tone.mjs'; import { Pattern, getTime } from './index.mjs';
import { Pattern } from '@strudel.cycles/core';
export const getDrawContext = (id = 'test-canvas') => { export const getDrawContext = (id = 'test-canvas') => {
let canvas = document.querySelector('#' + id); let canvas = document.querySelector('#' + id);
@ -28,7 +27,7 @@ Pattern.prototype.draw = function (callback, { from, to, onQuery }) {
let cycle, let cycle,
events = []; events = [];
const animate = (time) => { const animate = (time) => {
const t = Tone.getTransport().seconds; const t = getTime();
if (from !== undefined && to !== undefined) { if (from !== undefined && to !== undefined) {
const currentCycle = Math.floor(t); const currentCycle = Math.floor(t);
if (cycle !== currentCycle) { if (cycle !== currentCycle) {

View File

@ -4,9 +4,7 @@ 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/>. 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 * as strudel from '@strudel.cycles/core'; import { isPattern, Pattern } from './index.mjs';
const { isPattern, Pattern } = strudel;
let scoped = false; let scoped = false;
export const evalScope = async (...args) => { export const evalScope = async (...args) => {

View File

@ -19,6 +19,10 @@ export * from './speak.mjs';
export * from './evaluate.mjs'; export * from './evaluate.mjs';
export * from './repl.mjs'; export * from './repl.mjs';
export * from './logger.mjs'; export * from './logger.mjs';
export * from './time.mjs';
export * from './draw.mjs';
export * from './pianoroll.mjs';
export * from './ui.mjs';
export { default as drawLine } from './drawLine.mjs'; export { default as drawLine } from './drawLine.mjs';
export { default as gist } from './gist.js'; export { default as gist } from './gist.js';
// below won't work with runtime.mjs (json import fails) // below won't work with runtime.mjs (json import fails)

View File

@ -4,7 +4,7 @@ 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/>. 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 { Pattern } from '@strudel.cycles/core'; import { Pattern } from './index.mjs';
const scale = (normalized, min, max) => normalized * (max - min) + min; const scale = (normalized, min, max) => normalized * (max - min) + min;
const getValue = (e) => { const getValue = (e) => {

View File

@ -1,6 +1,7 @@
import { Cyclist } from './cyclist.mjs'; import { Cyclist } from './cyclist.mjs';
import { evaluate as _evaluate } from './evaluate.mjs'; import { evaluate as _evaluate } from './evaluate.mjs';
import { logger } from './logger.mjs'; import { logger } from './logger.mjs';
import { setTime } from './time.mjs';
export function repl({ export function repl({
interval, interval,
@ -33,6 +34,7 @@ export function repl({
getTime, getTime,
onToggle, onToggle,
}); });
setTime(() => scheduler.getPhase()); // TODO: refactor?
const evaluate = async (code, autostart = true) => { const evaluate = async (code, autostart = true) => {
if (!code) { if (!code) {
throw new Error('no code to evaluate'); throw new Error('no code to evaluate');

13
packages/core/time.mjs Normal file
View File

@ -0,0 +1,13 @@
console.log('load time.mjs');
let time;
export function getTime() {
if (!time) {
throw new Error('no time set! use setTime to define a time source');
}
return time();
}
export function setTime(func) {
console.log('setTime!');
time = func;
}

View File

@ -4,7 +4,7 @@ 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/>. 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 { Tone } from './tone.mjs'; import { getTime } from './time.mjs';
export const hideHeader = () => { export const hideHeader = () => {
document.getElementById('header').style = 'display:none'; document.getElementById('header').style = 'display:none';
@ -15,8 +15,7 @@ function frame(callback) {
cancelAnimationFrame(window.strudelAnimation); cancelAnimationFrame(window.strudelAnimation);
} }
const animate = (animationTime) => { const animate = (animationTime) => {
const toneTime = Tone.getTransport().seconds; callback(animationTime, getTime());
callback(animationTime, toneTime);
window.strudelAnimation = requestAnimationFrame(animate); window.strudelAnimation = requestAnimationFrame(animate);
}; };
requestAnimationFrame(animate); requestAnimationFrame(animate);
@ -51,6 +50,7 @@ export const cleanupUi = () => {
const container = document.getElementById('code'); const container = document.getElementById('code');
if (container) { if (container) {
container.style = ''; container.style = '';
container.className = 'grow relative'; // has to match App.tsx // TODO: find a way to remove that duplication..
container.className = 'grow flex text-gray-100 relative overflow-auto cursor-text pb-0'; // has to match App.tsx
} }
}; };

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -40,7 +40,8 @@
"dependencies": { "dependencies": {
"@codemirror/lang-javascript": "^6.1.1", "@codemirror/lang-javascript": "^6.1.1",
"@strudel.cycles/core": "^0.3.2", "@strudel.cycles/core": "^0.3.2",
"@strudel.cycles/eval": "^0.3.2", "@strudel.cycles/transpiler": "^0.3.2",
"@strudel.cycles/webaudio": "^0.3.3",
"@strudel.cycles/tone": "^0.3.3", "@strudel.cycles/tone": "^0.3.3",
"@uiw/codemirror-themes": "^4.12.4", "@uiw/codemirror-themes": "^4.12.4",
"@uiw/react-codemirror": "^4.12.4", "@uiw/react-codemirror": "^4.12.4",

View File

@ -1,5 +1,5 @@
import { useRef, useCallback, useEffect, useMemo, useState } from 'react'; import { useRef, useCallback, useEffect, useMemo, useState } from 'react';
import { repl } from '@strudel.cycles/core/repl.mjs'; import { repl } from '@strudel.cycles/core';
import { transpiler } from '@strudel.cycles/transpiler'; import { transpiler } from '@strudel.cycles/transpiler';
function useStrudel({ function useStrudel({

View File

@ -24,8 +24,9 @@ export default defineConfig({
// TODO: find out which of below names are obsolete now // TODO: find out which of below names are obsolete now
'@strudel.cycles/tone', '@strudel.cycles/tone',
'@strudel.cycles/eval', '@strudel.cycles/eval',
'@strudel.cycles/transpiler',
'acorn',
'@strudel.cycles/core', '@strudel.cycles/core',
'@strudel.cycles/core/util.mjs',
'@strudel.cycles/mini', '@strudel.cycles/mini',
'@strudel.cycles/tonal', '@strudel.cycles/tonal',
'@strudel.cycles/midi', '@strudel.cycles/midi',

View File

@ -1,5 +1 @@
import './pianoroll.mjs';
export * from './tone.mjs'; export * from './tone.mjs';
export * from './draw.mjs';
export * from './ui.mjs';

View File

@ -34,7 +34,7 @@ currently broken / buggy:
- [ ] hideHeader flag - [ ] hideHeader flag
- [ ] pending flag - [ ] pending flag
- [x] web midi, TODO: test - [x] web midi, TODO: test
- [ ] draw / pianoroll - [x] draw / pianoroll
- [x] repl url hash does not work - [x] repl url hash does not work
- [x] pause does stop - [x] pause does stop
- [-] pause then play logs "TOO LATE" and drops some events => now doing full stop - [-] pause then play logs "TOO LATE" and drops some events => now doing full stop
@ -42,6 +42,8 @@ currently broken / buggy:
- [x] unexpected ast format without body expression (kalimba) - [x] unexpected ast format without body expression (kalimba)
- [x] highlighting seems too late (off by latency ?) - [x] highlighting seems too late (off by latency ?)
- [x] highlighting sometimes drops highlights (zeldasRescue first note) - [x] highlighting sometimes drops highlights (zeldasRescue first note)
- [ ] highlighting still sometimes drops highlights (zeldasRescue somtimes) - [x] highlighting still sometimes drops highlights (zeldasRescue somtimes)
- [ ] highlighting out of range error is back (delete large chunk at the top while highlighting below is triggered) - [ ] highlighting out of range error is back (delete large chunk at the top while highlighting below is triggered)
- [ ] find a way to display errors when console is closed / another tab selected - [ ] find a way to display errors when console is closed / another tab selected
- [x] scheduler.getPhase is quantized to clock interval
- => draw was choppy + that also caused useHighlighting bugs

View File

@ -4,17 +4,14 @@ 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/>. 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 { evaluate } from '@strudel.cycles/eval';
import { CodeMirror, cx, flash, useHighlighting } from '@strudel.cycles/react'; import { CodeMirror, cx, flash, useHighlighting } from '@strudel.cycles/react';
// import { cleanupDraw, cleanupUi, Tone } from '@strudel.cycles/tone';
import React, { useEffect, useLayoutEffect, useRef, useState, useCallback } from 'react'; import React, { useEffect, useLayoutEffect, useRef, useState, useCallback } from 'react';
import './App.css'; import './App.css';
import logo from './logo.svg';
import * as tunes from './tunes.mjs'; import * as tunes from './tunes.mjs';
import { prebake } from './prebake.mjs'; import { prebake } from './prebake.mjs';
import * as WebDirt from 'WebDirt'; import * as WebDirt from 'WebDirt';
import { resetLoadedSamples, getAudioContext, getLoadedSamples } from '@strudel.cycles/webaudio'; import { resetLoadedSamples, getAudioContext, getLoadedSamples } from '@strudel.cycles/webaudio';
import { controls, evalScope, logger } from '@strudel.cycles/core'; import { controls, evalScope, logger, cleanupDraw, cleanupUi } from '@strudel.cycles/core';
import { createClient } from '@supabase/supabase-js'; import { createClient } from '@supabase/supabase-js';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import { useStrudel } from '@strudel.cycles/react'; import { useStrudel } from '@strudel.cycles/react';
@ -141,7 +138,8 @@ function App() {
} }
}, [log, activeFooter]); }, [log, activeFooter]);
useLayoutEffect(() => { useLayoutEffect(() => {
if (activeFooter === 'console') { if (!footerContent.current) {
} else if (activeFooter === 'console') {
footerContent.current.scrollTop = footerContent.current?.scrollHeight; footerContent.current.scrollTop = footerContent.current?.scrollHeight;
} else { } else {
footerContent.current.scrollTop = 0; footerContent.current.scrollTop = 0;
@ -197,7 +195,7 @@ function App() {
view, view,
pattern, pattern,
active: started && !activeCode?.includes('strudel disable-highlighting'), active: started && !activeCode?.includes('strudel disable-highlighting'),
getTime: () => scheduler.getPhase(), getTime: () => scheduler.getPhase(), // TODO: problem: phase is quantized to clock interval...
}); });
// //
@ -222,9 +220,9 @@ function App() {
const handleShuffle = async () => { const handleShuffle = async () => {
const { code, name } = getRandomTune(); const { code, name } = getRandomTune();
logger(`[repl] ✨ loading random tune "${name}"`); logger(`[repl] ✨ loading random tune "${name}"`);
/*
cleanupDraw(); cleanupDraw();
cleanupUi(); */ cleanupUi();
resetLoadedSamples(); resetLoadedSamples();
await prebake(); // declare default samples await prebake(); // declare default samples
await evaluate(code, false); await evaluate(code, false);
@ -390,7 +388,7 @@ function App() {
<section className="grow flex text-gray-100 relative overflow-auto cursor-text pb-0" id="code"> <section className="grow flex text-gray-100 relative overflow-auto cursor-text pb-0" id="code">
<CodeMirror value={code} onChange={handleChangeCode} onViewChanged={setView} /> <CodeMirror value={code} onChange={handleChangeCode} onViewChanged={setView} />
</section> </section>
<footer className="bg-footer"> <footer className="bg-footer z-[20]">
<div className="flex justify-between px-2"> <div className="flex justify-between px-2">
<div className="flex pb-2 select-none"> <div className="flex pb-2 select-none">
<FooterTab name="intro" /> <FooterTab name="intro" />