This commit is contained in:
Felix Roos 2022-03-16 23:04:25 +01:00
parent d8d460f175
commit 4128213acb
13 changed files with 355 additions and 114 deletions

7
docs/dist/App.js vendored
View file

@ -1,6 +1,6 @@
import React, {useCallback, useLayoutEffect, useRef, useState} from "../_snowpack/pkg/react.js";
import * as Tone from "../_snowpack/pkg/tone.js";
import CodeMirror, {markEvent} from "./CodeMirror.js";
import CodeMirror, {markEvent, markParens} from "./CodeMirror.js";
import cx from "./cx.js";
import {evaluate} from "./evaluate.js";
import logo from "./logo.svg.proxy.js";
@ -68,6 +68,7 @@ function App() {
return /* @__PURE__ */ React.createElement("div", {
className: "min-h-screen flex flex-col"
}, /* @__PURE__ */ React.createElement("header", {
id: "header",
className: cx("flex-none w-full h-14 px-2 flex border-b border-gray-200 justify-between z-[10]", uiHidden ? "bg-transparent text-white" : "bg-white")
}, /* @__PURE__ */ React.createElement("div", {
className: "flex items-center space-x-2"
@ -116,7 +117,8 @@ function App() {
}, "👀 ", uiHidden ? "show ui" : "hide ui"))), /* @__PURE__ */ React.createElement("section", {
className: "grow flex flex-col text-gray-100"
}, /* @__PURE__ */ React.createElement("div", {
className: "grow relative"
className: "grow relative",
id: "code"
}, /* @__PURE__ */ React.createElement("div", {
className: cx("h-full transition-opacity", error ? "focus:ring-red-500" : "focus:ring-slate-800", uiHidden ? "opacity-0" : "opacity-100")
}, /* @__PURE__ */ React.createElement(CodeMirror, {
@ -129,6 +131,7 @@ function App() {
styleSelectedText: true,
cursorBlinkRate: 0
},
onCursor: markParens,
onChange: (_2, __, value) => setCode(value)
}), /* @__PURE__ */ React.createElement("span", {
className: "p-4 absolute top-0 right-0 text-xs whitespace-pre text-right pointer-events-none"

View file

@ -4,7 +4,7 @@ import "../_snowpack/pkg/codemirror/mode/javascript/javascript.js";
import "../_snowpack/pkg/codemirror/mode/pegjs/pegjs.js";
import "../_snowpack/pkg/codemirror/lib/codemirror.css.proxy.js";
import "../_snowpack/pkg/codemirror/theme/material.css.proxy.js";
export default function CodeMirror({value, onChange, options, editorDidMount}) {
export default function CodeMirror({value, onChange, onCursor, options, editorDidMount}) {
options = options || {
mode: "javascript",
theme: "material",
@ -16,7 +16,8 @@ export default function CodeMirror({value, onChange, options, editorDidMount}) {
value,
options,
onBeforeChange: onChange,
editorDidMount
editorDidMount,
onCursor: (editor, data) => onCursor?.(editor, data)
});
}
export const markEvent = (editor) => (time, event) => {
@ -24,8 +25,71 @@ export const markEvent = (editor) => (time, event) => {
if (!locs || !editor) {
return;
}
const marks = locs.map(({start, end}) => editor.getDoc().markText({line: start.line - 1, ch: start.column}, {line: end.line - 1, ch: end.column}, {css: "background-color: #FFCA28; color: black"}));
const marks = locs.map(({start, end}) => editor.getDoc().markText({line: start.line - 1, ch: start.column}, {line: end.line - 1, ch: end.column}, {css: "outline: 2px solid #FFCA28; box-sizing:border-box"}));
setTimeout(() => {
marks.forEach((mark) => mark.clear());
}, event.duration * 0.9 * 1e3);
}, event.duration * 1e3);
};
let parenMark;
export const markParens = (editor, data) => {
const v = editor.getDoc().getValue();
const marked = getCurrentParenArea(v, data);
parenMark?.clear();
parenMark = editor.getDoc().markText(...marked, {css: "background-color: #0000dd20"});
};
export function offsetToPosition(offset, code) {
const lines = code.split("\n");
let line = 0;
let ch = 0;
for (let i = 0; i < offset; i++) {
if (ch === lines[line].length) {
line++;
ch = 0;
} else {
ch++;
}
}
return {line, ch};
}
export function positionToOffset(position, code) {
const lines = code.split("\n");
let offset = 0;
for (let i = 0; i < position.line; i++) {
offset += lines[i].length + 1;
}
offset += position.ch;
return offset;
}
export function getCurrentParenArea(code, caretPosition) {
const caret = positionToOffset(caretPosition, code);
let open, i, begin, end;
i = caret;
open = 0;
while (i > 0) {
if (code[i - 1] === "(") {
open--;
} else if (code[i - 1] === ")") {
open++;
}
if (open === -1) {
break;
}
i--;
}
begin = i;
i = caret;
open = 0;
while (i < code.length) {
if (code[i] === "(") {
open--;
} else if (code[i] === ")") {
open++;
}
if (open === 1) {
break;
}
i++;
}
end = i;
return [begin, end].map((o) => offsetToPosition(o, code));
}

View file

@ -8,6 +8,7 @@ import "./tune.js";
import "./tune.js";
import "./pianoroll.js";
import "./draw.js";
import * as uiHelpers from "./ui.js";
import * as drawHelpers from "./draw.js";
import gist from "./gist.js";
import shapeshifter from "./shapeshifter.js";
@ -27,7 +28,7 @@ function hackLiteral(literal, names, func) {
}
hackLiteral(String, ["mini", "m"], bootstrapped.mini);
hackLiteral(String, ["pure", "p"], bootstrapped.pure);
Object.assign(globalThis, bootstrapped, Tone, toneHelpers, voicingHelpers, drawHelpers, {gist});
Object.assign(globalThis, bootstrapped, Tone, toneHelpers, voicingHelpers, drawHelpers, uiHelpers, {gist});
export const evaluate = async (code) => {
const shapeshifted = shapeshifter(code);
drawHelpers.cleanup();

2
docs/dist/tone.js vendored
View file

@ -36,7 +36,7 @@ Pattern.prototype.tone = function(instrument) {
break;
case "Piano":
note = getPlayableNoteValue(event2);
instrument.keyDown({note, time, velocity: 0.5});
instrument.keyDown({note, time, velocity});
instrument.keyUp({note, time: time + event2.duration, velocity});
break;
case "Sampler":

177
docs/dist/tunes.js vendored
View file

@ -265,63 +265,57 @@ export const technoDrums = `stack(
"~ x".tone(new Tone.NoiseSynth().toDestination()),
"[~ c4]*2".tone(new Tone.MetalSynth().set({envelope:{decay:0.06,sustain:0}}).chain(new Gain(0.5),getDestination()))
)`;
export const loungerave = `() => {
const delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"),
"~ <x!7 [x@3 x]>".tone(snare).mask("<x@7 ~>/4"),
"[~ c4]*2".tone(hihat)
);
const thru = (x) => x.transpose("<0 1>/8").transpose(1);
const synths = stack(
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2").edit(thru).tone(bass),
"<Cm7 Bb7 Fm7 G7b9>/2".struct("~ [x@0.1 ~]").voicings().edit(thru).every(2, early(1/4)).tone(keys).mask("<x@7 ~>/8".early(1/4))
)
return stack(
drums,
synths
)
//.mask("<x ~>*4")
//.early("0.25 0");
}`;
export const caverave = `() => {
const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"),
"~ <x!7 [x@3 x]>".tone(snare).mask("<x@7 ~>/4"),
"[~ c4]*2".tone(hihat)
);
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
const synths = stack(
"<eb4 d4 c4 b3>/2".scale(timeCat([3,'C minor'],[1,'C melodic minor']).slow(8)).struct("[~ x]*2")
.edit(
scaleTranspose(0).early(0),
scaleTranspose(2).early(1/8),
scaleTranspose(7).early(1/4),
scaleTranspose(8).early(3/8)
).apply(thru).tone(keys).mask("<~ x>/16"),
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2)).apply(thru).tone(bass),
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.1 ~]".fast(2)).voicings().apply(thru).every(2, early(1/8)).tone(keys).mask("<x@7 ~>/8".early(1/4))
)
return stack(
drums.fast(2),
synths
).slow(2);
}`;
export const loungerave = `const delay = new FeedbackDelay(1/8, .2).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"),
"~ <x!7 [x@3 x]>".tone(snare).mask("<x@7 ~>/4"),
"[~ c4]*2".tone(hihat)
);
const thru = (x) => x.transpose("<0 1>/8").transpose(1);
const synths = stack(
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2").edit(thru).tone(bass),
"<Cm7 Bb7 Fm7 G7b9>/2".struct("~ [x@0.1 ~]").voicings().edit(thru).every(2, early(1/4)).tone(keys).mask("<x@7 ~>/8".early(1/4))
)
stack(
drums,
synths
)`;
export const caverave = `const delay = new FeedbackDelay(1/8, .4).chain(vol(0.5), out());
const kick = new MembraneSynth().chain(vol(.8), out());
const snare = new NoiseSynth().chain(vol(.8), out());
const hihat = new MetalSynth().set(adsr(0, .08, 0, .1)).chain(vol(.3).connect(delay),out());
const bass = new Synth().set({ ...osc('sawtooth'), ...adsr(0, .1, .4) }).chain(lowpass(900), vol(.5), out());
const keys = new PolySynth().set({ ...osc('sawtooth'), ...adsr(0, .5, .2, .7) }).chain(lowpass(1200), vol(.5), out());
const drums = stack(
"c1*2".tone(kick).mask("<x@7 ~>/8"),
"~ <x!7 [x@3 x]>".tone(snare).mask("<x@7 ~>/4"),
"[~ c4]*2".tone(hihat)
);
const thru = (x) => x.transpose("<0 1>/8").transpose(-1);
const synths = stack(
"<eb4 d4 c4 b3>/2".scale(timeCat([3,'C minor'],[1,'C melodic minor']).slow(8)).struct("[~ x]*2")
.edit(
scaleTranspose(0).early(0),
scaleTranspose(2).early(1/8),
scaleTranspose(7).early(1/4),
scaleTranspose(8).early(3/8)
).apply(thru).tone(keys).mask("<~ x>/16"),
"<C2 Bb1 Ab1 [G1 [G2 G1]]>/2".struct("[x [~ x] <[~ [~ x]]!3 [x x]>@2]/2".fast(2)).apply(thru).tone(bass),
"<Cm7 Bb7 Fm7 G7b13>/2".struct("~ [x@0.1 ~]".fast(2)).voicings().apply(thru).every(2, early(1/8)).tone(keys).mask("<x@7 ~>/8".early(1/4))
)
stack(
drums.fast(2),
synths
).slow(2)`;
export const callcenterhero = `()=>{
const bpm = 90;
const lead = polysynth().set({...osc('sine4'),...adsr(.004)}).chain(vol(0.15),out())
@ -489,31 +483,44 @@ export const wavyKalimba = `sampler({
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
.fast(1)
})`;
export const jemblung = `() => {
const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
return stack(
stack(
"0 1 4 [3!2 5]".edit(
// chords
x=>x.add("0,3").duration("0.05!3 0.02"),
// bass
x=>x.add("-8").struct("x*8").duration(0.1)
),
// melody
"12 11*3 12 ~".duration(0.005)
)
.add("<0 1>")
.tune("jemblung2")
//.mul(22/5).round().xen("22edo")
//.mul(12/5).round().xen("12edo")
.tone(s),
// kick
"[c2 ~]*2".duration(0.05).tone(membrane().chain(out())),
// snare
"[~ c1]*2".early(0.001).tone(snare),
// hihat
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
).slow(3)
}`;
export const jemblung = `const delay = new FeedbackDelay(1/8, .6).chain(vol(0.15), out());
const snare = noise({type:'white',...adsr(0,0.2,0)}).chain(lowpass(5000),vol(1.8),out());
const s = polysynth().set({...osc('sawtooth4'),...adsr(0.01,.2,.6,0.2)}).chain(vol(.23).connect(delay),out());
stack(
stack(
"0 1 4 [3!2 5]".edit(
// chords
x=>x.add("0,3").duration("0.05!3 0.02"),
// bass
x=>x.add("-8").struct("x*8").duration(0.1)
),
// melody
"12 11*3 12 ~".duration(0.005)
)
.add("<0 1>")
.tune("jemblung2")
//.mul(22/5).round().xen("22edo")
//.mul(12/5).round().xen("12edo")
.tone(s),
// kick
"[c2 ~]*2".duration(0.05).tone(membrane().chain(out())),
// snare
"[~ c1]*2".early(0.001).tone(snare),
// hihat
"c2*8".tone(noise().chain(highpass(6000),vol(0.5).connect(delay),out())),
).slow(3)`;
export const risingEnemy = `piano().then((p) =>
stack(
"2,6"
.scale('F3 dorian')
.transpose(sine2.struct("x*64").slow(4).mul(2).round())
.fast(2)
.struct("x x*3")
.legato(".9 .3"),
"0@3 -3*3".legato(".95@3 .4").scale('F2 dorian')
)
.transpose("<0 1 2 1>/2".early(0.5))
.transpose(5)
.fast(2 / 3)
.tone(p.toDestination())
)`;

36
docs/dist/ui.js vendored Normal file
View file

@ -0,0 +1,36 @@
import * as Tone from "../_snowpack/pkg/tone.js";
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));
}));
};