Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More functions #61

Merged
merged 6 commits into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
@@ -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>
2 changes: 1 addition & 1 deletion docs/static/css/main.0d689283.css.map

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/static/js/787.1c52cb78.chunk.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions docs/static/js/787.8f7ec9e0.chunk.js

This file was deleted.

3 changes: 3 additions & 0 deletions docs/static/js/main.194ee673.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/static/js/main.194ee673.js.map

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions docs/static/js/main.77e38ada.js

This file was deleted.

1 change: 0 additions & 1 deletion docs/static/js/main.77e38ada.js.map

This file was deleted.

95 changes: 0 additions & 95 deletions docs/tutorial/index.097d520a.js

This file was deleted.

1 change: 0 additions & 1 deletion docs/tutorial/index.097d520a.js.map

This file was deleted.

75 changes: 75 additions & 0 deletions docs/tutorial/index.3b5f65fb.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/tutorial/index.3b5f65fb.js.map

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/tutorial/index.html
Original file line number Diff line number Diff line change
@@ -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>
121 changes: 83 additions & 38 deletions packages/core/strudel.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -876,19 +910,20 @@ class Pattern {
// methods of Pattern that get callable factories
Pattern.prototype.patternified = [
'apply',
'fast',
'slow',
'ply',
'chop',
'color',
'cpm',
'duration',
'early',
'fast',
'jux',
'late',
'duration',
'legato',
'velocity',
'linger',
'ply',
'segment',
'color',
'jux'
'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 };
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 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 invert = (pat) => pat.invert();
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 chunk = curry((a, pat) => pat.chunk(a));
const chunkBack = curry((a, pat) => pat.chunkBack(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
Expand Down Expand Up @@ -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 () {
Expand Down Expand Up @@ -1240,6 +1284,7 @@ export {
jux,
juxBy,
late,
linger,
mask,
mul,
off,
Expand Down
10 changes: 9 additions & 1 deletion packages/core/test/pattern.test.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Fraction from 'fraction.js';

import { strict as assert } from 'assert';
import { deepStrictEqual, strict as assert } from 'assert';

import {
TimeSpan,
Expand Down Expand Up @@ -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(),
);
});
});
});