mirror of
https://github.com/eliasstepanik/strudel-docker.git
synced 2026-01-11 21:58:31 +00:00
Merge pull request #112 from tidalcycles/more-functions
`.brak()`, `.inside()` and `.outside()`
This commit is contained in:
commit
9588272639
@ -67,7 +67,7 @@ export class Pattern {
|
||||
* @param {Function} func the function to apply
|
||||
* @returns Pattern
|
||||
*/
|
||||
withQueryTime(func) {
|
||||
withQueryTime(func) {
|
||||
return new Pattern((state) => this.query(state.withSpan((span) => span.withTime(func))));
|
||||
}
|
||||
|
||||
@ -75,7 +75,7 @@ export class Pattern {
|
||||
* Similar to {@link Pattern#withQuerySpan|withQuerySpan}, but the function is applied to the timespans
|
||||
* of all haps returned by pattern queries (both `part` timespans, and where
|
||||
* present, `whole` timespans).
|
||||
* @param {Function} func
|
||||
* @param {Function} func
|
||||
* @returns Pattern
|
||||
*/
|
||||
withHapSpan(func) {
|
||||
@ -88,31 +88,31 @@ export class Pattern {
|
||||
* @param {Function} func the function to apply
|
||||
* @returns Pattern
|
||||
*/
|
||||
withHapTime(func) {
|
||||
withHapTime(func) {
|
||||
return this.withHapSpan((span) => span.withTime(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pattern with the given function applied to the list of haps returned by every query.
|
||||
* @param {Function} func
|
||||
* @param {Function} func
|
||||
* @returns Pattern
|
||||
*/
|
||||
_withHaps(func) {
|
||||
_withHaps(func) {
|
||||
return new Pattern((state) => func(this.query(state)));
|
||||
}
|
||||
|
||||
/**
|
||||
* As with {@link Pattern#_withHaps}, but applies the function to every hap, rather than every list of haps.
|
||||
* @param {Function} func
|
||||
* @param {Function} func
|
||||
* @returns Pattern
|
||||
*/
|
||||
_withHap(func) {
|
||||
_withHap(func) {
|
||||
return this._withHaps((haps) => haps.map(func));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pattern with the context field set to every hap set to the given value.
|
||||
* @param {*} context
|
||||
* @param {*} context
|
||||
* @returns Pattern
|
||||
*/
|
||||
_setContext(context) {
|
||||
@ -121,7 +121,7 @@ export class Pattern {
|
||||
|
||||
/**
|
||||
* Returns a new pattern with the given function applied to the context field of every hap.
|
||||
* @param {Function} func
|
||||
* @param {Function} func
|
||||
* @returns Pattern
|
||||
*/
|
||||
_withContext(func) {
|
||||
@ -129,7 +129,7 @@ export class Pattern {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pattern with the context field of every hap set to an empty object.
|
||||
* Returns a new pattern with the context field of every hap set to an empty object.
|
||||
* @returns Pattern
|
||||
*/
|
||||
_stripContext() {
|
||||
@ -139,8 +139,8 @@ export class Pattern {
|
||||
/**
|
||||
* Returns a new pattern with the given location information added to the
|
||||
* context of every hap.
|
||||
* @param {Number} start
|
||||
* @param {Number} end
|
||||
* @param {Number} start
|
||||
* @param {Number} end
|
||||
* @returns Pattern
|
||||
*/
|
||||
withLocation(start, end) {
|
||||
@ -183,7 +183,7 @@ export class Pattern {
|
||||
/**
|
||||
* Returns a new pattern, with the function applied to the value of
|
||||
* each hap. It has the alias {@link Pattern#fmap|fmap}.
|
||||
* @param {Function} func
|
||||
* @param {Function} func
|
||||
* @returns Pattern
|
||||
*/
|
||||
withValue(func) {
|
||||
@ -193,7 +193,7 @@ export class Pattern {
|
||||
/**
|
||||
* see {@link Pattern#withValue|withValue}
|
||||
*/
|
||||
fmap(func) {
|
||||
fmap(func) {
|
||||
return this.withValue(func);
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ export class Pattern {
|
||||
/**
|
||||
* As with {@link Pattern#_filterHaps}, but the function is applied to values
|
||||
* inside haps.
|
||||
* @param {Function} value_test
|
||||
* @param {Function} value_test
|
||||
* @returns Pattern
|
||||
*/
|
||||
_filterValues(value_test) {
|
||||
@ -231,7 +231,7 @@ export class Pattern {
|
||||
* as its `part` timespan.
|
||||
* @returns Pattern
|
||||
*/
|
||||
onsetsOnly() {
|
||||
onsetsOnly() {
|
||||
// Returns a new pattern that will only return haps where the start
|
||||
// of the 'whole' timespan matches the start of the 'part'
|
||||
// timespan, i.e. the haps that include their 'onset'.
|
||||
@ -278,12 +278,12 @@ export class Pattern {
|
||||
/**
|
||||
* When this method is called on a pattern of functions, it matches its haps
|
||||
* with those in the given pattern of values. A new pattern is returned, with
|
||||
* each matching value applied to the corresponding function.
|
||||
* each matching value applied to the corresponding function.
|
||||
*
|
||||
* In this `appBoth` variant, where timespans of the function and value haps
|
||||
* are not the same but do intersect, the resulting hap has a timespan of the
|
||||
* intersection. This applies to both the part and the whole timespan.
|
||||
* @param {Pattern} pat_val
|
||||
* @param {Pattern} pat_val
|
||||
* @returns Pattern
|
||||
*/
|
||||
appBoth(pat_val) {
|
||||
@ -303,7 +303,7 @@ export class Pattern {
|
||||
* on. In practice, this means that the pattern structure, including onsets,
|
||||
* are preserved from the pattern of functions (often referred to as the left
|
||||
* hand or inner pattern).
|
||||
* @param {Pattern} pat_val
|
||||
* @param {Pattern} pat_val
|
||||
* @returns Pattern
|
||||
*/
|
||||
appLeft(pat_val) {
|
||||
@ -333,7 +333,7 @@ export class Pattern {
|
||||
* As with {@link Pattern#appLeft|appLeft}, but `whole` timespans are instead taken from the
|
||||
* pattern of values, i.e. structure is preserved from the right hand/outer
|
||||
* pattern.
|
||||
* @param {Pattern} pat_val
|
||||
* @param {Pattern} pat_val
|
||||
* @returns Pattern
|
||||
*/
|
||||
appRight(pat_val) {
|
||||
@ -696,6 +696,14 @@ export class Pattern {
|
||||
return this._fast(Fraction(1).div(factor));
|
||||
}
|
||||
|
||||
_inside(factor, f) {
|
||||
return f(this._slow(factor))._fast(factor);
|
||||
}
|
||||
|
||||
_outside(factor, f) {
|
||||
return f(this._fast(factor))._slow(factor);
|
||||
}
|
||||
|
||||
_ply(factor) {
|
||||
return this.fmap((x) => pure(x)._fast(factor))._squeezeJoin();
|
||||
}
|
||||
@ -822,6 +830,16 @@ export class Pattern {
|
||||
return slowcatPrime(...pats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new pattern where every other cycle is played once, twice as
|
||||
* fast, and offset in time by one quarter of a cycle. Creates a kind of
|
||||
* breakbeat feel.
|
||||
* @returns Pattern
|
||||
*/
|
||||
brak() {
|
||||
return this.when(slowcat(false, true), (x) => fastcat(x, silence)._late(0.25));
|
||||
}
|
||||
|
||||
rev() {
|
||||
const pat = this;
|
||||
const query = function (state) {
|
||||
@ -979,7 +997,7 @@ function _composeOp(a, b, func) {
|
||||
}
|
||||
|
||||
// Make composers
|
||||
(function() {
|
||||
(function () {
|
||||
const num = (pat) => pat._asNumber();
|
||||
const numOrString = (pat) => pat._asNumber(false, true);
|
||||
|
||||
@ -1390,6 +1408,14 @@ Pattern.prototype.compress = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._compress)(...args, this);
|
||||
};
|
||||
Pattern.prototype.outside = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._outside)(...args, this);
|
||||
};
|
||||
Pattern.prototype.inside = function (...args) {
|
||||
args = args.map(reify);
|
||||
return patternify2(Pattern.prototype._inside)(...args, this);
|
||||
};
|
||||
|
||||
// call this after all Patter.prototype.define calls have been executed! (right before evaluate)
|
||||
Pattern.prototype.bootstrap = function () {
|
||||
|
||||
@ -41,6 +41,7 @@ import {
|
||||
tri2,
|
||||
id,
|
||||
ply,
|
||||
rev
|
||||
} from '../index.mjs';
|
||||
|
||||
import { steady } from '../signal.mjs';
|
||||
@ -277,10 +278,7 @@ describe('Pattern', function () {
|
||||
);
|
||||
});
|
||||
it('can SqueezeOut() structure', () => {
|
||||
sameFirst(
|
||||
sequence(1, [2, 3]).keepifSqueezeOut(true, true, false),
|
||||
sequence([1, [2, 3]], [1, [2, 3]], silence),
|
||||
);
|
||||
sameFirst(sequence(1, [2, 3]).keepifSqueezeOut(true, true, false), sequence([1, [2, 3]], [1, [2, 3]], silence));
|
||||
});
|
||||
});
|
||||
describe('sub()', function () {
|
||||
@ -439,6 +437,20 @@ describe('Pattern', function () {
|
||||
// mini('eb3 [c3 g3]/2 ') always plays [c3 g3]
|
||||
});
|
||||
});
|
||||
describe('inside', () => {
|
||||
it('can rev inside a cycle', () => {
|
||||
sameFirst(sequence('a', 'b', 'c', 'd').inside(2, rev),
|
||||
sequence('b', 'a', 'd', 'c')
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('outside', () => {
|
||||
it('can rev outside a cycle', () => {
|
||||
sameFirst(sequence('a', 'b', 'c', 'd')._slow(2).outside(2, rev),
|
||||
sequence('d', 'c')
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('_filterValues()', function () {
|
||||
it('Filters true', function () {
|
||||
assert.equal(
|
||||
@ -589,6 +601,11 @@ describe('Pattern', function () {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('brak()', () => {
|
||||
it('Can make something a bit breakbeaty', () => {
|
||||
sameFirst(sequence('a', 'b').brak()._fast(2), sequence('a', 'b', fastcat(silence, 'a'), fastcat('b', silence)));
|
||||
});
|
||||
});
|
||||
describe('timeCat()', function () {
|
||||
it('Can concatenate patterns with different relative durations', function () {
|
||||
assert.deepStrictEqual(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user