Merge branch 'main' of github.com:yaxu/strudel into main
This commit is contained in:
commit
92a7d81063
9 changed files with 120 additions and 7 deletions
|
|
@ -4,6 +4,7 @@ import {isNote, toMidi} from "./util.js";
|
||||||
const removeUndefineds = (xs) => xs.filter((x) => x != void 0);
|
const removeUndefineds = (xs) => xs.filter((x) => x != void 0);
|
||||||
const flatten = (arr) => [].concat(...arr);
|
const flatten = (arr) => [].concat(...arr);
|
||||||
const id = (a) => a;
|
const id = (a) => a;
|
||||||
|
const range = (min, max) => Array.from({length: max - min + 1}, (_, i) => i + min);
|
||||||
export function curry(func, overload) {
|
export function curry(func, overload) {
|
||||||
const fn = function curried(...args) {
|
const fn = function curried(...args) {
|
||||||
if (args.length >= func.length) {
|
if (args.length >= func.length) {
|
||||||
|
|
@ -443,6 +444,9 @@ class Pattern {
|
||||||
_slow(factor) {
|
_slow(factor) {
|
||||||
return this._fast(Fraction(1).div(factor));
|
return this._fast(Fraction(1).div(factor));
|
||||||
}
|
}
|
||||||
|
_cpm(cpm) {
|
||||||
|
return this._fast(cpm / 60);
|
||||||
|
}
|
||||||
_early(offset) {
|
_early(offset) {
|
||||||
offset = Fraction(offset);
|
offset = Fraction(offset);
|
||||||
return this.withQueryTime((t) => t.add(offset)).withEventTime((t) => t.sub(offset));
|
return this.withQueryTime((t) => t.add(offset)).withEventTime((t) => t.sub(offset));
|
||||||
|
|
@ -526,6 +530,15 @@ class Pattern {
|
||||||
superimpose(...funcs) {
|
superimpose(...funcs) {
|
||||||
return this.stack(...funcs.map((func) => func(this)));
|
return this.stack(...funcs.map((func) => func(this)));
|
||||||
}
|
}
|
||||||
|
stutWith(times, time, func) {
|
||||||
|
return stack(...range(0, times - 1).map((i) => func(this.late(i * time), i)));
|
||||||
|
}
|
||||||
|
stut(times, feedback, time) {
|
||||||
|
return this.stutWith(times, time, (pat, i) => pat.velocity(Math.pow(feedback, i)));
|
||||||
|
}
|
||||||
|
iter(times) {
|
||||||
|
return slowcat(...range(0, times - 1).map((i) => this.early(i / times)));
|
||||||
|
}
|
||||||
edit(...funcs) {
|
edit(...funcs) {
|
||||||
return stack(...funcs.map((func) => func(this)));
|
return stack(...funcs.map((func) => func(this)));
|
||||||
}
|
}
|
||||||
|
|
@ -549,7 +562,7 @@ class Pattern {
|
||||||
return this._withContext((context) => ({...context, velocity: (context.velocity || 1) * velocity}));
|
return this._withContext((context) => ({...context, velocity: (context.velocity || 1) * velocity}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pattern.prototype.patternified = ["apply", "fast", "slow", "early", "late", "duration", "legato", "velocity", "segment"];
|
Pattern.prototype.patternified = ["apply", "fast", "slow", "cpm", "early", "late", "duration", "legato", "velocity", "segment"];
|
||||||
Pattern.prototype.factories = {pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr};
|
Pattern.prototype.factories = {pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr};
|
||||||
const silence = new Pattern((_) => []);
|
const silence = new Pattern((_) => []);
|
||||||
function pure(value) {
|
function pure(value) {
|
||||||
|
|
@ -771,5 +784,7 @@ export {
|
||||||
struct,
|
struct,
|
||||||
mask,
|
mask,
|
||||||
invert,
|
invert,
|
||||||
inv
|
inv,
|
||||||
|
id,
|
||||||
|
range
|
||||||
};
|
};
|
||||||
|
|
|
||||||
1
docs/dist/pianoroll.js
vendored
1
docs/dist/pianoroll.js
vendored
|
|
@ -18,6 +18,7 @@ Pattern.prototype.pianoroll = function({
|
||||||
events.forEach((event) => {
|
events.forEach((event) => {
|
||||||
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
||||||
ctx.fillStyle = isActive ? active : inactive;
|
ctx.fillStyle = isActive ? active : inactive;
|
||||||
|
ctx.globalAlpha = event.context.velocity ?? 1;
|
||||||
const x = Math.round(event.whole.begin / timeframe * w);
|
const x = Math.round(event.whole.begin / timeframe * w);
|
||||||
const width = Math.round((event.whole.end - event.whole.begin) / timeframe * w);
|
const width = Math.round((event.whole.end - event.whole.begin) / timeframe * w);
|
||||||
const y = Math.round(h - (Number(event.value) - minMidi) / midiRange * h);
|
const y = Math.round(h - (Number(event.value) - minMidi) / midiRange * h);
|
||||||
|
|
|
||||||
24
docs/dist/tunes.js
vendored
24
docs/dist/tunes.js
vendored
|
|
@ -560,3 +560,27 @@ stack(
|
||||||
.legato(cosine.struct("x*8").add(4/5).mul(4/5).fast(8))
|
.legato(cosine.struct("x*8").add(4/5).mul(4/5).fast(8))
|
||||||
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
||||||
.tone((await piano()).chain(out())).fast(3/4)`;
|
.tone((await piano()).chain(out())).fast(3/4)`;
|
||||||
|
export const undergroundPlumber = `backgroundImage('https://images.nintendolife.com/news/2016/08/video_exploring_the_funky_inspiration_for_the_super_mario_bros_underground_theme/large.jpg',{
|
||||||
|
className:'darken'
|
||||||
|
})
|
||||||
|
const drums = await players({
|
||||||
|
bd: 'bd/BT0A0D0.wav',
|
||||||
|
sn: 'sn/ST0T0S3.wav',
|
||||||
|
hh: 'hh/000_hh3closedhh.wav',
|
||||||
|
cp: 'cp/HANDCLP0.wav',
|
||||||
|
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
||||||
|
stack(
|
||||||
|
"<<bd*2 bd> sn> hh".fast(4).slow(2).tone(drums.chain(vol(.5),out())),
|
||||||
|
stack(
|
||||||
|
"[c2 a1 bb1 ~] ~"
|
||||||
|
.stut(2, .6, 1/16)
|
||||||
|
.legato(.4)
|
||||||
|
.slow(2)
|
||||||
|
.tone(synth({...osc('sawtooth7'),...adsr(0,.3,0)}).chain(out())),
|
||||||
|
"[g2,[c3 eb3]]".iter(4)
|
||||||
|
.stutWith(4, 1/4, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
|
||||||
|
.legato(.1)
|
||||||
|
)
|
||||||
|
.transpose("<0@2 5 0 7 5 0 -5>/2")
|
||||||
|
.pianoroll({minMidi:21,maxMidi:180, background:'transparent',inactive:'#3F8F90',active:'#DE3123'})
|
||||||
|
)`;
|
||||||
|
|
|
||||||
|
|
@ -42144,6 +42144,10 @@ parcelHelpers.export(exports, "invert", ()=>invert
|
||||||
);
|
);
|
||||||
parcelHelpers.export(exports, "inv", ()=>inv
|
parcelHelpers.export(exports, "inv", ()=>inv
|
||||||
);
|
);
|
||||||
|
parcelHelpers.export(exports, "id", ()=>id
|
||||||
|
);
|
||||||
|
parcelHelpers.export(exports, "range", ()=>range
|
||||||
|
);
|
||||||
var _fractionMjs = require("./fraction.mjs");
|
var _fractionMjs = require("./fraction.mjs");
|
||||||
var _fractionMjsDefault = parcelHelpers.interopDefault(_fractionMjs);
|
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
|
||||||
|
|
@ -42156,6 +42160,11 @@ const flatten = (arr)=>[].concat(...arr)
|
||||||
;
|
;
|
||||||
const id = (a)=>a
|
const id = (a)=>a
|
||||||
;
|
;
|
||||||
|
const range = (min, max)=>Array.from({
|
||||||
|
length: max - min + 1
|
||||||
|
}, (_, i)=>i + min
|
||||||
|
)
|
||||||
|
;
|
||||||
function curry(func, overload) {
|
function curry(func, overload) {
|
||||||
const fn = function curried(...args) {
|
const fn = function curried(...args) {
|
||||||
if (args.length >= func.length) return func.apply(this, args);
|
if (args.length >= func.length) return func.apply(this, args);
|
||||||
|
|
@ -42706,6 +42715,10 @@ class Pattern {
|
||||||
_slow(factor) {
|
_slow(factor) {
|
||||||
return this._fast(_fractionMjsDefault.default(1).div(factor));
|
return this._fast(_fractionMjsDefault.default(1).div(factor));
|
||||||
}
|
}
|
||||||
|
// cpm = cycles per minute
|
||||||
|
_cpm(cpm) {
|
||||||
|
return this._fast(cpm / 60);
|
||||||
|
}
|
||||||
_early(offset) {
|
_early(offset) {
|
||||||
// Equivalent of Tidal's <~ operator
|
// Equivalent of Tidal's <~ operator
|
||||||
offset = _fractionMjsDefault.default(offset);
|
offset = _fractionMjsDefault.default(offset);
|
||||||
|
|
@ -42818,6 +42831,18 @@ class Pattern {
|
||||||
return this.stack(...funcs.map((func)=>func(this)
|
return this.stack(...funcs.map((func)=>func(this)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
stutWith(times, time, func) {
|
||||||
|
return stack(...range(0, times - 1).map((i)=>func(this.late(i * time), i)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
stut(times, feedback, time) {
|
||||||
|
return this.stutWith(times, time, (pat, i)=>pat.velocity(Math.pow(feedback, i))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
iter(times) {
|
||||||
|
return slowcat(...range(0, times - 1).map((i)=>this.early(i / times)
|
||||||
|
));
|
||||||
|
}
|
||||||
edit(...funcs) {
|
edit(...funcs) {
|
||||||
return stack(...funcs.map((func)=>func(this)
|
return stack(...funcs.map((func)=>func(this)
|
||||||
));
|
));
|
||||||
|
|
@ -42855,6 +42880,7 @@ Pattern.prototype.patternified = [
|
||||||
'apply',
|
'apply',
|
||||||
'fast',
|
'fast',
|
||||||
'slow',
|
'slow',
|
||||||
|
'cpm',
|
||||||
'early',
|
'early',
|
||||||
'late',
|
'late',
|
||||||
'duration',
|
'duration',
|
||||||
|
|
@ -136401,6 +136427,7 @@ _strudelMjs.Pattern.prototype.pianoroll = function({ timeframe =10 , inactive ='
|
||||||
events.forEach((event)=>{
|
events.forEach((event)=>{
|
||||||
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
||||||
ctx.fillStyle = isActive ? active : inactive;
|
ctx.fillStyle = isActive ? active : inactive;
|
||||||
|
ctx.globalAlpha = event.context.velocity ?? 1;
|
||||||
const x = Math.round(event.whole.begin / timeframe * w);
|
const x = Math.round(event.whole.begin / timeframe * w);
|
||||||
const width = Math.round((event.whole.end - event.whole.begin) / timeframe * w);
|
const width = Math.round((event.whole.end - event.whole.begin) / timeframe * w);
|
||||||
const y = Math.round(h - (Number(event.value) - minMidi) / midiRange * h);
|
const y = Math.round(h - (Number(event.value) - minMidi) / midiRange * h);
|
||||||
|
|
@ -183306,4 +183333,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.7cec804e.js.map
|
//# sourceMappingURL=index.74a36131.js.map
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -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.7cec804e.js" defer=""></script>
|
<script src="/tutorial/index.74a36131.js" defer=""></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ Pattern.prototype.pianoroll = function ({
|
||||||
events.forEach((event) => {
|
events.forEach((event) => {
|
||||||
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
const isActive = event.whole.begin <= t && event.whole.end >= t;
|
||||||
ctx.fillStyle = isActive ? active : inactive;
|
ctx.fillStyle = isActive ? active : inactive;
|
||||||
|
ctx.globalAlpha = event.context.velocity ?? 1;
|
||||||
const x = Math.round((event.whole.begin / timeframe) * w);
|
const x = Math.round((event.whole.begin / timeframe) * w);
|
||||||
const width = Math.round(((event.whole.end - event.whole.begin) / timeframe) * w);
|
const width = Math.round(((event.whole.end - event.whole.begin) / timeframe) * w);
|
||||||
const y = Math.round(h - ((Number(event.value) - minMidi) / midiRange) * h);
|
const y = Math.round(h - ((Number(event.value) - minMidi) / midiRange) * h);
|
||||||
|
|
|
||||||
|
|
@ -593,3 +593,29 @@ stack(
|
||||||
.legato(cosine.struct("x*8").add(4/5).mul(4/5).fast(8))
|
.legato(cosine.struct("x*8").add(4/5).mul(4/5).fast(8))
|
||||||
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
.velocity(sine.struct("x*8").add(3/5).mul(2/5).fast(8))
|
||||||
.tone((await piano()).chain(out())).fast(3/4)`;
|
.tone((await piano()).chain(out())).fast(3/4)`;
|
||||||
|
|
||||||
|
// iter, stut, stutWith
|
||||||
|
export const undergroundPlumber = `backgroundImage('https://images.nintendolife.com/news/2016/08/video_exploring_the_funky_inspiration_for_the_super_mario_bros_underground_theme/large.jpg',{
|
||||||
|
className:'darken'
|
||||||
|
})
|
||||||
|
const drums = await players({
|
||||||
|
bd: 'bd/BT0A0D0.wav',
|
||||||
|
sn: 'sn/ST0T0S3.wav',
|
||||||
|
hh: 'hh/000_hh3closedhh.wav',
|
||||||
|
cp: 'cp/HANDCLP0.wav',
|
||||||
|
}, 'https://loophole-letters.vercel.app/samples/tidal/')
|
||||||
|
stack(
|
||||||
|
"<<bd*2 bd> sn> hh".fast(4).slow(2).tone(drums.chain(vol(.5),out())),
|
||||||
|
stack(
|
||||||
|
"[c2 a1 bb1 ~] ~"
|
||||||
|
.stut(2, .6, 1/16)
|
||||||
|
.legato(.4)
|
||||||
|
.slow(2)
|
||||||
|
.tone(synth({...osc('sawtooth7'),...adsr(0,.3,0)}).chain(out())),
|
||||||
|
"[g2,[c3 eb3]]".iter(4)
|
||||||
|
.stutWith(4, 1/4, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
|
||||||
|
.legato(.1)
|
||||||
|
)
|
||||||
|
.transpose("<0@2 5 0 7 5 0 -5>/2")
|
||||||
|
.pianoroll({minMidi:21,maxMidi:180, background:'transparent',inactive:'#3F8F90',active:'#DE3123'})
|
||||||
|
)`;
|
||||||
|
|
|
||||||
23
strudel.mjs
23
strudel.mjs
|
|
@ -9,6 +9,8 @@ const flatten = arr => [].concat(...arr)
|
||||||
|
|
||||||
const id = a => a
|
const id = a => a
|
||||||
|
|
||||||
|
const range = (min, max) => Array.from({ length: max - min + 1 }, (_, i) => i + min);
|
||||||
|
|
||||||
export function curry(func, overload) {
|
export function curry(func, overload) {
|
||||||
const fn = function curried(...args) {
|
const fn = function curried(...args) {
|
||||||
if (args.length >= func.length) {
|
if (args.length >= func.length) {
|
||||||
|
|
@ -605,6 +607,11 @@ class Pattern {
|
||||||
return this._fast(Fraction(1).div(factor))
|
return this._fast(Fraction(1).div(factor))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cpm = cycles per minute
|
||||||
|
_cpm(cpm) {
|
||||||
|
return this._fast(cpm / 60);
|
||||||
|
}
|
||||||
|
|
||||||
_early(offset) {
|
_early(offset) {
|
||||||
// Equivalent of Tidal's <~ operator
|
// Equivalent of Tidal's <~ operator
|
||||||
offset = Fraction(offset)
|
offset = Fraction(offset)
|
||||||
|
|
@ -713,6 +720,18 @@ class Pattern {
|
||||||
return this.stack(...funcs.map((func) => func(this)));
|
return this.stack(...funcs.map((func) => func(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stutWith(times, time, func) {
|
||||||
|
return stack(...range(0, times - 1).map((i) => func(this.late(i * time), i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
stut(times, feedback, time) {
|
||||||
|
return this.stutWith(times, time, (pat, i) => pat.velocity(Math.pow(feedback, i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
iter(times) {
|
||||||
|
return slowcat(...range(0, times - 1).map((i) => this.early(i/times)));
|
||||||
|
}
|
||||||
|
|
||||||
edit(...funcs) {
|
edit(...funcs) {
|
||||||
return stack(...funcs.map(func => func(this)));
|
return stack(...funcs.map(func => func(this)));
|
||||||
}
|
}
|
||||||
|
|
@ -745,7 +764,7 @@ class Pattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods of Pattern that get callable factories
|
// methods of Pattern that get callable factories
|
||||||
Pattern.prototype.patternified = ['apply', 'fast', 'slow', 'early', 'late', 'duration', 'legato', 'velocity', 'segment'];
|
Pattern.prototype.patternified = ['apply', 'fast', 'slow', 'cpm', 'early', 'late', 'duration', 'legato', 'velocity', 'segment'];
|
||||||
// methods that create patterns, which are added to patternified Pattern methods
|
// 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};
|
Pattern.prototype.factories = { pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr};
|
||||||
// the magic happens in Pattern constructor. Keeping this in prototype enables adding methods from the outside (e.g. see tonal.ts)
|
// the magic happens in Pattern constructor. Keeping this in prototype enables adding methods from the outside (e.g. see tonal.ts)
|
||||||
|
|
@ -1023,6 +1042,6 @@ export {Fraction, TimeSpan, Hap, Pattern,
|
||||||
pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr, reify, silence,
|
pure, stack, slowcat, fastcat, cat, timeCat, sequence, polymeter, pm, polyrhythm, pr, reify, silence,
|
||||||
fast, slow, early, late, rev,
|
fast, slow, early, late, rev,
|
||||||
add, sub, mul, div, union, every, when, off, jux, append, superimpose,
|
add, sub, mul, div, union, every, when, off, jux, append, superimpose,
|
||||||
struct, mask, invert, inv,
|
struct, mask, invert, inv, id, range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue