This commit is contained in:
Felix Roos 2022-03-19 19:30:29 +01:00
parent aec5b3bb2b
commit 3c56f24eed
7 changed files with 681 additions and 2169 deletions

View file

@ -1,908 +1,45 @@
/** import Fraction from "../pkg/fractionjs.js";
* @license Fraction.js v4.1.2 23/05/2021 import {TimeSpan} from "./strudel.js";
* https://www.xarg.org/2014/03/rational-numbers-in-javascript/ Fraction.prototype.sam = function() {
* return this.floor();
* Copyright (c) 2021, Robert Eisele (robert@xarg.org)
* Dual licensed under the MIT or GPL Version 2 licenses.
**/
/**
*
* This class offers the possibility to calculate fractions.
* You can pass a fraction in different formats. Either as array, as double, as string or as an integer.
*
* Array/Object form
* [ 0 => <nominator>, 1 => <denominator> ]
* [ n => <nominator>, d => <denominator> ]
*
* Integer form
* - Single integer value
*
* Double form
* - Single double value
*
* String form
* 123.456 - a simple double
* 123/456 - a string fraction
* 123.'456' - a double with repeating decimal places
* 123.(456) - synonym
* 123.45'6' - a double with repeating last place
* 123.45(6) - synonym
*
* Example:
*
* var f = new Fraction("9.4'31'");
* f.mul([-4, 3]).div(4.9);
*
*/
const memo = {};
let root = {};
"use strict";
// Maximum search depth for cyclic rational numbers. 2000 should be more than enough.
// Example: 1/7 = 0.(142857) has 6 repeating decimal places.
// If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits
var MAX_CYCLE_LEN = 2000;
// Parsed data to avoid calling "new" all the time
var P = {
"s": 1,
"n": 0,
"d": 1
}; };
Fraction.prototype.nextSam = function() {
function createError(name) { return this.sam().add(1);
function errorConstructor() {
var temp = Error.apply(this, arguments);
temp['name'] = this['name'] = name;
this['stack'] = temp['stack'];
this['message'] = temp['message'];
}
/**
* Error constructor
*
* @constructor
*/
function IntermediateInheritor() { }
IntermediateInheritor.prototype = Error.prototype;
errorConstructor.prototype = new IntermediateInheritor();
return errorConstructor;
}
var DivisionByZero = Fraction['DivisionByZero'] = createError('DivisionByZero');
var InvalidParameter = Fraction['InvalidParameter'] = createError('InvalidParameter');
function assign(n, s) {
if (isNaN(n = parseInt(n, 10))) {
throwInvalidParam();
}
return n * s;
}
function throwInvalidParam() {
throw new InvalidParameter();
}
function factorize(num) {
var factors = {};
var n = num;
var i = 2;
var s = 4;
while (s <= n) {
while (n % i === 0) {
n /= i;
factors[i] = (factors[i] || 0) + 1;
}
s += 1 + 2 * i++;
}
if (n !== num) {
if (n > 1)
factors[n] = (factors[n] || 0) + 1;
} else {
factors[num] = (factors[num] || 0) + 1;
}
return factors;
}
var parse = function(p1, p2) {
var n = 0, d = 1, s = 1;
var v = 0, w = 0, x = 0, y = 1, z = 1;
var A = 0, B = 1;
var C = 1, D = 1;
var N = 10000000;
var M;
if (p1 === undefined || p1 === null) {
/* void */
} else if (p2 !== undefined) {
n = p1;
d = p2;
s = n * d;
} else
switch (typeof p1) {
case "object":
{
if ("d" in p1 && "n" in p1) {
n = p1["n"];
d = p1["d"];
if ("s" in p1)
n *= p1["s"];
} else if (0 in p1) {
n = p1[0];
if (1 in p1)
d = p1[1];
} else {
throwInvalidParam();
}
s = n * d;
break;
}
case "number":
{
if (p1 < 0) {
s = p1;
p1 = -p1;
}
if (p1 % 1 === 0) {
n = p1;
} else if (p1 > 0) { // check for != 0, scale would become NaN (log(0)), which converges really slow
if (p1 >= 1) {
z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10));
p1 /= z;
}
const key = p1+'#'+p2
const memoized = memo[key]
if(memoized) {
s = memoized.s;
n = memoized.n;
d = memoized.d;
break;
}
// Using Farey Sequences
// http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/
while (B <= N && D <= N) {
M = (A + C) / (B + D);
if (p1 === M) {
if (B + D <= N) {
n = A + C;
d = B + D;
} else if (D > B) {
n = C;
d = D;
} else {
n = A;
d = B;
}
break;
} else {
if (p1 > M) {
A += C;
B += D;
} else {
C += A;
D += B;
}
if (B > N) {
n = C;
d = D;
} else {
n = A;
d = B;
}
}
}
n *= z;
} else if (isNaN(p1) || isNaN(p2)) {
d = n = NaN;
}
break;
}
case "string":
{
B = p1.match(/\d+|./g);
if (B === null)
throwInvalidParam();
if (B[A] === '-') {// Check for minus sign at the beginning
s = -1;
A++;
} else if (B[A] === '+') {// Check for plus sign at the beginning
A++;
}
if (B.length === A + 1) { // Check if it's just a simple number "1234"
w = assign(B[A++], s);
} else if (B[A + 1] === '.' || B[A] === '.') { // Check if it's a decimal number
if (B[A] !== '.') { // Handle 0.5 and .5
v = assign(B[A++], s);
}
A++;
// Check for decimal places
if (A + 1 === B.length || B[A + 1] === '(' && B[A + 3] === ')' || B[A + 1] === "'" && B[A + 3] === "'") {
w = assign(B[A], s);
y = Math.pow(10, B[A].length);
A++;
}
// Check for repeating places
if (B[A] === '(' && B[A + 2] === ')' || B[A] === "'" && B[A + 2] === "'") {
x = assign(B[A + 1], s);
z = Math.pow(10, B[A + 1].length) - 1;
A += 3;
}
} else if (B[A + 1] === '/' || B[A + 1] === ':') { // Check for a simple fraction "123/456" or "123:456"
w = assign(B[A], s);
y = assign(B[A + 2], 1);
A += 3;
} else if (B[A + 3] === '/' && B[A + 1] === ' ') { // Check for a complex fraction "123 1/2"
v = assign(B[A], s);
w = assign(B[A + 2], s);
y = assign(B[A + 4], 1);
A += 5;
}
if (B.length <= A) { // Check for more tokens on the stack
d = y * z;
s = /* void */
n = x + d * v + z * w;
break;
}
/* Fall through on error */
}
default:
throwInvalidParam();
}
if (d === 0) {
throw new DivisionByZero();
}
P["s"] = s < 0 ? -1 : 1;
P["n"] = Math.abs(n);
P["d"] = Math.abs(d);
memo[p1+'#'+p2] = {s:P["s"],n:P["n"],d:P["d"]};
}; };
Fraction.prototype.wholeCycle = function() {
function modpow(b, e, m) { return new TimeSpan(this.sam(), this.nextSam());
var r = 1;
for (; e > 0; b = (b * b) % m, e >>= 1) {
if (e & 1) {
r = (r * b) % m;
}
}
return r;
}
function cycleLen(n, d) {
for (; d % 2 === 0;
d /= 2) {
}
for (; d % 5 === 0;
d /= 5) {
}
if (d === 1) // Catch non-cyclic numbers
return 0;
// If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem:
// 10^(d-1) % d == 1
// However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone,
// as we want to translate the numbers to strings.
var rem = 10 % d;
var t = 1;
for (; rem !== 1; t++) {
rem = rem * 10 % d;
if (t > MAX_CYCLE_LEN)
return 0; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1`
}
return t;
}
function cycleStart(n, d, len) {
var rem1 = 1;
var rem2 = modpow(10, len, d);
for (var t = 0; t < 300; t++) { // s < ~log10(Number.MAX_VALUE)
// Solve 10^s == 10^(s+t) (mod d)
if (rem1 === rem2)
return t;
rem1 = rem1 * 10 % d;
rem2 = rem2 * 10 % d;
}
return 0;
}
function gcd(a, b) {
if (!a)
return b;
if (!b)
return a;
while (1) {
a %= b;
if (!a)
return b;
b %= a;
if (!b)
return a;
}
}; };
Fraction.prototype.lt = function(other) {
/** return this.compare(other) < 0;
* Module constructor
*
* @constructor
* @param {number|Fraction=} a
* @param {number=} b
*/
function Fraction(a, b) {
if (!(this instanceof Fraction)) {
return new Fraction(a, b);
}
parse(a, b);
a = gcd(P["d"], P["n"]); // Abuse variable a
this["s"] = P["s"];
this["n"] = P["n"] / a;
this["d"] = P["d"] / a;
}
Fraction.prototype = {
"s": 1,
"n": 0,
"d": 1,
/**
* Calculates the absolute value
*
* Ex: new Fraction(-4).abs() => 4
**/
"abs": function() {
return new Fraction(this["n"], this["d"]);
},
/**
* Inverts the sign of the current fraction
*
* Ex: new Fraction(-4).neg() => 4
**/
"neg": function() {
return new Fraction(-this["s"] * this["n"], this["d"]);
},
/**
* Adds two rational numbers
*
* Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30
**/
"add": function(a, b) {
parse(a, b);
return new Fraction(
this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"],
this["d"] * P["d"]
);
},
/**
* Subtracts two rational numbers
*
* Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30
**/
"sub": function(a, b) {
parse(a, b);
return new Fraction(
this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"],
this["d"] * P["d"]
);
},
/**
* Multiplies two rational numbers
*
* Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111
**/
"mul": function(a, b) {
parse(a, b);
return new Fraction(
this["s"] * P["s"] * this["n"] * P["n"],
this["d"] * P["d"]
);
},
/**
* Divides two rational numbers
*
* Ex: new Fraction("-17.(345)").inverse().div(3)
**/
"div": function(a, b) {
parse(a, b);
return new Fraction(
this["s"] * P["s"] * this["n"] * P["d"],
this["d"] * P["n"]
);
},
/**
* Clones the actual object
*
* Ex: new Fraction("-17.(345)").clone()
**/
"clone": function() {
return new Fraction(this);
},
/**
* Calculates the modulo of two rational numbers - a more precise fmod
*
* Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6)
**/
"mod": function(a, b) {
if (isNaN(this['n']) || isNaN(this['d'])) {
return new Fraction(NaN);
}
if (a === undefined) {
return new Fraction(this["s"] * this["n"] % this["d"], 1);
}
parse(a, b);
if (0 === P["n"] && 0 === this["d"]) {
Fraction(0, 0); // Throw DivisionByZero
}
/*
* First silly attempt, kinda slow
*
return that["sub"]({
"n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)),
"d": num["d"],
"s": this["s"]
});*/
/*
* New attempt: a1 / b1 = a2 / b2 * q + r
* => b2 * a1 = a2 * b1 * q + b1 * b2 * r
* => (b2 * a1 % a2 * b1) / (b1 * b2)
*/
return new Fraction(
this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]),
P["d"] * this["d"]
);
},
/**
* Calculates the fractional gcd of two rational numbers
*
* Ex: new Fraction(5,8).gcd(3,7) => 1/56
*/
"gcd": function(a, b) {
parse(a, b);
// gcd(a / b, c / d) = gcd(a, c) / lcm(b, d)
return new Fraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]);
},
/**
* Calculates the fractional lcm of two rational numbers
*
* Ex: new Fraction(5,8).lcm(3,7) => 15
*/
"lcm": function(a, b) {
parse(a, b);
// lcm(a / b, c / d) = lcm(a, c) / gcd(b, d)
if (P["n"] === 0 && this["n"] === 0) {
return new Fraction;
}
return new Fraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]));
},
/**
* Calculates the ceil of a rational number
*
* Ex: new Fraction('4.(3)').ceil() => (5 / 1)
**/
"ceil": function(places) {
places = Math.pow(10, places || 0);
if (isNaN(this["n"]) || isNaN(this["d"])) {
return new Fraction(NaN);
}
return new Fraction(Math.ceil(places * this["s"] * this["n"] / this["d"]), places);
},
/**
* Calculates the floor of a rational number
*
* Ex: new Fraction('4.(3)').floor() => (4 / 1)
**/
"floor": function(places) {
places = Math.pow(10, places || 0);
if (isNaN(this["n"]) || isNaN(this["d"])) {
return new Fraction(NaN);
}
return new Fraction(Math.floor(places * this["s"] * this["n"] / this["d"]), places);
},
/**
* Rounds a rational numbers
*
* Ex: new Fraction('4.(3)').round() => (4 / 1)
**/
"round": function(places) {
places = Math.pow(10, places || 0);
if (isNaN(this["n"]) || isNaN(this["d"])) {
return new Fraction(NaN);
}
return new Fraction(Math.round(places * this["s"] * this["n"] / this["d"]), places);
},
/**
* Gets the inverse of the fraction, means numerator and denominator are exchanged
*
* Ex: new Fraction([-3, 4]).inverse() => -4 / 3
**/
"inverse": function() {
return new Fraction(this["s"] * this["d"], this["n"]);
},
/**
* Calculates the fraction to some rational exponent, if possible
*
* Ex: new Fraction(-1,2).pow(-3) => -8
*/
"pow": function(a, b) {
parse(a, b);
// Trivial case when exp is an integer
if (P['d'] === 1) {
if (P['s'] < 0) {
return new Fraction(Math.pow(this['s'] * this["d"], P['n']), Math.pow(this["n"], P['n']));
} else {
return new Fraction(Math.pow(this['s'] * this["n"], P['n']), Math.pow(this["d"], P['n']));
}
}
// Negative roots become complex
// (-a/b)^(c/d) = x
// <=> (-1)^(c/d) * (a/b)^(c/d) = x
// <=> (cos(pi) + i*sin(pi))^(c/d) * (a/b)^(c/d) = x # rotate 1 by 180°
// <=> (cos(c*pi/d) + i*sin(c*pi/d)) * (a/b)^(c/d) = x # DeMoivre's formula in Q ( https://proofwiki.org/wiki/De_Moivre%27s_Formula/Rational_Index )
// From which follows that only for c=0 the root is non-complex. c/d is a reduced fraction, so that sin(c/dpi)=0 occurs for d=1, which is handled by our trivial case.
if (this['s'] < 0) return null;
// Now prime factor n and d
var N = factorize(this['n']);
var D = factorize(this['d']);
// Exponentiate and take root for n and d individually
var n = 1;
var d = 1;
for (var k in N) {
if (k === '1') continue;
if (k === '0') {
n = 0;
break;
}
N[k]*= P['n'];
if (N[k] % P['d'] === 0) {
N[k]/= P['d'];
} else return null;
n*= Math.pow(k, N[k]);
}
for (var k in D) {
if (k === '1') continue;
D[k]*= P['n'];
if (D[k] % P['d'] === 0) {
D[k]/= P['d'];
} else return null;
d*= Math.pow(k, D[k]);
}
if (P['s'] < 0) {
return new Fraction(d, n);
}
return new Fraction(n, d);
},
/**
* Check if two rational numbers are the same
*
* Ex: new Fraction(19.6).equals([98, 5]);
**/
"equals": function(a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0
},
/**
* Check if two rational numbers are the same
*
* Ex: new Fraction(19.6).equals([98, 5]);
**/
"compare": function(a, b) {
parse(a, b);
var t = (this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"]);
return (0 < t) - (t < 0);
},
"simplify": function(eps) {
// First naive implementation, needs improvement
if (isNaN(this['n']) || isNaN(this['d'])) {
return this;
}
var cont = this['abs']()['toContinued']();
eps = eps || 0.001;
function rec(a) {
if (a.length === 1)
return new Fraction(a[0]);
return rec(a.slice(1))['inverse']()['add'](a[0]);
}
for (var i = 0; i < cont.length; i++) {
var tmp = rec(cont.slice(0, i + 1));
if (tmp['sub'](this['abs']())['abs']().valueOf() < eps) {
return tmp['mul'](this['s']);
}
}
return this;
},
/**
* Check if two rational numbers are divisible
*
* Ex: new Fraction(19.6).divisible(1.5);
*/
"divisible": function(a, b) {
parse(a, b);
return !(!(P["n"] * this["d"]) || ((this["n"] * P["d"]) % (P["n"] * this["d"])));
},
/**
* Returns a decimal representation of the fraction
*
* Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183
**/
'valueOf': function() {
return this["s"] * this["n"] / this["d"];
},
/**
* Returns a string-fraction representation of a Fraction object
*
* Ex: new Fraction("1.'3'").toFraction() => "4 1/3"
**/
'toFraction': function(excludeWhole) {
var whole, str = "";
var n = this["n"];
var d = this["d"];
if (this["s"] < 0) {
str += '-';
}
if (d === 1) {
str += n;
} else {
if (excludeWhole && (whole = Math.floor(n / d)) > 0) {
str += whole;
str += " ";
n %= d;
}
str += n;
str += '/';
str += d;
}
return str;
},
/**
* Returns a latex representation of a Fraction object
*
* Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}"
**/
'toLatex': function(excludeWhole) {
var whole, str = "";
var n = this["n"];
var d = this["d"];
if (this["s"] < 0) {
str += '-';
}
if (d === 1) {
str += n;
} else {
if (excludeWhole && (whole = Math.floor(n / d)) > 0) {
str += whole;
n %= d;
}
str += "\\frac{";
str += n;
str += '}{';
str += d;
str += '}';
}
return str;
},
/**
* Returns an array of continued fraction elements
*
* Ex: new Fraction("7/8").toContinued() => [0,1,7]
*/
'toContinued': function() {
var t;
var a = this['n'];
var b = this['d'];
var res = [];
if (isNaN(a) || isNaN(b)) {
return res;
}
do {
res.push(Math.floor(a / b));
t = a % b;
a = b;
b = t;
} while (a !== 1);
return res;
},
/**
* Creates a string representation of a fraction with all digits
*
* Ex: new Fraction("100.'91823'").toString() => "100.(91823)"
**/
'toString': function(dec) {
var g;
var N = this["n"];
var D = this["d"];
if (isNaN(N) || isNaN(D)) {
return "NaN";
}
dec = dec || 15; // 15 = decimal places when no repetation
var cycLen = cycleLen(N, D); // Cycle length
var cycOff = cycleStart(N, D, cycLen); // Cycle start
var str = this['s'] === -1 ? "-" : "";
str += N / D | 0;
N %= D;
N *= 10;
if (N)
str += ".";
if (cycLen) {
for (var i = cycOff; i--;) {
str += N / D | 0;
N %= D;
N *= 10;
}
str += "(";
for (var i = cycLen; i--;) {
str += N / D | 0;
N %= D;
N *= 10;
}
str += ")";
} else {
for (var i = dec; N && i--;) {
str += N / D | 0;
N %= D;
N *= 10;
}
}
return str;
}
}; };
Fraction.prototype.gt = function(other) {
if (typeof define === "function" && define["amd"]) { return this.compare(other) > 0;
define([], function() { };
return Fraction; Fraction.prototype.lte = function(other) {
}); return this.compare(other) <= 0;
} else if (typeof exports === "object") { };
Object.defineProperty(Fraction, "__esModule", { 'value': true }); Fraction.prototype.gte = function(other) {
Fraction['default'] = Fraction; return this.compare(other) >= 0;
Fraction['Fraction'] = Fraction; };
module['exports'] = Fraction; Fraction.prototype.eq = function(other) {
} else { return this.compare(other) == 0;
root['Fraction'] = Fraction; };
Fraction.prototype.max = function(other) {
return this.gt(other) ? this : other;
};
Fraction.prototype.min = function(other) {
return this.lt(other) ? this : other;
};
Fraction.prototype.show = function() {
return this.s * this.n + "/" + this.d;
};
Fraction.prototype.or = function(other) {
return this.eq(0) ? other : this;
};
const fraction = (n) => {
if (typeof n === "number") {
n = String(n);
} }
return Fraction(n);
};
export default Fraction; export default fraction;

View file

@ -23,42 +23,6 @@ export function curry(func, overload) {
} }
return fn; return fn;
} }
Fraction.prototype.sam = function() {
return this.floor();
};
Fraction.prototype.nextSam = function() {
return this.sam().add(1);
};
Fraction.prototype.wholeCycle = function() {
return new TimeSpan(this.sam(), this.nextSam());
};
Fraction.prototype.lt = function(other) {
return this.compare(other) < 0;
};
Fraction.prototype.gt = function(other) {
return this.compare(other) > 0;
};
Fraction.prototype.lte = function(other) {
return this.compare(other) <= 0;
};
Fraction.prototype.gte = function(other) {
return this.compare(other) >= 0;
};
Fraction.prototype.eq = function(other) {
return this.compare(other) == 0;
};
Fraction.prototype.max = function(other) {
return this.gt(other) ? this : other;
};
Fraction.prototype.min = function(other) {
return this.lt(other) ? this : other;
};
Fraction.prototype.show = function() {
return this.s * this.n + "/" + this.d;
};
Fraction.prototype.or = function(other) {
return this.eq(0) ? other : this;
};
class TimeSpan { class TimeSpan {
constructor(begin, end) { constructor(begin, end) {
this.begin = Fraction(begin); this.begin = Fraction(begin);

2
docs/dist/euclid.js vendored
View file

@ -1,7 +1,7 @@
import {Pattern, timeCat} from "../_snowpack/link/strudel.js"; import {Pattern, timeCat} from "../_snowpack/link/strudel.js";
import bjork from "../_snowpack/pkg/bjork.js"; import bjork from "../_snowpack/pkg/bjork.js";
import {rotate} from "../_snowpack/link/util.js"; import {rotate} from "../_snowpack/link/util.js";
import Fraction from "../_snowpack/pkg/fractionjs.js"; import Fraction from "../_snowpack/link/fraction.js";
const euclid = (pulses, steps, rotation = 0) => { const euclid = (pulses, steps, rotation = 0) => {
const b = bjork(steps, pulses); const b = bjork(steps, pulses);
if (rotation) { if (rotation) {

4
docs/dist/parse.js vendored
View file

@ -10,7 +10,7 @@ const applyOptions = (parent) => (pat, i) => {
if (operator) { if (operator) {
switch (operator.type_) { switch (operator.type_) {
case "stretch": case "stretch":
const speed = new Fraction(operator.arguments_.amount).inverse(); const speed = Fraction(operator.arguments_.amount).inverse();
return reify(pat).fast(speed); return reify(pat).fast(speed);
case "bjorklund": case "bjorklund":
return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation); return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
@ -46,7 +46,7 @@ function resolveReplications(ast) {
options_: { options_: {
operator: { operator: {
type_: "stretch", type_: "stretch",
arguments_: {amount: new Fraction(replicate).inverse().toString()} arguments_: {amount: Fraction(replicate).inverse().toString()}
} }
} }
} }

View file

@ -42079,7 +42079,7 @@ parcelHelpers.export(exports, "square2", ()=>square2
// then you can do transpose(2).late(0.2) instead of x => x.transpose(2).late(0.2) // then you can do transpose(2).late(0.2) instead of x => x.transpose(2).late(0.2)
parcelHelpers.export(exports, "makeComposable", ()=>makeComposable parcelHelpers.export(exports, "makeComposable", ()=>makeComposable
); );
parcelHelpers.export(exports, "Fraction", ()=>_fractionJsDefault.default parcelHelpers.export(exports, "Fraction", ()=>_fractionMjsDefault.default
); );
parcelHelpers.export(exports, "TimeSpan", ()=>TimeSpan parcelHelpers.export(exports, "TimeSpan", ()=>TimeSpan
); );
@ -42155,8 +42155,8 @@ parcelHelpers.export(exports, "inv", ()=>inv
); );
parcelHelpers.export(exports, "withLocationOffset", ()=>withLocationOffset parcelHelpers.export(exports, "withLocationOffset", ()=>withLocationOffset
); );
var _fractionJs = require("./fraction.js"); var _fractionMjs = require("./fraction.mjs");
var _fractionJsDefault = parcelHelpers.interopDefault(_fractionJs); var _fractionMjsDefault = parcelHelpers.interopDefault(_fractionMjs);
var _ramda = require("ramda"); // will remove this as soon as compose is implemented here var _ramda = require("ramda"); // will remove this as soon as compose is implemented here
var _utilMjs = require("./util.mjs"); var _utilMjs = require("./util.mjs");
// Removes 'None' values from given list // Removes 'None' values from given list
@ -42181,49 +42181,10 @@ function curry(func, overload) {
if (overload) overload(fn, []); if (overload) overload(fn, []);
return fn; return fn;
} }
// Returns the start of the cycle.
_fractionJsDefault.default.prototype.sam = function() {
return this.floor();
};
// Returns the start of the next cycle.
_fractionJsDefault.default.prototype.nextSam = function() {
return this.sam().add(1);
};
// Returns a TimeSpan representing the begin and end of the Time value's cycle
_fractionJsDefault.default.prototype.wholeCycle = function() {
return new TimeSpan(this.sam(), this.nextSam());
};
_fractionJsDefault.default.prototype.lt = function(other) {
return this.compare(other) < 0;
};
_fractionJsDefault.default.prototype.gt = function(other) {
return this.compare(other) > 0;
};
_fractionJsDefault.default.prototype.lte = function(other) {
return this.compare(other) <= 0;
};
_fractionJsDefault.default.prototype.gte = function(other) {
return this.compare(other) >= 0;
};
_fractionJsDefault.default.prototype.eq = function(other) {
return this.compare(other) == 0;
};
_fractionJsDefault.default.prototype.max = function(other) {
return this.gt(other) ? this : other;
};
_fractionJsDefault.default.prototype.min = function(other) {
return this.lt(other) ? this : other;
};
_fractionJsDefault.default.prototype.show = function() {
return this.s * this.n + "/" + this.d;
};
_fractionJsDefault.default.prototype.or = function(other) {
return this.eq(0) ? other : this;
};
class TimeSpan { class TimeSpan {
constructor(begin, end){ constructor(begin, end){
this.begin = _fractionJsDefault.default(begin); this.begin = _fractionMjsDefault.default(begin);
this.end = _fractionJsDefault.default(end); this.end = _fractionMjsDefault.default(end);
} }
get spanCycles() { get spanCycles() {
const spans = []; const spans = [];
@ -42271,7 +42232,7 @@ class TimeSpan {
return result; return result;
} }
midpoint() { midpoint() {
return this.begin.add(this.end.sub(this.begin).div(_fractionJsDefault.default(2))); return this.begin.add(this.end.sub(this.begin).div(_fractionMjsDefault.default(2)));
} }
equals(other) { equals(other) {
return this.begin.equals(other.begin) && this.end.equals(other.end); return this.begin.equals(other.begin) && this.end.equals(other.end);
@ -42538,7 +42499,7 @@ class Pattern {
firstCycle(with_context = false) { firstCycle(with_context = false) {
var self = this; var self = this;
if (!with_context) self = self._stripContext(); if (!with_context) self = self._stripContext();
return self.query(new State(new TimeSpan(_fractionJsDefault.default(0), _fractionJsDefault.default(1)))); return self.query(new State(new TimeSpan(_fractionMjsDefault.default(0), _fractionMjsDefault.default(1))));
} }
_sortEventsByPart() { _sortEventsByPart() {
return this._withEvents((events)=>events.sort((a, b)=>a.part.begin.sub(b.part.begin).or(a.part.end.sub(b.part.end)).or(a.whole.begin.sub(b.whole.begin).or(a.whole.end.sub(b.whole.end))) return this._withEvents((events)=>events.sort((a, b)=>a.part.begin.sub(b.part.begin).or(a.part.end.sub(b.part.end)).or(a.whole.begin.sub(b.whole.begin).or(a.whole.end.sub(b.whole.end)))
@ -42697,7 +42658,7 @@ class Pattern {
const b = span.begin; const b = span.begin;
const e = span.end; const e = span.end;
if (b > e || b > 1 || e > 1 || b < 0 || e < 0) return silence; if (b > e || b > 1 || e > 1 || b < 0 || e < 0) return silence;
return this._fastGap(_fractionJsDefault.default(1).div(e.sub(b)))._late(b); return this._fastGap(_fractionMjsDefault.default(1).div(e.sub(b)))._late(b);
} }
_fast(factor) { _fast(factor) {
const fastQuery = this.withQueryTime((t)=>t.mul(factor) const fastQuery = this.withQueryTime((t)=>t.mul(factor)
@ -42706,19 +42667,19 @@ class Pattern {
); );
} }
_slow(factor) { _slow(factor) {
return this._fast(_fractionJsDefault.default(1).div(factor)); return this._fast(_fractionMjsDefault.default(1).div(factor));
} }
_early(offset) { _early(offset) {
// Equivalent of Tidal's <~ operator // Equivalent of Tidal's <~ operator
offset = _fractionJsDefault.default(offset); offset = _fractionMjsDefault.default(offset);
return this.withQueryTime((t)=>t.add(offset) return this.withQueryTime((t)=>t.add(offset)
).withEventTime((t)=>t.sub(offset) ).withEventTime((t)=>t.sub(offset)
); );
} }
_late(offset) { _late(offset) {
// Equivalent of Tidal's ~> operator // Equivalent of Tidal's ~> operator
offset = _fractionJsDefault.default(offset); offset = _fractionMjsDefault.default(offset);
return this._early(_fractionJsDefault.default(0).sub(offset)); return this._early(_fractionMjsDefault.default(0).sub(offset));
} }
struct(...binary_pats) { struct(...binary_pats) {
// Re structure the pattern according to a binary pattern (false values are dropped) // Re structure the pattern according to a binary pattern (false values are dropped)
@ -42886,7 +42847,7 @@ const silence = new Pattern((_)=>[]
function pure(value) { function pure(value) {
// A discrete value that repeats once per cycle // A discrete value that repeats once per cycle
function query(state) { function query(state) {
return state.span.spanCycles.map((subspan)=>new Hap(_fractionJsDefault.default(subspan.begin).wholeCycle(), subspan, value) return state.span.spanCycles.map((subspan)=>new Hap(_fractionMjsDefault.default(subspan.begin).wholeCycle(), subspan, value)
); );
} }
return new Pattern(query); return new Pattern(query);
@ -42912,8 +42873,8 @@ const _fromBipolar = (pat)=>pat.fmap((x)=>(x + 1) / 2
const sine2 = signal((t)=>Math.sin(Math.PI * 2 * t) const sine2 = signal((t)=>Math.sin(Math.PI * 2 * t)
); );
const sine = _fromBipolar(sine2); const sine = _fromBipolar(sine2);
const cosine2 = sine2._early(_fractionJsDefault.default(1).div(4)); const cosine2 = sine2._early(_fractionMjsDefault.default(1).div(4));
const cosine = sine._early(_fractionJsDefault.default(1).div(4)); const cosine = sine._early(_fractionMjsDefault.default(1).div(4));
const saw = signal((t)=>t % 1 const saw = signal((t)=>t % 1
); );
const saw2 = _toBipolar(saw); const saw2 = _toBipolar(saw);
@ -42982,8 +42943,8 @@ function timeCat(...timepats) {
// Like cat, but where each step has a temporal 'weight' // Like cat, but where each step has a temporal 'weight'
const total = timepats.map((a)=>a[0] const total = timepats.map((a)=>a[0]
).reduce((a, b)=>a.add(b) ).reduce((a, b)=>a.add(b)
, _fractionJsDefault.default(0)); , _fractionMjsDefault.default(0));
let begin = _fractionJsDefault.default(0); let begin = _fractionMjsDefault.default(0);
const pats = []; const pats = [];
for (const [time, pat] of timepats){ for (const [time, pat] of timepats){
const end = begin.add(time); const end = begin.add(time);
@ -43022,7 +42983,7 @@ function polymeter(steps = 0, ...args) {
for (const seq of seqs){ for (const seq of seqs){
seq[1]; seq[1];
if (steps == seq[1]) pats.push(seq[0]); if (steps == seq[1]) pats.push(seq[0]);
else pats.push(seq[0]._fast(_fractionJsDefault.default(steps).div(_fractionJsDefault.default(seq[1])))); else pats.push(seq[0]._fast(_fractionMjsDefault.default(steps).div(_fractionMjsDefault.default(seq[1]))));
} }
return stack(pats); return stack(pats);
} }
@ -43183,10 +43144,77 @@ function withLocationOffset(pat, offset) {
}); });
} }
},{"./fraction.js":"8kRZA","ramda":"10uzi","./util.mjs":"9Z602","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"8kRZA":[function(require,module,exports) { },{"./fraction.mjs":"8Ovmi","ramda":"10uzi","./util.mjs":"9Z602","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"8Ovmi":[function(require,module,exports) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
parcelHelpers.defineInteropFlag(exports); parcelHelpers.defineInteropFlag(exports);
"use strict"; var _fractionJs = require("fraction.js");
var _fractionJsDefault = parcelHelpers.interopDefault(_fractionJs);
var _strudelMjs = require("./strudel.mjs");
// Returns the start of the cycle.
_fractionJsDefault.default.prototype.sam = function() {
return this.floor();
};
// Returns the start of the next cycle.
_fractionJsDefault.default.prototype.nextSam = function() {
return this.sam().add(1);
};
// Returns a TimeSpan representing the begin and end of the Time value's cycle
_fractionJsDefault.default.prototype.wholeCycle = function() {
return new _strudelMjs.TimeSpan(this.sam(), this.nextSam());
};
_fractionJsDefault.default.prototype.lt = function(other) {
return this.compare(other) < 0;
};
_fractionJsDefault.default.prototype.gt = function(other) {
return this.compare(other) > 0;
};
_fractionJsDefault.default.prototype.lte = function(other) {
return this.compare(other) <= 0;
};
_fractionJsDefault.default.prototype.gte = function(other) {
return this.compare(other) >= 0;
};
_fractionJsDefault.default.prototype.eq = function(other) {
return this.compare(other) == 0;
};
_fractionJsDefault.default.prototype.max = function(other) {
return this.gt(other) ? this : other;
};
_fractionJsDefault.default.prototype.min = function(other) {
return this.lt(other) ? this : other;
};
_fractionJsDefault.default.prototype.show = function() {
return this.s * this.n + '/' + this.d;
};
_fractionJsDefault.default.prototype.or = function(other) {
return this.eq(0) ? other : this;
};
const fraction = (n)=>{
if (typeof n === 'number') /*
https://github.com/infusion/Fraction.js/#doubles
If you pass a double as it is, Fraction.js will perform a number analysis based on Farey Sequences."
If you want to keep the number as it is, convert it to a string, as the string parser will not perform any further observations
-> those farey sequences turn out to make pattern querying ~20 times slower! always use strings!
-> still, some optimizations could be done: .mul .div .add .sub calls still use numbers
*/ n = String(n);
return _fractionJsDefault.default(n);
};
exports.default = fraction; // "If you concern performance, cache Fraction.js objects and pass arrays/objects.“
// -> tested memoized version, but it's slower than unmemoized, even with repeated evaluation
/* const memo = {};
const memoizedFraction = (n) => {
if (typeof n === 'number') {
n = String(n);
}
if (memo[n] !== undefined) {
return memo[n];
}
memo[n] = Fraction(n);
return memo[n];
}; */
},{"fraction.js":"1Q5M2","./strudel.mjs":"ggZqJ","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"1Q5M2":[function(require,module,exports) {
/** /**
* @license Fraction.js v4.1.2 23/05/2021 * @license Fraction.js v4.1.2 23/05/2021
* https://www.xarg.org/2014/03/rational-numbers-in-javascript/ * https://www.xarg.org/2014/03/rational-numbers-in-javascript/
@ -43221,10 +43249,7 @@ parcelHelpers.defineInteropFlag(exports);
* var f = new Fraction("9.4'31'"); * var f = new Fraction("9.4'31'");
* f.mul([-4, 3]).div(4.9); * f.mul([-4, 3]).div(4.9);
* *
*/ const memo = { */ (function(root) {
};
let root = {
};
// Maximum search depth for cyclic rational numbers. 2000 should be more than enough. // Maximum search depth for cyclic rational numbers. 2000 should be more than enough.
// Example: 1/7 = 0.(142857) has 6 repeating decimal places. // Example: 1/7 = 0.(142857) has 6 repeating decimal places.
// If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits // If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits
@ -43314,14 +43339,6 @@ var parse = function(p1, p2) {
z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10)); z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10));
p1 /= z; p1 /= z;
} }
const key = p1 + '#' + p2;
const memoized = memo[key];
if (memoized) {
s = memoized.s;
n = memoized.n;
d = memoized.d;
break;
}
// Using Farey Sequences // Using Farey Sequences
// http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/ // http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/
while(B <= N && D <= N){ while(B <= N && D <= N){
@ -43403,11 +43420,6 @@ var parse = function(p1, p2) {
P["s"] = s < 0 ? -1 : 1; P["s"] = s < 0 ? -1 : 1;
P["n"] = Math.abs(n); P["n"] = Math.abs(n);
P["d"] = Math.abs(d); P["d"] = Math.abs(d);
memo[p1 + '#' + p2] = {
s: P["s"],
n: P["n"],
d: P["d"]
};
}; };
function modpow(b, e, m) { function modpow(b, e, m) {
var r = 1; var r = 1;
@ -43801,9 +43813,9 @@ else if (typeof exports === "object") {
Fraction['Fraction'] = Fraction; Fraction['Fraction'] = Fraction;
module['exports'] = Fraction; module['exports'] = Fraction;
} else root['Fraction'] = Fraction; } else root['Fraction'] = Fraction;
exports.default = Fraction; })(this);
},{"@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"10uzi":[function(require,module,exports) { },{}],"10uzi":[function(require,module,exports) {
var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js"); var parcelHelpers = require("@parcel/transformer-js/src/esmodule-helpers.js");
parcelHelpers.defineInteropFlag(exports); parcelHelpers.defineInteropFlag(exports);
parcelHelpers.export(exports, "F", ()=>_fJsDefault.default parcelHelpers.export(exports, "F", ()=>_fJsDefault.default
@ -136310,8 +136322,8 @@ var _strudelMjs = require("../../strudel.mjs");
var _bjork = require("bjork"); var _bjork = require("bjork");
var _bjorkDefault = parcelHelpers.interopDefault(_bjork); var _bjorkDefault = parcelHelpers.interopDefault(_bjork);
var _utilMjs = require("../../util.mjs"); var _utilMjs = require("../../util.mjs");
var _fractionJs = require("fraction.js"); var _fractionMjs = require("../../fraction.mjs");
var _fractionJsDefault = parcelHelpers.interopDefault(_fractionJs); var _fractionMjsDefault = parcelHelpers.interopDefault(_fractionMjs);
const euclid = (pulses, steps, rotation = 0)=>{ const euclid = (pulses, steps, rotation = 0)=>{
const b = _bjorkDefault.default(steps, pulses); const b = _bjorkDefault.default(steps, pulses);
if (rotation) return _utilMjs.rotate(b, -rotation); if (rotation) return _utilMjs.rotate(b, -rotation);
@ -136328,11 +136340,11 @@ _strudelMjs.Pattern.prototype.euclidLegato = function(pulses, steps, rotation =
true true
] ]
); );
return this.struct(_strudelMjs.timeCat(...gapless)).late(_fractionJsDefault.default(firstOne).div(steps)); return this.struct(_strudelMjs.timeCat(...gapless)).late(_fractionMjsDefault.default(firstOne).div(steps));
}; };
exports.default = euclid; exports.default = euclid;
},{"../../strudel.mjs":"ggZqJ","bjork":"hTZTb","../../util.mjs":"9Z602","fraction.js":"iDLoJ","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"hTZTb":[function(require,module,exports) { },{"../../strudel.mjs":"ggZqJ","bjork":"hTZTb","../../util.mjs":"9Z602","../../fraction.mjs":"8Ovmi","@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}],"hTZTb":[function(require,module,exports) {
function bjorklund(slots, pulses) { function bjorklund(slots, pulses) {
var pattern = [], count = [], remainder = [ var pattern = [], count = [], remainder = [
pulses pulses
@ -136359,607 +136371,6 @@ module.exports = function(m, k) {
else return bjorklund(k, m); else return bjorklund(k, m);
}; };
},{}],"iDLoJ":[function(require,module,exports) {
/**
* @license Fraction.js v4.1.2 23/05/2021
* https://www.xarg.org/2014/03/rational-numbers-in-javascript/
*
* Copyright (c) 2021, Robert Eisele (robert@xarg.org)
* Dual licensed under the MIT or GPL Version 2 licenses.
**/ /**
*
* This class offers the possibility to calculate fractions.
* You can pass a fraction in different formats. Either as array, as double, as string or as an integer.
*
* Array/Object form
* [ 0 => <nominator>, 1 => <denominator> ]
* [ n => <nominator>, d => <denominator> ]
*
* Integer form
* - Single integer value
*
* Double form
* - Single double value
*
* String form
* 123.456 - a simple double
* 123/456 - a string fraction
* 123.'456' - a double with repeating decimal places
* 123.(456) - synonym
* 123.45'6' - a double with repeating last place
* 123.45(6) - synonym
*
* Example:
*
* var f = new Fraction("9.4'31'");
* f.mul([-4, 3]).div(4.9);
*
*/ (function(root) {
// Maximum search depth for cyclic rational numbers. 2000 should be more than enough.
// Example: 1/7 = 0.(142857) has 6 repeating decimal places.
// If MAX_CYCLE_LEN gets reduced, long cycles will not be detected and toString() only gets the first 10 digits
var MAX_CYCLE_LEN = 2000;
// Parsed data to avoid calling "new" all the time
var P = {
"s": 1,
"n": 0,
"d": 1
};
function createError(name) {
function errorConstructor() {
var temp = Error.apply(this, arguments);
temp['name'] = this['name'] = name;
this['stack'] = temp['stack'];
this['message'] = temp['message'];
}
/**
* Error constructor
*
* @constructor
*/ function IntermediateInheritor() {
}
IntermediateInheritor.prototype = Error.prototype;
errorConstructor.prototype = new IntermediateInheritor();
return errorConstructor;
}
var DivisionByZero = Fraction['DivisionByZero'] = createError('DivisionByZero');
var InvalidParameter = Fraction['InvalidParameter'] = createError('InvalidParameter');
function assign(n, s) {
if (isNaN(n = parseInt(n, 10))) throwInvalidParam();
return n * s;
}
function throwInvalidParam() {
throw new InvalidParameter();
}
function factorize(num) {
var factors = {
};
var n = num;
var i = 2;
var s = 4;
while(s <= n){
while(n % i === 0){
n /= i;
factors[i] = (factors[i] || 0) + 1;
}
s += 1 + 2 * i++;
}
if (n !== num) {
if (n > 1) factors[n] = (factors[n] || 0) + 1;
} else factors[num] = (factors[num] || 0) + 1;
return factors;
}
var parse = function(p1, p2) {
var n = 0, d = 1, s = 1;
var v = 0, w = 0, x = 0, y = 1, z = 1;
var A = 0, B = 1;
var C = 1, D = 1;
var N = 10000000;
var M;
if (p1 === undefined || p1 === null) ;
else if (p2 !== undefined) {
n = p1;
d = p2;
s = n * d;
} else switch(typeof p1){
case "object":
if ("d" in p1 && "n" in p1) {
n = p1["n"];
d = p1["d"];
if ("s" in p1) n *= p1["s"];
} else if (0 in p1) {
n = p1[0];
if (1 in p1) d = p1[1];
} else throwInvalidParam();
s = n * d;
break;
case "number":
if (p1 < 0) {
s = p1;
p1 = -p1;
}
if (p1 % 1 === 0) n = p1;
else if (p1 > 0) {
if (p1 >= 1) {
z = Math.pow(10, Math.floor(1 + Math.log(p1) / Math.LN10));
p1 /= z;
}
// Using Farey Sequences
// http://www.johndcook.com/blog/2010/10/20/best-rational-approximation/
while(B <= N && D <= N){
M = (A + C) / (B + D);
if (p1 === M) {
if (B + D <= N) {
n = A + C;
d = B + D;
} else if (D > B) {
n = C;
d = D;
} else {
n = A;
d = B;
}
break;
} else {
if (p1 > M) {
A += C;
B += D;
} else {
C += A;
D += B;
}
if (B > N) {
n = C;
d = D;
} else {
n = A;
d = B;
}
}
}
n *= z;
} else if (isNaN(p1) || isNaN(p2)) d = n = NaN;
break;
case "string":
B = p1.match(/\d+|./g);
if (B === null) throwInvalidParam();
if (B[A] === '-') {
s = -1;
A++;
} else if (B[A] === '+') A++;
if (B.length === A + 1) w = assign(B[A++], s);
else if (B[A + 1] === '.' || B[A] === '.') {
if (B[A] !== '.') v = assign(B[A++], s);
A++;
// Check for decimal places
if (A + 1 === B.length || B[A + 1] === '(' && B[A + 3] === ')' || B[A + 1] === "'" && B[A + 3] === "'") {
w = assign(B[A], s);
y = Math.pow(10, B[A].length);
A++;
}
// Check for repeating places
if (B[A] === '(' && B[A + 2] === ')' || B[A] === "'" && B[A + 2] === "'") {
x = assign(B[A + 1], s);
z = Math.pow(10, B[A + 1].length) - 1;
A += 3;
}
} else if (B[A + 1] === '/' || B[A + 1] === ':') {
w = assign(B[A], s);
y = assign(B[A + 2], 1);
A += 3;
} else if (B[A + 3] === '/' && B[A + 1] === ' ') {
v = assign(B[A], s);
w = assign(B[A + 2], s);
y = assign(B[A + 4], 1);
A += 5;
}
if (B.length <= A) {
d = y * z;
s = /* void */ n = x + d * v + z * w;
break;
}
default:
throwInvalidParam();
}
if (d === 0) throw new DivisionByZero();
P["s"] = s < 0 ? -1 : 1;
P["n"] = Math.abs(n);
P["d"] = Math.abs(d);
};
function modpow(b, e, m) {
var r = 1;
for(; e > 0; b = b * b % m, e >>= 1)if (e & 1) r = r * b % m;
return r;
}
function cycleLen(n, d) {
for(; d % 2 === 0; d /= 2);
for(; d % 5 === 0; d /= 5);
if (d === 1) return 0;
// If we would like to compute really large numbers quicker, we could make use of Fermat's little theorem:
// 10^(d-1) % d == 1
// However, we don't need such large numbers and MAX_CYCLE_LEN should be the capstone,
// as we want to translate the numbers to strings.
var rem = 10 % d;
var t = 1;
for(; rem !== 1; t++){
rem = rem * 10 % d;
if (t > MAX_CYCLE_LEN) return 0; // Returning 0 here means that we don't print it as a cyclic number. It's likely that the answer is `d-1`
}
return t;
}
function cycleStart(n, d, len) {
var rem1 = 1;
var rem2 = modpow(10, len, d);
for(var t = 0; t < 300; t++){
// Solve 10^s == 10^(s+t) (mod d)
if (rem1 === rem2) return t;
rem1 = rem1 * 10 % d;
rem2 = rem2 * 10 % d;
}
return 0;
}
function gcd(a, b) {
if (!a) return b;
if (!b) return a;
while(true){
a %= b;
if (!a) return b;
b %= a;
if (!b) return a;
}
}
/**
* Module constructor
*
* @constructor
* @param {number|Fraction=} a
* @param {number=} b
*/ function Fraction(a, b) {
if (!(this instanceof Fraction)) return new Fraction(a, b);
parse(a, b);
a = gcd(P["d"], P["n"]); // Abuse variable a
this["s"] = P["s"];
this["n"] = P["n"] / a;
this["d"] = P["d"] / a;
}
Fraction.prototype = {
"s": 1,
"n": 0,
"d": 1,
/**
* Calculates the absolute value
*
* Ex: new Fraction(-4).abs() => 4
**/ "abs": function() {
return new Fraction(this["n"], this["d"]);
},
/**
* Inverts the sign of the current fraction
*
* Ex: new Fraction(-4).neg() => 4
**/ "neg": function() {
return new Fraction(-this["s"] * this["n"], this["d"]);
},
/**
* Adds two rational numbers
*
* Ex: new Fraction({n: 2, d: 3}).add("14.9") => 467 / 30
**/ "add": function(a, b) {
parse(a, b);
return new Fraction(this["s"] * this["n"] * P["d"] + P["s"] * this["d"] * P["n"], this["d"] * P["d"]);
},
/**
* Subtracts two rational numbers
*
* Ex: new Fraction({n: 2, d: 3}).add("14.9") => -427 / 30
**/ "sub": function(a, b) {
parse(a, b);
return new Fraction(this["s"] * this["n"] * P["d"] - P["s"] * this["d"] * P["n"], this["d"] * P["d"]);
},
/**
* Multiplies two rational numbers
*
* Ex: new Fraction("-17.(345)").mul(3) => 5776 / 111
**/ "mul": function(a, b) {
parse(a, b);
return new Fraction(this["s"] * P["s"] * this["n"] * P["n"], this["d"] * P["d"]);
},
/**
* Divides two rational numbers
*
* Ex: new Fraction("-17.(345)").inverse().div(3)
**/ "div": function(a, b) {
parse(a, b);
return new Fraction(this["s"] * P["s"] * this["n"] * P["d"], this["d"] * P["n"]);
},
/**
* Clones the actual object
*
* Ex: new Fraction("-17.(345)").clone()
**/ "clone": function() {
return new Fraction(this);
},
/**
* Calculates the modulo of two rational numbers - a more precise fmod
*
* Ex: new Fraction('4.(3)').mod([7, 8]) => (13/3) % (7/8) = (5/6)
**/ "mod": function(a, b) {
if (isNaN(this['n']) || isNaN(this['d'])) return new Fraction(NaN);
if (a === undefined) return new Fraction(this["s"] * this["n"] % this["d"], 1);
parse(a, b);
if (0 === P["n"] && 0 === this["d"]) Fraction(0, 0); // Throw DivisionByZero
/*
* First silly attempt, kinda slow
*
return that["sub"]({
"n": num["n"] * Math.floor((this.n / this.d) / (num.n / num.d)),
"d": num["d"],
"s": this["s"]
});*/ /*
* New attempt: a1 / b1 = a2 / b2 * q + r
* => b2 * a1 = a2 * b1 * q + b1 * b2 * r
* => (b2 * a1 % a2 * b1) / (b1 * b2)
*/ return new Fraction(this["s"] * (P["d"] * this["n"]) % (P["n"] * this["d"]), P["d"] * this["d"]);
},
/**
* Calculates the fractional gcd of two rational numbers
*
* Ex: new Fraction(5,8).gcd(3,7) => 1/56
*/ "gcd": function(a, b) {
parse(a, b);
// gcd(a / b, c / d) = gcd(a, c) / lcm(b, d)
return new Fraction(gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]), P["d"] * this["d"]);
},
/**
* Calculates the fractional lcm of two rational numbers
*
* Ex: new Fraction(5,8).lcm(3,7) => 15
*/ "lcm": function(a, b) {
parse(a, b);
// lcm(a / b, c / d) = lcm(a, c) / gcd(b, d)
if (P["n"] === 0 && this["n"] === 0) return new Fraction;
return new Fraction(P["n"] * this["n"], gcd(P["n"], this["n"]) * gcd(P["d"], this["d"]));
},
/**
* Calculates the ceil of a rational number
*
* Ex: new Fraction('4.(3)').ceil() => (5 / 1)
**/ "ceil": function(places) {
places = Math.pow(10, places || 0);
if (isNaN(this["n"]) || isNaN(this["d"])) return new Fraction(NaN);
return new Fraction(Math.ceil(places * this["s"] * this["n"] / this["d"]), places);
},
/**
* Calculates the floor of a rational number
*
* Ex: new Fraction('4.(3)').floor() => (4 / 1)
**/ "floor": function(places) {
places = Math.pow(10, places || 0);
if (isNaN(this["n"]) || isNaN(this["d"])) return new Fraction(NaN);
return new Fraction(Math.floor(places * this["s"] * this["n"] / this["d"]), places);
},
/**
* Rounds a rational numbers
*
* Ex: new Fraction('4.(3)').round() => (4 / 1)
**/ "round": function(places) {
places = Math.pow(10, places || 0);
if (isNaN(this["n"]) || isNaN(this["d"])) return new Fraction(NaN);
return new Fraction(Math.round(places * this["s"] * this["n"] / this["d"]), places);
},
/**
* Gets the inverse of the fraction, means numerator and denominator are exchanged
*
* Ex: new Fraction([-3, 4]).inverse() => -4 / 3
**/ "inverse": function() {
return new Fraction(this["s"] * this["d"], this["n"]);
},
/**
* Calculates the fraction to some rational exponent, if possible
*
* Ex: new Fraction(-1,2).pow(-3) => -8
*/ "pow": function(a, b) {
parse(a, b);
// Trivial case when exp is an integer
if (P['d'] === 1) {
if (P['s'] < 0) return new Fraction(Math.pow(this['s'] * this["d"], P['n']), Math.pow(this["n"], P['n']));
else return new Fraction(Math.pow(this['s'] * this["n"], P['n']), Math.pow(this["d"], P['n']));
}
// Negative roots become complex
// (-a/b)^(c/d) = x
// <=> (-1)^(c/d) * (a/b)^(c/d) = x
// <=> (cos(pi) + i*sin(pi))^(c/d) * (a/b)^(c/d) = x # rotate 1 by 180°
// <=> (cos(c*pi/d) + i*sin(c*pi/d)) * (a/b)^(c/d) = x # DeMoivre's formula in Q ( https://proofwiki.org/wiki/De_Moivre%27s_Formula/Rational_Index )
// From which follows that only for c=0 the root is non-complex. c/d is a reduced fraction, so that sin(c/dpi)=0 occurs for d=1, which is handled by our trivial case.
if (this['s'] < 0) return null;
// Now prime factor n and d
var N = factorize(this['n']);
var D = factorize(this['d']);
// Exponentiate and take root for n and d individually
var n = 1;
var d = 1;
for(var k in N){
if (k === '1') continue;
if (k === '0') {
n = 0;
break;
}
N[k] *= P['n'];
if (N[k] % P['d'] === 0) N[k] /= P['d'];
else return null;
n *= Math.pow(k, N[k]);
}
for(var k in D){
if (k === '1') continue;
D[k] *= P['n'];
if (D[k] % P['d'] === 0) D[k] /= P['d'];
else return null;
d *= Math.pow(k, D[k]);
}
if (P['s'] < 0) return new Fraction(d, n);
return new Fraction(n, d);
},
/**
* Check if two rational numbers are the same
*
* Ex: new Fraction(19.6).equals([98, 5]);
**/ "equals": function(a, b) {
parse(a, b);
return this["s"] * this["n"] * P["d"] === P["s"] * P["n"] * this["d"]; // Same as compare() === 0
},
/**
* Check if two rational numbers are the same
*
* Ex: new Fraction(19.6).equals([98, 5]);
**/ "compare": function(a, b) {
parse(a, b);
var t = this["s"] * this["n"] * P["d"] - P["s"] * P["n"] * this["d"];
return (0 < t) - (t < 0);
},
"simplify": function(eps) {
// First naive implementation, needs improvement
if (isNaN(this['n']) || isNaN(this['d'])) return this;
var cont = this['abs']()['toContinued']();
eps = eps || 0.001;
function rec(a) {
if (a.length === 1) return new Fraction(a[0]);
return rec(a.slice(1))['inverse']()['add'](a[0]);
}
for(var i = 0; i < cont.length; i++){
var tmp = rec(cont.slice(0, i + 1));
if (tmp['sub'](this['abs']())['abs']().valueOf() < eps) return tmp['mul'](this['s']);
}
return this;
},
/**
* Check if two rational numbers are divisible
*
* Ex: new Fraction(19.6).divisible(1.5);
*/ "divisible": function(a, b) {
parse(a, b);
return !(!(P["n"] * this["d"]) || this["n"] * P["d"] % (P["n"] * this["d"]));
},
/**
* Returns a decimal representation of the fraction
*
* Ex: new Fraction("100.'91823'").valueOf() => 100.91823918239183
**/ 'valueOf': function() {
return this["s"] * this["n"] / this["d"];
},
/**
* Returns a string-fraction representation of a Fraction object
*
* Ex: new Fraction("1.'3'").toFraction() => "4 1/3"
**/ 'toFraction': function(excludeWhole) {
var whole, str = "";
var n = this["n"];
var d = this["d"];
if (this["s"] < 0) str += '-';
if (d === 1) str += n;
else {
if (excludeWhole && (whole = Math.floor(n / d)) > 0) {
str += whole;
str += " ";
n %= d;
}
str += n;
str += '/';
str += d;
}
return str;
},
/**
* Returns a latex representation of a Fraction object
*
* Ex: new Fraction("1.'3'").toLatex() => "\frac{4}{3}"
**/ 'toLatex': function(excludeWhole) {
var whole, str = "";
var n = this["n"];
var d = this["d"];
if (this["s"] < 0) str += '-';
if (d === 1) str += n;
else {
if (excludeWhole && (whole = Math.floor(n / d)) > 0) {
str += whole;
n %= d;
}
str += "\\frac{";
str += n;
str += '}{';
str += d;
str += '}';
}
return str;
},
/**
* Returns an array of continued fraction elements
*
* Ex: new Fraction("7/8").toContinued() => [0,1,7]
*/ 'toContinued': function() {
var t;
var a = this['n'];
var b = this['d'];
var res = [];
if (isNaN(a) || isNaN(b)) return res;
do {
res.push(Math.floor(a / b));
t = a % b;
a = b;
b = t;
}while (a !== 1)
return res;
},
/**
* Creates a string representation of a fraction with all digits
*
* Ex: new Fraction("100.'91823'").toString() => "100.(91823)"
**/ 'toString': function(dec) {
var g;
var N = this["n"];
var D = this["d"];
if (isNaN(N) || isNaN(D)) return "NaN";
dec = dec || 15; // 15 = decimal places when no repetation
var cycLen = cycleLen(N, D); // Cycle length
var cycOff = cycleStart(N, D, cycLen); // Cycle start
var str = this['s'] === -1 ? "-" : "";
str += N / D | 0;
N %= D;
N *= 10;
if (N) str += ".";
if (cycLen) {
for(var i = cycOff; i--;){
str += N / D | 0;
N %= D;
N *= 10;
}
str += "(";
for(var i = cycLen; i--;){
str += N / D | 0;
N %= D;
N *= 10;
}
str += ")";
} else for(var i = dec; N && i--;){
str += N / D | 0;
N %= D;
N *= 10;
}
return str;
}
};
if (typeof define === "function" && define["amd"]) define([], function() {
return Fraction;
});
else if (typeof exports === "object") {
Object.defineProperty(Fraction, "__esModule", {
'value': true
});
Fraction['default'] = Fraction;
Fraction['Fraction'] = Fraction;
module['exports'] = Fraction;
} else root['Fraction'] = Fraction;
})(this);
},{}],"6BZJ6":[function(require,module,exports) { },{}],"6BZJ6":[function(require,module,exports) {
var _strudelMjs = require("../../strudel.mjs"); var _strudelMjs = require("../../strudel.mjs");
_strudelMjs.Pattern.prototype.pianoroll = function({ timeframe =10 , inactive ='#C9E597' , active ='#FFCA28' , background ='#2A3236' , maxMidi =90 , minMidi =0 , } = { _strudelMjs.Pattern.prototype.pianoroll = function({ timeframe =10 , inactive ='#C9E597' , active ='#FFCA28' , background ='#2A3236' , maxMidi =90 , minMidi =0 , } = {
@ -170442,7 +169853,7 @@ const applyOptions = (parent)=>(pat, i)=>{
if (operator) { if (operator) {
switch(operator.type_){ switch(operator.type_){
case 'stretch': case 'stretch':
const speed = new Fraction(operator.arguments_.amount).inverse(); const speed = Fraction(operator.arguments_.amount).inverse();
return reify(pat).fast(speed); return reify(pat).fast(speed);
case 'bjorklund': case 'bjorklund':
return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation); return pat.euclid(operator.arguments_.pulse, operator.arguments_.step, operator.arguments_.rotation);
@ -170486,7 +169897,7 @@ function resolveReplications(ast) {
operator: { operator: {
type_: 'stretch', type_: 'stretch',
arguments_: { arguments_: {
amount: new Fraction(replicate).inverse().toString() amount: Fraction(replicate).inverse().toString()
} }
} }
} }
@ -183933,4 +183344,4 @@ exports.default = cx;
},{"@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}]},["3uVTb"], "3uVTb", "parcelRequire94c2") },{"@parcel/transformer-js/src/esmodule-helpers.js":"gkKU3"}]},["3uVTb"], "3uVTb", "parcelRequire94c2")
//# sourceMappingURL=index.1b17fa9c.js.map //# sourceMappingURL=index.f0b57381.js.map

File diff suppressed because one or more lines are too long

View file

@ -11,6 +11,6 @@
<body> <body>
<div id="root"></div> <div id="root"></div>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<script src="/tutorial/index.1b17fa9c.js" defer=""></script> <script src="/tutorial/index.f0b57381.js" defer=""></script>
</body> </body>
</html> </html>