Merge commit '83a46c68dc6583ad36b256bc0d03e0913ecbc1f0' into webaudio-compat

This commit is contained in:
Felix Roos 2022-04-18 18:33:47 +02:00
commit 3d74b8a2fa
18 changed files with 150 additions and 3657 deletions

View File

@ -1,16 +1,16 @@
{ {
"files": { "files": {
"main.css": "/static/css/main.0d689283.css", "main.css": "/static/css/main.0d689283.css",
"main.js": "/static/js/main.f7b8088f.js", "main.js": "/static/js/main.df1472e5.js",
"static/js/787.1c52cb78.chunk.js": "/static/js/787.1c52cb78.chunk.js", "static/js/787.1c52cb78.chunk.js": "/static/js/787.1c52cb78.chunk.js",
"static/media/logo.svg": "/static/media/logo.ac95051720b3dccfe511e0e02d8e1029.svg", "static/media/logo.svg": "/static/media/logo.ac95051720b3dccfe511e0e02d8e1029.svg",
"index.html": "/index.html", "index.html": "/index.html",
"main.0d689283.css.map": "/static/css/main.0d689283.css.map", "main.0d689283.css.map": "/static/css/main.0d689283.css.map",
"main.f7b8088f.js.map": "/static/js/main.f7b8088f.js.map", "main.df1472e5.js.map": "/static/js/main.df1472e5.js.map",
"787.1c52cb78.chunk.js.map": "/static/js/787.1c52cb78.chunk.js.map" "787.1c52cb78.chunk.js.map": "/static/js/787.1c52cb78.chunk.js.map"
}, },
"entrypoints": [ "entrypoints": [
"static/css/main.0d689283.css", "static/css/main.0d689283.css",
"static/js/main.f7b8088f.js" "static/js/main.df1472e5.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.f7b8088f.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.df1472e5.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

3
docs/static/js/main.df1472e5.js 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

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.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.36c08014.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.a35b0e47.js" defer></script> </body></html>

3674
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -179,14 +179,16 @@ export class Pattern {
const query = function (state) { const query = function (state) {
const haps = []; const haps = [];
for (const hap_func of pat_func.query(state)) { for (const hap_func of pat_func.query(state)) {
const event_vals = pat_val.query(state.setSpan(hap_func.part)); const event_vals = pat_val.query(state.setSpan(hap_func.wholeOrPart()));
for (const hap_val of event_vals) { for (const hap_val of event_vals) {
const new_whole = hap_func.whole; const new_whole = hap_func.whole;
const new_part = hap_func.part.intersection_e(hap_val.part); const new_part = hap_func.part.intersection(hap_val.part);
const new_value = hap_func.value(hap_val.value); if (new_part) {
const new_context = hap_val.combineContext(hap_func); const new_value = hap_func.value(hap_val.value);
const hap = new Hap(new_whole, new_part, new_value, new_context); const new_context = hap_val.combineContext(hap_func);
haps.push(hap); const hap = new Hap(new_whole, new_part, new_value, new_context);
haps.push(hap);
}
} }
} }
return haps; return haps;
@ -200,14 +202,16 @@ export class Pattern {
const query = function (state) { const query = function (state) {
const haps = []; const haps = [];
for (const hap_val of pat_val.query(state)) { for (const hap_val of pat_val.query(state)) {
const hap_funcs = pat_func.query(state.setSpan(hap_val.part)); const hap_funcs = pat_func.query(state.setSpan(hap_val.wholeOrPart()));
for (const hap_func of hap_funcs) { for (const hap_func of hap_funcs) {
const new_whole = hap_val.whole; const new_whole = hap_val.whole;
const new_part = hap_func.part.intersection_e(hap_val.part); const new_part = hap_func.part.intersection(hap_val.part);
const new_value = hap_func.value(hap_val.value); if (new_part) {
const new_context = hap_val.combineContext(hap_func); const new_value = hap_func.value(hap_val.value);
const hap = new Hap(new_whole, new_part, new_value, new_context); const new_context = hap_val.combineContext(hap_func);
haps.push(hap); const hap = new Hap(new_whole, new_part, new_value, new_context);
haps.push(hap);
}
} }
} }
return haps; return haps;
@ -558,7 +562,7 @@ export class Pattern {
} }
_segment(rate) { _segment(rate) {
return this.struct(pure(true).fast(rate)); return this.struct(pure(true)._fast(rate));
} }
invert() { invert() {

View File

@ -5,7 +5,7 @@ import { id } from './util.mjs';
export function steady(value) { export function steady(value) {
// A continuous value // A continuous value
return new Pattern((span) => Hap(undefined, span, value)); return new Pattern((state) => [new Hap(undefined, state.span, value)]);
} }
export const signal = (func) => { export const signal = (func) => {
@ -47,7 +47,7 @@ const timeToIntSeed = (x) => xorwise(Math.trunc(_frac(x / 300) * 536870912));
const intSeedToRand = (x) => (x % 536870912) / 536870912; const intSeedToRand = (x) => (x % 536870912) / 536870912;
const timeToRand = (x) => intSeedToRand(timeToIntSeed(x)); const timeToRand = (x) => Math.abs(intSeedToRand(timeToIntSeed(x)));
const timeToRandsPrime = (seed, n) => { const timeToRandsPrime = (seed, n) => {
const result = []; const result = [];
@ -60,8 +60,7 @@ const timeToRandsPrime = (seed, n) => {
const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n); const timeToRands = (t, n) => timeToRandsPrime(timeToIntSeed(t), n);
export const rand2 = signal(timeToRand); export const rand = signal(timeToRand);
export const rand = rand2.fmap(Math.abs);
export const _brandBy = (p) => rand.fmap((x) => x < p); export const _brandBy = (p) => rand.fmap((x) => x < p);
export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin(); export const brandBy = (pPat) => reify(pPat).fmap(_brandBy).innerJoin();
@ -71,14 +70,37 @@ export const _irand = (i) => rand.fmap((x) => Math.trunc(x * i));
export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin(); export const irand = (ipat) => reify(ipat).fmap(_irand).innerJoin();
export const chooseWith = (pat, xs) => { export const chooseWith = (pat, xs) => {
xs = xs.map(reify);
if (xs.length == 0) { if (xs.length == 0) {
return silence; return silence;
} }
return pat.range(0, xs.length).fmap((i) => xs[Math.floor(i)]); return pat.range(0, xs.length).fmap((i) => xs[Math.floor(i)]).outerJoin();
}; };
export const choose = (...xs) => chooseWith(rand, xs); export const choose = (...xs) => chooseWith(rand, xs);
const _wchooseWith = function (pat, ...pairs) {
const values = pairs.map((pair) => reify(pair[0]));
const weights = [];
let accum = 0;
for (const pair of pairs) {
accum += pair[1];
weights.push(accum);
}
const total = accum;
const match = function(r) {
const find = r * total;
return values[weights.findIndex((x) => x > find, weights)];
};
return pat.fmap(match);
};
const wchooseWith = (...args) => _wchooseWith(...args).outerJoin()
export const wchoose = (...pairs) => wchooseWith(rand, ...pairs);
export const wchooseCycles = (...pairs) => _wchooseWith(rand, ...pairs).innerJoin();
export const perlinWith = (pat) => { export const perlinWith = (pat) => {
const pata = pat.fmap(Math.floor); const pata = pat.fmap(Math.floor);
const patb = pat.fmap((t) => Math.floor(t) + 1); const patb = pat.fmap((t) => Math.floor(t) + 1);
@ -142,6 +164,24 @@ Pattern.prototype.sometimesPre = function (func) {
return this._sometimesByPre(0.5, func); return this._sometimesByPre(0.5, func);
}; };
Pattern.prototype._someCyclesBy = function (x, func) {
return stack(
this._degradeByWith(rand._segment(1), x),
func(this._degradeByWith(rand.fmap((r) => 1 - r)._segment(1), 1 - x)),
);
};
Pattern.prototype.someCyclesBy = function (patx, func) {
const pat = this;
return reify(patx)
.fmap((x) => pat._someCyclesBy(x, func))
.innerJoin();
};
Pattern.prototype.someCycles = function (func) {
return this._someCyclesBy(0.5, func);
};
Pattern.prototype.often = function (func) { Pattern.prototype.often = function (func) {
return this.sometimesBy(0.75, func); return this.sometimesBy(0.75, func);
}; };

View File

@ -36,6 +36,9 @@ import {
id, id,
ply, ply,
} from '../index.mjs'; } from '../index.mjs';
import { steady } from '../signal.mjs';
//import { Time } from 'tone'; //import { Time } from 'tone';
import pkg from 'tone'; import pkg from 'tone';
const { Time } = pkg; const { Time } = pkg;
@ -108,6 +111,18 @@ describe('Hap', function () {
assert.deepStrictEqual(state3, { incrementme: 12 }); assert.deepStrictEqual(state3, { incrementme: 12 });
}); });
}); });
describe('wholeOrPart()', () => {
const ts1 = new TimeSpan(Fraction(0), Fraction(1));
const ts0_5 = new TimeSpan(Fraction(0), Fraction(0.5));
const continuousHap = new Hap(undefined, ts1, 'hello');
const discreteHap = new Hap(ts1, ts0_5, 'hello');
it('Can pick a whole', () => {
assert.deepStrictEqual(discreteHap.wholeOrPart(), ts1);
});
it('Can pick a part', () => {
assert.deepStrictEqual(continuousHap.wholeOrPart(), ts1);
});
});
}); });
describe('Pattern', function () { describe('Pattern', function () {
@ -399,7 +414,7 @@ describe('Pattern', function () {
}); });
}); });
describe('struct()', function () { describe('struct()', function () {
it('Can restructure a pattern', function () { it('Can restructure a discrete pattern', function () {
assert.deepStrictEqual(sequence('a', 'b').struct(sequence(true, true, true)).firstCycle(), [ assert.deepStrictEqual(sequence('a', 'b').struct(sequence(true, true, true)).firstCycle(), [
hap(ts(0, third), ts(0, third), 'a'), hap(ts(0, third), ts(0, third), 'a'),
hap(ts(third, twothirds), ts(third, 0.5), 'a'), hap(ts(third, twothirds), ts(third, 0.5), 'a'),
@ -425,6 +440,9 @@ describe('Pattern', function () {
sequence('a', ['a', silence], 'a').firstCycle(), sequence('a', ['a', silence], 'a').firstCycle(),
); );
}); });
it('Can structure a continuous pattern', () => {
assert.deepStrictEqual(steady('a').struct(true, [true, true]).firstCycle(), sequence('a', ['a', 'a']).firstCycle());
});
}); });
describe('mask()', function () { describe('mask()', function () {
it('Can fragment a pattern', function () { it('Can fragment a pattern', function () {

View File

@ -81,8 +81,7 @@ export class TimeSpan {
// Like 'sect', but raises an exception if the timespans don't intersect. // Like 'sect', but raises an exception if the timespans don't intersect.
const result = this.intersection(other); const result = this.intersection(other);
if (result == undefined) { if (result == undefined) {
// TODO - raise exception throw 'TimeSpans do not intersect';
// raise ValueError(f'TimeSpan {self} and TimeSpan {other} do not intersect')
} }
return result; return result;
} }

View File

@ -21,6 +21,7 @@
"algorave" "algorave"
], ],
"author": "Felix Roos <flix91@gmail.com>", "author": "Felix Roos <flix91@gmail.com>",
"contributors": ["Alex McLean <alex@slab.org>"],
"license": "GPL-3.0-or-later", "license": "GPL-3.0-or-later",
"bugs": { "bugs": {
"url": "https://github.com/tidalcycles/strudel/issues" "url": "https://github.com/tidalcycles/strudel/issues"

View File

@ -1,6 +1,6 @@
{ {
"name": "@strudel.cycles/webaudio", "name": "@strudel.cycles/webaudio",
"version": "0.0.5", "version": "0.0.6",
"description": "Web Audio helpers for Strudel", "description": "Web Audio helpers for Strudel",
"main": "index.mjs", "main": "index.mjs",
"directories": { "directories": {

View File

@ -1,4 +1,5 @@
import ClockWorker from './clockworker.mjs'; import ClockWorker from './clockworker.mjs';
import { State, TimeSpan } from '@strudel.cycles/core';
class Scheduler { class Scheduler {
worker; worker;