add repl-react + fix deps

This commit is contained in:
Felix Roos 2022-03-25 18:46:45 +01:00
parent 6f60a3a1d5
commit 6430f6207d
53 changed files with 33850 additions and 24809 deletions

53
packages/tone/draw.mjs Normal file
View file

@ -0,0 +1,53 @@
import * as Tone from 'tone';
import { Pattern } from '@strudel/core';
export const getDrawContext = (id = 'test-canvas') => {
let canvas = document.querySelector('#' + id);
if (!canvas) {
canvas = document.createElement('canvas');
canvas.id = id;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style = 'pointer-events:none;width:100%;height:100%;position:fixed;top:0;left:0;z-index:5';
document.body.prepend(canvas);
}
return canvas.getContext('2d');
};
Pattern.prototype.draw = function (callback, cycleSpan, lookaheadCycles = 1) {
if (window.strudelAnimation) {
cancelAnimationFrame(window.strudelAnimation);
}
const ctx = getDrawContext();
let cycle,
events = [];
const animate = (time) => {
const t = Tone.getTransport().seconds;
if (cycleSpan) {
const currentCycle = Math.floor(t / cycleSpan);
if (cycle !== currentCycle) {
cycle = currentCycle;
const begin = currentCycle * cycleSpan;
const end = (currentCycle + lookaheadCycles) * cycleSpan;
events = this._asNumber(true) // true = silent error
.query(new State(new TimeSpan(begin, end)))
.filter((event) => event.part.begin.equals(event.whole.begin));
}
}
callback(ctx, events, t, cycleSpan, time);
window.strudelAnimation = requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
return this;
};
export const cleanup = () => {
const ctx = getDrawContext();
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
if (window.strudelAnimation) {
cancelAnimationFrame(window.strudelAnimation);
}
if (window.strudelScheduler) {
clearInterval(window.strudelScheduler);
}
};

View file

@ -0,0 +1,38 @@
import { Pattern } from '@strudel/core';
Pattern.prototype.pianoroll = function ({
timeframe = 10,
inactive = '#C9E597',
active = '#FFCA28',
background = '#2A3236',
maxMidi = 90,
minMidi = 0,
} = {}) {
const w = window.innerWidth;
const h = window.innerHeight;
const midiRange = maxMidi - minMidi + 1;
const height = h / midiRange;
this.draw(
(ctx, events, t) => {
ctx.fillStyle = background;
ctx.clearRect(0, 0, w, h);
ctx.fillRect(0, 0, w, h);
events.forEach((event) => {
const isActive = event.whole.begin <= t && event.whole.end >= t;
ctx.fillStyle = event.context?.color || inactive;
ctx.strokeStyle = event.context?.color || active;
ctx.globalAlpha = event.context.velocity ?? 1;
const x = Math.round((event.whole.begin / timeframe) * w);
const width = Math.round(((event.whole.end - event.whole.begin) / timeframe) * w);
const y = Math.round(h - ((Number(event.value) - minMidi) / midiRange) * h);
const offset = (t / timeframe) * w;
const margin = 0;
const coords = [x - offset + margin + 1, y + 1, width - 2, height - 2];
isActive ? ctx.strokeRect(...coords) : ctx.fillRect(...coords);
});
},
timeframe,
2, // lookaheadCycles
);
return this;
};

View file

@ -1,5 +1,6 @@
import { Pattern as _Pattern } from '../core/strudel.mjs';
import Tone from 'tone';
import { Pattern as _Pattern } from '@strudel/core';
import * as Tone from 'tone';
const {
AutoFilter,
Destination,
@ -20,8 +21,8 @@ const {
getDestination,
Players,
} = Tone;
/* import tonePiano from '@tonejs/piano';
const { Piano } = tonePiano; */
import * as tonePiano from '@tonejs/piano';
const { Piano } = tonePiano;
import { getPlayableNoteValue } from '../../packages/core/util.mjs';
// "balanced" | "interactive" | "playback";
@ -106,11 +107,11 @@ export const players = (options, baseUrl = '') => {
});
};
export const synth = (options) => new Synth(options);
/* export const piano = async (options = { velocities: 1 }) => {
export const piano = async (options = { velocities: 1 }) => {
const p = new Piano(options);
await p.load();
return p;
}; */
};
// effect helpers
export const vol = (v) => new Gain(v);

50
packages/tone/ui.mjs Normal file
View file

@ -0,0 +1,50 @@
import * as Tone from 'tone';
export const hideHeader = () => {
document.getElementById('header').style = 'display:none';
};
function frame(callback) {
if (window.strudelAnimation) {
cancelAnimationFrame(window.strudelAnimation);
}
const animate = (animationTime) => {
const toneTime = Tone.getTransport().seconds;
callback(animationTime, toneTime);
window.strudelAnimation = requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}
export const backgroundImage = function (src, animateOptions = {}) {
const container = document.getElementById('code');
const bg = 'background-image:url(' + src + ');background-size:contain;';
container.style = bg;
const { className: initialClassName } = container;
const handleOption = (option, value) => {
({
style: () => (container.style = bg + ';' + value),
className: () => (container.className = value + ' ' + initialClassName),
}[option]());
};
const funcOptions = Object.entries(animateOptions).filter(([_, v]) => typeof v === 'function');
const stringOptions = Object.entries(animateOptions).filter(([_, v]) => typeof v === 'string');
stringOptions.forEach(([option, value]) => handleOption(option, value));
if (funcOptions.length === 0) {
return;
}
frame((_, t) =>
funcOptions.forEach(([option, value]) => {
handleOption(option, value(t));
}),
);
};
export const cleanup = () => {
const container = document.getElementById('code');
if (container) {
container.style = '';
container.className = 'grow relative'; // has to match App.tsx
}
};