Merge pull request #61 from tidalcycles/more-functions

More functions
This commit is contained in:
Alex McLean 2022-04-13 16:26:45 +01:00 committed by GitHub
commit 0396c3f475
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 191 additions and 158 deletions

View File

@ -1,16 +1,16 @@
{
"files": {
"main.css": "/static/css/main.0d689283.css",
"main.js": "/static/js/main.77e38ada.js",
"static/js/787.8f7ec9e0.chunk.js": "/static/js/787.8f7ec9e0.chunk.js",
"main.js": "/static/js/main.194ee673.js",
"static/js/787.1c52cb78.chunk.js": "/static/js/787.1c52cb78.chunk.js",
"static/media/logo.svg": "/static/media/logo.ac95051720b3dccfe511e0e02d8e1029.svg",
"index.html": "/index.html",
"main.0d689283.css.map": "/static/css/main.0d689283.css.map",
"main.77e38ada.js.map": "/static/js/main.77e38ada.js.map",
"787.8f7ec9e0.chunk.js.map": "/static/js/787.8f7ec9e0.chunk.js.map"
"main.194ee673.js.map": "/static/js/main.194ee673.js.map",
"787.1c52cb78.chunk.js.map": "/static/js/787.1c52cb78.chunk.js.map"
},
"entrypoints": [
"static/css/main.0d689283.css",
"static/js/main.77e38ada.js"
"static/js/main.194ee673.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Strudel REPL"/><title>Strudel REPL</title><script defer="defer" src="/static/js/main.77e38ada.js"></script><link href="/static/css/main.0d689283.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Strudel REPL"/><title>Strudel REPL</title><script defer="defer" src="/static/js/main.194ee673.js"></script><link href="/static/css/main.0d689283.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

2
docs/static/js/787.1c52cb78.chunk.js vendored Normal file
View File

@ -0,0 +1,2 @@
"use strict";(self.webpackChunk_strudel_cycles_repl=self.webpackChunk_strudel_cycles_repl||[]).push([[787],{787:function(e,t,n){n.r(t),n.d(t,{getCLS:function(){return y},getFCP:function(){return g},getFID:function(){return C},getLCP:function(){return P},getTTFB:function(){return D}});var i,r,a,o,u=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},f=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},s=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},m=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},v=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},d=function(){f((function(e){var t=e.timeStamp;v=t}),!0)},l=function(){return v<0&&(v=p(),d(),s((function(){setTimeout((function(){v=p(),d()}),0)}))),{get firstHiddenTime(){return v}}},g=function(e,t){var n,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime<i.firstHiddenTime&&(r.value=e.startTime,r.entries.push(e),n(!0)))},o=window.performance&&performance.getEntriesByName&&performance.getEntriesByName("first-contentful-paint")[0],f=o?null:c("paint",a);(o||f)&&(n=m(e,r,t),o&&a(o),s((function(i){r=u("FCP"),n=m(e,r,t),requestAnimationFrame((function(){requestAnimationFrame((function(){r.value=performance.now()-i.timeStamp,n(!0)}))}))})))},h=!1,T=-1,y=function(e,t){h||(g((function(e){T=e.value})),h=!0);var n,i=function(t){T>-1&&e(t)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var t=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,n())}},p=c("layout-shift",v);p&&(n=m(i,r,t),f((function(){p.takeRecords().map(v),n(!0)})),s((function(){a=0,T=-1,r=u("CLS",0),n=m(i,r,t)})))},E={passive:!0,capture:!0},w=new Date,L=function(e,t){i||(i=t,r=e,a=new Date,F(removeEventListener),S())},S=function(){if(r>=0&&r<a-w){var e={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+r};o.forEach((function(t){t(e)})),o=[]}},b=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){L(e,t),r()},i=function(){r()},r=function(){removeEventListener("pointerup",n,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",n,E),addEventListener("pointercancel",i,E)}(t,e):L(t,e)}},F=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,b,E)}))},C=function(e,t){var n,a=l(),v=u("FID"),p=function(e){e.startTime<a.firstHiddenTime&&(v.value=e.processingStart-e.startTime,v.entries.push(e),n(!0))},d=c("first-input",p);n=m(e,v,t),d&&f((function(){d.takeRecords().map(p),d.disconnect()}),!0),d&&s((function(){var a;v=u("FID"),n=m(e,v,t),o=[],r=-1,i=null,F(addEventListener),a=p,o.push(a),S()}))},k={},P=function(e,t){var n,i=l(),r=u("LCP"),a=function(e){var t=e.startTime;t<i.firstHiddenTime&&(r.value=t,r.entries.push(e),n())},o=c("largest-contentful-paint",a);if(o){n=m(e,r,t);var v=function(){k[r.id]||(o.takeRecords().map(a),o.disconnect(),k[r.id]=!0,n(!0))};["keydown","click"].forEach((function(e){addEventListener(e,v,{once:!0,capture:!0})})),f(v,!0),s((function(i){r=u("LCP"),n=m(e,r,t),requestAnimationFrame((function(){requestAnimationFrame((function(){r.value=performance.now()-i.timeStamp,k[r.id]=!0,n(!0)}))}))}))}},D=function(e){var t,n=u("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(n.value=n.delta=t.responseStart,n.value<0||n.value>performance.now())return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("load",(function(){return setTimeout(t,0)}))}}}]);
//# sourceMappingURL=787.1c52cb78.chunk.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
"use strict";(self.webpackChunk_strudel_repl=self.webpackChunk_strudel_repl||[]).push([[787],{787:function(e,t,n){n.r(t),n.d(t,{getCLS:function(){return y},getFCP:function(){return g},getFID:function(){return C},getLCP:function(){return P},getTTFB:function(){return D}});var i,r,a,o,u=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},f=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},s=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},m=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},v=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},d=function(){f((function(e){var t=e.timeStamp;v=t}),!0)},l=function(){return v<0&&(v=p(),d(),s((function(){setTimeout((function(){v=p(),d()}),0)}))),{get firstHiddenTime(){return v}}},g=function(e,t){var n,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime<i.firstHiddenTime&&(r.value=e.startTime,r.entries.push(e),n(!0)))},o=window.performance&&performance.getEntriesByName&&performance.getEntriesByName("first-contentful-paint")[0],f=o?null:c("paint",a);(o||f)&&(n=m(e,r,t),o&&a(o),s((function(i){r=u("FCP"),n=m(e,r,t),requestAnimationFrame((function(){requestAnimationFrame((function(){r.value=performance.now()-i.timeStamp,n(!0)}))}))})))},h=!1,T=-1,y=function(e,t){h||(g((function(e){T=e.value})),h=!0);var n,i=function(t){T>-1&&e(t)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var t=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,n())}},p=c("layout-shift",v);p&&(n=m(i,r,t),f((function(){p.takeRecords().map(v),n(!0)})),s((function(){a=0,T=-1,r=u("CLS",0),n=m(i,r,t)})))},E={passive:!0,capture:!0},w=new Date,L=function(e,t){i||(i=t,r=e,a=new Date,F(removeEventListener),S())},S=function(){if(r>=0&&r<a-w){var e={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+r};o.forEach((function(t){t(e)})),o=[]}},b=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){L(e,t),r()},i=function(){r()},r=function(){removeEventListener("pointerup",n,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",n,E),addEventListener("pointercancel",i,E)}(t,e):L(t,e)}},F=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,b,E)}))},C=function(e,t){var n,a=l(),v=u("FID"),p=function(e){e.startTime<a.firstHiddenTime&&(v.value=e.processingStart-e.startTime,v.entries.push(e),n(!0))},d=c("first-input",p);n=m(e,v,t),d&&f((function(){d.takeRecords().map(p),d.disconnect()}),!0),d&&s((function(){var a;v=u("FID"),n=m(e,v,t),o=[],r=-1,i=null,F(addEventListener),a=p,o.push(a),S()}))},k={},P=function(e,t){var n,i=l(),r=u("LCP"),a=function(e){var t=e.startTime;t<i.firstHiddenTime&&(r.value=t,r.entries.push(e),n())},o=c("largest-contentful-paint",a);if(o){n=m(e,r,t);var v=function(){k[r.id]||(o.takeRecords().map(a),o.disconnect(),k[r.id]=!0,n(!0))};["keydown","click"].forEach((function(e){addEventListener(e,v,{once:!0,capture:!0})})),f(v,!0),s((function(i){r=u("LCP"),n=m(e,r,t),requestAnimationFrame((function(){requestAnimationFrame((function(){r.value=performance.now()-i.timeStamp,k[r.id]=!0,n(!0)}))}))}))}},D=function(e){var t,n=u("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(n.value=n.delta=t.responseStart,n.value<0||n.value>performance.now())return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("load",(function(){return setTimeout(t,0)}))}}}]);
//# sourceMappingURL=787.8f7ec9e0.chunk.js.map

3
docs/static/js/main.194ee673.js vendored Normal file

File diff suppressed because one or more lines are too long

1
docs/static/js/main.194ee673.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><link rel="icon" href="/tutorial/favicon.e3ab9dd9.ico"><link rel="stylesheet" type="text/css" href="/tutorial/index.999678aa.css"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Strudel REPL"><title>Strudel Tutorial</title></head><body> <div id="root"></div> <noscript>You need to enable JavaScript to run this app.</noscript> <script src="/tutorial/index.097d520a.js" defer></script> </body></html>
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><link rel="icon" href="/tutorial/favicon.e3ab9dd9.ico"><link rel="stylesheet" type="text/css" href="/tutorial/index.757e9f9d.css"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Strudel REPL"><title>Strudel Tutorial</title></head><body> <div id="root"></div> <noscript>You need to enable JavaScript to run this app.</noscript> <script src="/tutorial/index.3b5f65fb.js" defer></script> </body></html>

View File

@ -39,14 +39,24 @@ class TimeSpan {
}
withTime(func_time) {
// Applies given function to both the begin and end time value of the timespan"""
// Applies given function to both the begin and end time of the timespan"""
return new TimeSpan(func_time(this.begin), func_time(this.end));
}
withEnd(func_time) {
// Applies given function to both the begin and end time value of the timespan"""
// Applies given function to the end time of the timespan"""
return new TimeSpan(this.begin, func_time(this.end));
}
withCycle(func_time) {
// Like withTime, but time is relative to relative to the cycle (i.e. the
// sam of the start of the timespan)
const sam = this.begin.sam();
const b = sam.add(func_time(this.begin.sub(sam)));
const e = sam.add(func_time(this.end.sub(sam)));
return new TimeSpan(b, e);
}
intersection(other) {
// Intersection of two timespans, returns None if they don't intersect.
const intersect_begin = this.begin.max(other.begin);
@ -496,14 +506,14 @@ class Pattern {
// Assumes source pattern of numbers in range 0..1
range(min, max) {
return this.mul(max-min).add(min);
return this.mul(max - min).add(min);
}
// Assumes source pattern of numbers in range -1..1
range2(min, max) {
return _fromBipolar(this).range(min,max);
return _fromBipolar(this).range(min, max);
}
union(other) {
return this._opleft(other, (a) => (b) => Object.assign({}, a, b));
}
@ -647,15 +657,17 @@ class Pattern {
return this.withQuerySpan(qf).withEventSpan(ef)._splitQueries();
}
_compressSpan(span) {
const b = span.begin;
const e = span.end;
_compress(b, e) {
if (b > e || b > 1 || e > 1 || b < 0 || e < 0) {
return silence;
}
return this._fastGap(Fraction(1).div(e.sub(b)))._late(b);
}
_compressSpan(span) {
return this._compress(span.begin, span.end);
}
_fast(factor) {
const fastQuery = this.withQueryTime((t) => t.mul(factor));
return fastQuery.withEventTime((t) => t.div(factor));
@ -695,6 +707,28 @@ class Pattern {
return this._early(Fraction(0).sub(offset));
}
_zoom(s, e) {
e = Fraction(e)
s = Fraction(s)
const d = e.sub(s);
return this.withQuerySpan((span) => span.withCycle((t) => t.mul(d).add(s)))
.withEventSpan((span) => span.withCycle((t) => t.sub(s).div(d)))
._splitQueries();
}
_zoomArc(a) {
return this.zoom(a.begin, a.end);
}
_linger(t) {
if (t == 0) {
return silence;
} else if (t < 0) {
return this._zoom(t.add(1), 1)._slow(t);
}
return this._zoom(0, t)._slow(t);
}
struct(...binary_pats) {
// Re structure the pattern according to a binary pattern (false values are dropped)
const binary_pat = sequence(binary_pats);
@ -876,19 +910,20 @@ class Pattern {
// methods of Pattern that get callable factories
Pattern.prototype.patternified = [
'apply',
'fast',
'slow',
'ply',
'chop',
'cpm',
'early',
'late',
'duration',
'legato',
'velocity',
'segment',
'color',
'jux'
'cpm',
'duration',
'early',
'fast',
'jux',
'late',
'legato',
'linger',
'ply',
'segment',
'slow',
'velocity',
];
// methods that create patterns, which are added to patternified Pattern methods
Pattern.prototype.factories = { pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr };
@ -1008,7 +1043,7 @@ function timeCat(...timepats) {
const pats = [];
for (const [time, pat] of timepats) {
const end = begin.add(time);
pats.push(reify(pat)._compressSpan(new TimeSpan(begin.div(total), end.div(total))));
pats.push(reify(pat)._compress(begin.div(total), end.div(total)));
begin = end;
}
return stack(...pats);
@ -1076,35 +1111,36 @@ function pr(args) {
polyrhythm(args);
}
const fast = curry((a, pat) => pat.fast(a));
const slow = curry((a, pat) => pat.slow(a));
const early = curry((a, pat) => pat.early(a));
const late = curry((a, pat) => pat.late(a));
const rev = (pat) => pat.rev();
const add = curry((a, pat) => pat.add(a));
const sub = curry((a, pat) => pat.sub(a));
const mul = curry((a, pat) => pat.mul(a));
const div = curry((a, pat) => pat.div(a));
const union = curry((a, pat) => pat.union(a));
const range = curry((a, b, pat) => pat.range(a,b));
const range2 = curry((a, b, pat) => pat.range2(a,b));
const every = curry((i, f, pat) => pat.every(i, f));
const when = curry((binary, f, pat) => pat.when(binary, f));
const off = curry((t, f, pat) => pat.off(t, f));
const jux = curry((f, pat) => pat.jux(f));
const juxBy = curry((by, f, pat) => pat.juxBy(by, f));
const append = curry((a, pat) => pat.append(a));
const superimpose = curry((array, pat) => pat.superimpose(...array));
const struct = curry((a, pat) => pat.struct(a));
const mask = curry((a, pat) => pat.mask(a));
const echo = curry((a, b, c, pat) => pat.echo(a, b, c));
const invert = (pat) => pat.invert();
const inv = (pat) => pat.inv();
const iter = curry((a, pat) => pat.iter(a));
const iterBack = curry((a, pat) => pat.iter(a));
const chunk = curry((a, pat) => pat.chunk(a));
const chunkBack = curry((a, pat) => pat.chunkBack(a));
const div = curry((a, pat) => pat.div(a));
const early = curry((a, pat) => pat.early(a));
const echo = curry((a, b, c, pat) => pat.echo(a, b, c));
const every = curry((i, f, pat) => pat.every(i, f));
const fast = curry((a, pat) => pat.fast(a));
const inv = (pat) => pat.inv();
const invert = (pat) => pat.invert();
const iter = curry((a, pat) => pat.iter(a));
const iterBack = curry((a, pat) => pat.iter(a));
const jux = curry((f, pat) => pat.jux(f));
const juxBy = curry((by, f, pat) => pat.juxBy(by, f));
const late = curry((a, pat) => pat.late(a));
const linger = curry((a, pat) => pat.linger(a));
const mask = curry((a, pat) => pat.mask(a));
const mul = curry((a, pat) => pat.mul(a));
const off = curry((t, f, pat) => pat.off(t, f));
const ply = curry((a, pat) => pat.ply(a));
const range = curry((a, b, pat) => pat.range(a, b));
const range2 = curry((a, b, pat) => pat.range2(a, b));
const rev = (pat) => pat.rev();
const slow = curry((a, pat) => pat.slow(a));
const struct = curry((a, pat) => pat.struct(a));
const sub = curry((a, pat) => pat.sub(a));
const superimpose = curry((array, pat) => pat.superimpose(...array));
const union = curry((a, pat) => pat.union(a));
const when = curry((binary, f, pat) => pat.when(binary, f));
// problem: curried functions with spread arguments must have pat at the beginning
// with this, we cannot keep the pattern open at the end.. solution for now: use array to keep using pat as last arg
@ -1163,6 +1199,14 @@ Pattern.prototype.chunkBack = function (...args) {
args = args.map(reify);
return patternify2(Pattern.prototype._chunkBack)(...args, this);
};
Pattern.prototype.zoom = function (...args) {
args = args.map(reify);
return patternify2(Pattern.prototype._zoom)(...args, this);
}
Pattern.prototype.compress = function (...args) {
args = args.map(reify);
return patternify2(Pattern.prototype._compress)(...args, this);
}
// call this after all Patter.prototype.define calls have been executed! (right before evaluate)
Pattern.prototype.bootstrap = function () {
@ -1240,6 +1284,7 @@ export {
jux,
juxBy,
late,
linger,
mask,
mul,
off,

View File

@ -1,6 +1,6 @@
import Fraction from 'fraction.js';
import { strict as assert } from 'assert';
import { deepStrictEqual, strict as assert } from 'assert';
import {
TimeSpan,
@ -656,4 +656,12 @@ describe('Pattern', function () {
);
});
});
describe('linger', () => {
it('Can linger on the first quarter of a cycle', () => {
assert.deepStrictEqual(
sequence(0, 1, 2, 3, 4, 5, 6, 7).linger(0.25).firstCycle(),
sequence(0, 1, 0, 1, 0, 1, 0, 1).firstCycle(),
);
});
});
});