This commit is contained in:
Felix Roos 2022-02-05 20:38:24 +01:00
parent 9d20c62106
commit 7fc10552f6
4 changed files with 43 additions and 32 deletions

View File

@ -297,12 +297,12 @@ class Pattern {
return stack(this, func(this.early(time_pat))); return stack(this, func(this.early(time_pat)));
} }
every(n, func) { every(n, func) {
pats = Array(n - 1).fill(this); const pats = Array(n - 1).fill(this);
pats.unshift(this); pats.unshift(this);
return slowcat(pats); return slowcat(...pats);
} }
append(other) { append(other) {
return fastcat([this, other]); return fastcat(...[this, other]);
} }
rev() { rev() {
var pat = this; var pat = this;
@ -349,29 +349,26 @@ function pure(value) {
function steady(value) { function steady(value) {
return new Pattern((span) => Hap(void 0, span, value)); return new Pattern((span) => Hap(void 0, span, value));
} }
function stack(pats2) { function stack(...pats) {
var pats2 = pats2.map(reify); pats = pats.map(reify);
var query2 = function(span) { var query2 = function(span) {
return flatten(pats2.map((pat) => pat.query(span))); return flatten(pats.map((pat) => pat.query(span)));
}; };
return new Pattern(query2); return new Pattern(query2);
} }
function slowcat(pats2) { function slowcat(...pats) {
pats = pats.map(reify);
var query2 = function(span) { var query2 = function(span) {
var pat = pats2[Math.floor(span.begin) % pats2.length]; var pat = pats[Math.floor(span.begin) % pats.length];
return pat.query(span); return pat.query(span);
}; };
return new Pattern(query2)._splitQueries(); return new Pattern(query2)._splitQueries();
} }
function slow(...pats2) { function fastcat(...pats) {
pats2 = pats2.map((pat) => reify(pat)); return slowcat(...pats)._fast(pats.length);
return slowcat(pats2);
} }
function fastcat(pats2) { function cat(...pats) {
return slowcat(pats2)._fast(pats2.length); return fastcat(...pats);
}
function cat(pats2) {
return fastcat(pats2);
} }
function _sequenceCount(x) { function _sequenceCount(x) {
if (Array.isArray(x)) { if (Array.isArray(x)) {
@ -381,7 +378,7 @@ function _sequenceCount(x) {
if (x.length == 1) { if (x.length == 1) {
return _sequenceCount(x[0]); return _sequenceCount(x[0]);
} }
return [fastcat(x.map((a) => _sequenceCount(a)[0])), x.length]; return [fastcat(...x.map((a) => _sequenceCount(a)[0])), x.length];
} }
return [reify(x), 1]; return [reify(x), 1];
} }
@ -396,18 +393,18 @@ function polymeter(steps = 0, ...args) {
if (steps == 0) { if (steps == 0) {
steps = seqs[0][1]; steps = seqs[0][1];
} }
var pats2 = []; var pats = [];
for (var seq of seqs) { for (var seq of seqs) {
if (seq[1] == 0) { if (seq[1] == 0) {
next; next;
} }
if (steps == seq[1]) { if (steps == seq[1]) {
pats2.push(seq[0]); pats.push(seq[0]);
} else { } else {
pats2.push(seq[0]._fast(Fraction(steps).div(Fraction(seq[1])))); pats.push(seq[0]._fast(Fraction(steps).div(Fraction(seq[1]))));
} }
} }
return stack(pats2); return stack(pats);
} }
function silence() { function silence() {
return new Pattern((_) => []); return new Pattern((_) => []);
@ -418,11 +415,12 @@ export {
Hap, Hap,
Pattern, Pattern,
pure, pure,
reify,
stack, stack,
slowcat, slowcat,
slow,
fastcat, fastcat,
cat, cat,
sequence, sequence,
polymeter polymeter,
silence
}; };

19
docs/dist/App.js vendored
View File

@ -8,12 +8,23 @@ const {Fraction, TimeSpan} = strudel;
const fr = (v) => new Fraction(v); const fr = (v) => new Fraction(v);
const ts = (start, end) => new TimeSpan(fr(start), fr(end)); const ts = (start, end) => new TimeSpan(fr(start), fr(end));
const parse = (code) => { const parse = (code) => {
const {sequence, stack, pure, slowcat, slow} = strudel; const {sequence, pure, reify, slowcat, fastcat, cat, stack, silence} = strudel;
return eval(code); return eval(code);
}; };
const synth = new Tone.Synth().toDestination(); const synth = new Tone.PolySynth().toDestination();
synth.set({
oscillator: {type: "triangle"},
envelope: {
release: 0.01
}
});
function App() { function App() {
const [code, setCode] = useState("slow(sequence('c3', 'eb3', sequence('g3', 'f3')), 'g3')"); const [code, setCode] = useState(`slowcat(
stack('c4','eb4','g4'),
stack('bb3','d4','f4'),
stack('ab3','c4','eb4'),
stack('g3','b3','d4')
)`);
const [log, setLog] = useState(""); const [log, setLog] = useState("");
const logBox = useRef(); const logBox = useRef();
const [error, setError] = useState(); const [error, setError] = useState();
@ -63,7 +74,7 @@ function App() {
}, /* @__PURE__ */ React.createElement("div", { }, /* @__PURE__ */ React.createElement("div", {
className: "absolute right-2 bottom-2 text-red-500" className: "absolute right-2 bottom-2 text-red-500"
}, error?.message), /* @__PURE__ */ React.createElement("textarea", { }, error?.message), /* @__PURE__ */ React.createElement("textarea", {
className: cx("w-full h-32 bg-slate-600", error ? "focus:ring-red-500" : "focus:ring-slate-800"), className: cx("w-full h-64 bg-slate-600", error ? "focus:ring-red-500" : "focus:ring-slate-800"),
value: code, value: code,
onChange: (e) => { onChange: (e) => {
setLog((log2) => log2 + `${log2 ? "\n\n" : ""}✏️ edit setLog((log2) => log2 + `${log2 ? "\n\n" : ""}✏️ edit

View File

@ -17,9 +17,14 @@ function useCycle(props) {
const cancelFrom = timespan.begin.valueOf(); const cancelFrom = timespan.begin.valueOf();
Tone.Transport.cancel(cancelFrom); Tone.Transport.cancel(cancelFrom);
const queryNextTime = (cycle + 1) * cycleDuration - 0.1; const queryNextTime = (cycle + 1) * cycleDuration - 0.1;
Tone.Transport.schedule(() => { const delta = queryNextTime - Tone.Transport.seconds;
if (delta < 0.2) {
query(cycle + 1); query(cycle + 1);
}, queryNextTime); } else {
Tone.Transport.schedule(() => {
query(cycle + 1);
}, queryNextTime);
}
events?.forEach((event) => { events?.forEach((event) => {
Tone.Transport.schedule((time) => { Tone.Transport.schedule((time) => {
const toneEvent = { const toneEvent = {

View File

@ -611,9 +611,6 @@ select {
.h-16 { .h-16 {
height: 4rem; height: 4rem;
} }
.h-32 {
height: 8rem;
}
.h-64 { .h-64 {
height: 16rem; height: 16rem;
} }