Merge pull request #598 from tidalcycles/clip-support-floats

clip now works like legato in tidal
This commit is contained in:
Felix Roos 2023-06-23 09:55:18 +02:00 committed by GitHub
commit 7cfed80443
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 3365 additions and 3134 deletions

View File

@ -133,7 +133,7 @@ export class StrudelMirror {
this.code = initialCode; this.code = initialCode;
this.drawer = new Drawer((haps, time) => { this.drawer = new Drawer((haps, time) => {
const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.whole.end); const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped);
this.highlight(currentFrame); this.highlight(currentFrame);
onDraw?.(haps, time, currentFrame); onDraw?.(haps, time, currentFrame);
}, drawTime); }, drawTime);

View File

@ -222,6 +222,7 @@ const generic_params = [
* *
* @name legato * @name legato
* @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time * @param {number | Pattern} duration between 0 and 1, where 1 is the length of the whole hap time
* @noAutocomplete
* @example * @example
* "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>") * "c4 eb4 g4 bb4".legato("<0.125 .25 .5 .75 1 2 4>")
* *
@ -749,13 +750,14 @@ const generic_params = [
['val'], ['val'],
['cps'], ['cps'],
/** /**
* If set to 1, samples will be cut to the duration of their event. * Multiplies the duration with the given number. Also cuts samples off at the end if they exceed the duration.
* In tidal, this would be done with legato, which [is about to land in strudel too](https://github.com/tidalcycles/strudel/issues/111) * In tidal, this would be done with legato, [which has a complicated history in strudel](https://github.com/tidalcycles/strudel/issues/111).
* For now, if you're coming from tidal, just think clip = legato.
* *
* @name clip * @name clip
* @param {number | Pattern} active 1 or 0 * @param {number | Pattern} factor >= 0
* @example * @example
* note("c a f e ~").s("piano").clip(1) * note("c a f e").s("piano").clip("<.5 1 2>")
* *
*/ */
['clip'], ['clip'],

View File

@ -32,7 +32,11 @@ export class Hap {
} }
get duration() { get duration() {
return this.whole.end.sub(this.whole.begin); return this.whole.end.sub(this.whole.begin).mul(typeof this.value?.clip === 'number' ? this.value?.clip : 1);
}
get endClipped() {
return this.whole.begin.add(this.duration);
} }
wholeOrPart() { wholeOrPart() {

View File

@ -2053,7 +2053,7 @@ export const jux = register('jux', function (func, pat) {
* @example * @example
* "<0 [2 4]>" * "<0 [2 4]>"
* .echoWith(4, 1/8, (p,n) => p.add(n*2)) * .echoWith(4, 1/8, (p,n) => p.add(n*2))
* .scale('C minor').note().legato(.2) * .scale('C minor').note().clip(.2)
*/ */
export const { echoWith, echowith, stutWith, stutwith } = register( export const { echoWith, echowith, stutWith, stutwith } = register(
['echoWith', 'echowith', 'stutWith', 'stutwith'], ['echoWith', 'echowith', 'stutWith', 'stutwith'],
@ -2203,6 +2203,7 @@ export const velocity = register('velocity', function (velocity, pat) {
/** /**
* *
* Multiplies the hap duration with the given factor. * Multiplies the hap duration with the given factor.
* With samples, `clip` might be a better function to use ([more info](https://github.com/tidalcycles/strudel/pull/598))
* @name legato * @name legato
* @memberof Pattern * @memberof Pattern
* @example * @example

View File

@ -83,9 +83,9 @@ Pattern.prototype.pianoroll = function ({
ctx.fillRect(0, 0, w, h); ctx.fillRect(0, 0, w, h);
} }
const inFrame = (event) => const inFrame = (event) =>
(!hideNegative || event.whole.begin >= 0) && event.whole.begin <= t + to && event.whole.end >= t + from; (!hideNegative || event.whole.begin >= 0) && event.whole.begin <= t + to && event.endClipped >= t + from;
events.filter(inFrame).forEach((event) => { events.filter(inFrame).forEach((event) => {
const isActive = event.whole.begin <= t && event.whole.end > t; const isActive = event.whole.begin <= t && event.endClipped > t;
ctx.fillStyle = event.context?.color || inactive; ctx.fillStyle = event.context?.color || inactive;
ctx.strokeStyle = event.context?.color || active; ctx.strokeStyle = event.context?.color || active;
ctx.globalAlpha = event.context.velocity ?? event.value?.gain ?? 1; ctx.globalAlpha = event.context.velocity ?? event.value?.gain ?? 1;

View File

@ -27,7 +27,7 @@ export const isaw2 = isaw.toBipolar();
* *
* @return {Pattern} * @return {Pattern}
* @example * @example
* "c3 [eb3,g3] g2 [g3,bb3]".legato(saw.slow(4)).note() * "c3 [eb3,g3] g2 [g3,bb3]".note().clip(saw.slow(4))
* @example * @example
* saw.range(0,8).segment(8).scale('C major').slow(4).note() * saw.range(0,8).segment(8).scale('C major').slow(4).note()
* *

View File

@ -17,7 +17,7 @@ function useHighlighting({ view, pattern, active, getTime }) {
const begin = Math.max(lastEnd.current ?? audioTime, audioTime - 1 / 10, -0.01); // negative time seems buggy const begin = Math.max(lastEnd.current ?? audioTime, audioTime - 1 / 10, -0.01); // negative time seems buggy
const span = [round(begin), round(audioTime + 1 / 60)]; const span = [round(begin), round(audioTime + 1 / 60)];
lastEnd.current = span[1]; lastEnd.current = span[1];
highlights.current = highlights.current.filter((hap) => hap.whole.end > audioTime); // keep only highlights that are still active highlights.current = highlights.current.filter((hap) => hap.endClipped > audioTime); // keep only highlights that are still active
const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset()); const haps = pattern.queryArc(...span).filter((hap) => hap.hasOnset());
highlights.current = highlights.current.concat(haps); // add potential new onsets highlights.current = highlights.current.concat(haps); // add potential new onsets
view.dispatch({ effects: setHighlights.of({ haps: highlights.current }) }); // highlight all still active + new active haps view.dispatch({ effects: setHighlights.of({ haps: highlights.current }) }); // highlight all still active + new active haps

View File

@ -170,7 +170,7 @@ export async function onTriggerSample(t, value, onended, bank) {
nudge = 0, // TODO: is this in seconds? nudge = 0, // TODO: is this in seconds?
cut, cut,
loop, loop,
clip = 0, // if 1, samples will be cut off when the hap ends clip = undefined, // if 1, samples will be cut off when the hap ends
n = 0, n = 0,
note, note,
speed = 1, // sample playback speed speed = 1, // sample playback speed
@ -232,7 +232,7 @@ export async function onTriggerSample(t, value, onended, bank) {
out.disconnect(); out.disconnect();
onended(); onended();
}; };
const stop = (endTime, playWholeBuffer = !clip) => { const stop = (endTime, playWholeBuffer = clip === undefined) => {
let releaseTime = endTime; let releaseTime = endTime;
if (playWholeBuffer) { if (playWholeBuffer) {
releaseTime = t + (end - begin) * bufferDuration; releaseTime = t + (end - begin) * bufferDuration;

View File

@ -1079,22 +1079,22 @@ exports[`runs examples > example "chunkBack" example index 0 1`] = `
exports[`runs examples > example "clip" example index 0 1`] = ` exports[`runs examples > example "clip" example index 0 1`] = `
[ [
"[ 0/1 → 1/5 | note:c s:piano clip:1 ]", "[ 0/1 → 1/4 | note:c s:piano clip:0.5 ]",
"[ 1/5 → 2/5 | note:a s:piano clip:1 ]", "[ 1/4 → 1/2 | note:a s:piano clip:0.5 ]",
"[ 2/5 → 3/5 | note:f s:piano clip:1 ]", "[ 1/2 → 3/4 | note:f s:piano clip:0.5 ]",
"[ 3/5 → 4/5 | note:e s:piano clip:1 ]", "[ 3/4 → 1/1 | note:e s:piano clip:0.5 ]",
"[ 1/1 → 6/5 | note:c s:piano clip:1 ]", "[ 1/1 → 5/4 | note:c s:piano clip:1 ]",
"[ 6/5 → 7/5 | note:a s:piano clip:1 ]", "[ 5/4 → 3/2 | note:a s:piano clip:1 ]",
"[ 7/5 → 8/5 | note:f s:piano clip:1 ]", "[ 3/2 → 7/4 | note:f s:piano clip:1 ]",
"[ 8/5 → 9/5 | note:e s:piano clip:1 ]", "[ 7/4 → 2/1 | note:e s:piano clip:1 ]",
"[ 2/1 → 11/5 | note:c s:piano clip:1 ]", "[ 2/1 → 9/4 | note:c s:piano clip:2 ]",
"[ 11/5 → 12/5 | note:a s:piano clip:1 ]", "[ 9/4 → 5/2 | note:a s:piano clip:2 ]",
"[ 12/5 → 13/5 | note:f s:piano clip:1 ]", "[ 5/2 → 11/4 | note:f s:piano clip:2 ]",
"[ 13/5 → 14/5 | note:e s:piano clip:1 ]", "[ 11/4 → 3/1 | note:e s:piano clip:2 ]",
"[ 3/1 → 16/5 | note:c s:piano clip:1 ]", "[ 3/1 → 13/4 | note:c s:piano clip:0.5 ]",
"[ 16/5 → 17/5 | note:a s:piano clip:1 ]", "[ 13/4 → 7/2 | note:a s:piano clip:0.5 ]",
"[ 17/5 → 18/5 | note:f s:piano clip:1 ]", "[ 7/2 → 15/4 | note:f s:piano clip:0.5 ]",
"[ 18/5 → 19/5 | note:e s:piano clip:1 ]", "[ 15/4 → 4/1 | note:e s:piano clip:0.5 ]",
] ]
`; `;
@ -1588,42 +1588,42 @@ exports[`runs examples > example "echo" example index 0 1`] = `
exports[`runs examples > example "echoWith" example index 0 1`] = ` exports[`runs examples > example "echoWith" example index 0 1`] = `
[ [
"[ 0/1 → 1/5 | note:C3 ]", "[ 0/1 → 1/1 | note:C3 clip:0.2 ]",
"[ -3/8 ⇜ (0/1 → 1/40) ⇝ -11/40 | note:Bb3 ]", "[ -3/8 ⇜ (0/1 → 1/8) | note:Bb3 clip:0.2 ]",
"[ (1/8 → 3/10) ⇝ 13/40 | note:Eb3 ]", "[ (1/8 → 1/1) ⇝ 9/8 | note:Eb3 clip:0.2 ]",
"[ -1/4 ⇜ (0/1 → 1/20) ⇝ -3/20 | note:D4 ]", "[ -1/4 ⇜ (0/1 → 1/4) | note:D4 clip:0.2 ]",
"[ (1/4 → 2/5) ⇝ 9/20 | note:G3 ]", "[ (1/4 → 1/1) ⇝ 5/4 | note:G3 clip:0.2 ]",
"[ -1/8 ⇜ (0/1 → 3/40) ⇝ -1/40 | note:F4 ]", "[ -1/8 ⇜ (0/1 → 3/8) | note:F4 clip:0.2 ]",
"[ (3/8 → 1/2) ⇝ 23/40 | note:Bb3 ]", "[ (3/8 → 1/1) ⇝ 11/8 | note:Bb3 clip:0.2 ]",
"[ 1/1 → 11/10 | note:Eb3 ]", "[ 1/1 → 3/2 | note:Eb3 clip:0.2 ]",
"[ 3/2 → 8/5 | note:G3 ]", "[ 3/2 → 2/1 | note:G3 clip:0.2 ]",
"[ 1/8 ⇜ (1/1 → 41/40) ⇝ 13/40 | note:Eb3 ]", "[ 1/8 ⇜ (1/1 → 9/8) | note:Eb3 clip:0.2 ]",
"[ 9/8 → 49/40 | note:G3 ]", "[ 9/8 → 13/8 | note:G3 clip:0.2 ]",
"[ (13/8 → 17/10) ⇝ 69/40 | note:Bb3 ]", "[ (13/8 → 2/1) ⇝ 17/8 | note:Bb3 clip:0.2 ]",
"[ 1/4 ⇜ (1/1 → 21/20) ⇝ 9/20 | note:G3 ]", "[ 1/4 ⇜ (1/1 → 5/4) | note:G3 clip:0.2 ]",
"[ 5/4 → 27/20 | note:Bb3 ]", "[ 5/4 → 7/4 | note:Bb3 clip:0.2 ]",
"[ (7/4 → 9/5) ⇝ 37/20 | note:D4 ]", "[ (7/4 → 2/1) ⇝ 9/4 | note:D4 clip:0.2 ]",
"[ 3/8 ⇜ (1/1 → 43/40) ⇝ 23/40 | note:Bb3 ]", "[ 3/8 ⇜ (1/1 → 11/8) | note:Bb3 clip:0.2 ]",
"[ 11/8 → 59/40 | note:D4 ]", "[ 11/8 → 15/8 | note:D4 clip:0.2 ]",
"[ (15/8 → 19/10) ⇝ 79/40 | note:F4 ]", "[ (15/8 → 2/1) ⇝ 19/8 | note:F4 clip:0.2 ]",
"[ 2/1 → 11/5 | note:C3 ]", "[ 2/1 → 3/1 | note:C3 clip:0.2 ]",
"[ 13/8 ⇜ (2/1 → 81/40) ⇝ 69/40 | note:Bb3 ]", "[ 13/8 ⇜ (2/1 → 17/8) | note:Bb3 clip:0.2 ]",
"[ (17/8 → 23/10) ⇝ 93/40 | note:Eb3 ]", "[ (17/8 → 3/1) ⇝ 25/8 | note:Eb3 clip:0.2 ]",
"[ 7/4 ⇜ (2/1 → 41/20) ⇝ 37/20 | note:D4 ]", "[ 7/4 ⇜ (2/1 → 9/4) | note:D4 clip:0.2 ]",
"[ (9/4 → 12/5) ⇝ 49/20 | note:G3 ]", "[ (9/4 → 3/1) ⇝ 13/4 | note:G3 clip:0.2 ]",
"[ 15/8 ⇜ (2/1 → 83/40) ⇝ 79/40 | note:F4 ]", "[ 15/8 ⇜ (2/1 → 19/8) | note:F4 clip:0.2 ]",
"[ (19/8 → 5/2) ⇝ 103/40 | note:Bb3 ]", "[ (19/8 → 3/1) ⇝ 27/8 | note:Bb3 clip:0.2 ]",
"[ 3/1 → 31/10 | note:Eb3 ]", "[ 3/1 → 7/2 | note:Eb3 clip:0.2 ]",
"[ 7/2 → 18/5 | note:G3 ]", "[ 7/2 → 4/1 | note:G3 clip:0.2 ]",
"[ 17/8 ⇜ (3/1 → 121/40) ⇝ 93/40 | note:Eb3 ]", "[ 17/8 ⇜ (3/1 → 25/8) | note:Eb3 clip:0.2 ]",
"[ 25/8 → 129/40 | note:G3 ]", "[ 25/8 → 29/8 | note:G3 clip:0.2 ]",
"[ (29/8 → 37/10) ⇝ 149/40 | note:Bb3 ]", "[ (29/8 → 4/1) ⇝ 33/8 | note:Bb3 clip:0.2 ]",
"[ 9/4 ⇜ (3/1 → 61/20) ⇝ 49/20 | note:G3 ]", "[ 9/4 ⇜ (3/1 → 13/4) | note:G3 clip:0.2 ]",
"[ 13/4 → 67/20 | note:Bb3 ]", "[ 13/4 → 15/4 | note:Bb3 clip:0.2 ]",
"[ (15/4 → 19/5) ⇝ 77/20 | note:D4 ]", "[ (15/4 → 4/1) ⇝ 17/4 | note:D4 clip:0.2 ]",
"[ 19/8 ⇜ (3/1 → 123/40) ⇝ 103/40 | note:Bb3 ]", "[ 19/8 ⇜ (3/1 → 27/8) | note:Bb3 clip:0.2 ]",
"[ 27/8 → 139/40 | note:D4 ]", "[ 27/8 → 31/8 | note:D4 clip:0.2 ]",
"[ (31/8 → 39/10) ⇝ 159/40 | note:F4 ]", "[ (31/8 → 4/1) ⇝ 35/8 | note:F4 clip:0.2 ]",
] ]
`; `;
@ -3503,30 +3503,30 @@ exports[`runs examples > example "samples" example index 1 1`] = `
exports[`runs examples > example "saw" example index 0 1`] = ` exports[`runs examples > example "saw" example index 0 1`] = `
[ [
"[ 0/1 → 1/32 | note:c3 ]", "[ 0/1 → 1/4 | note:c3 clip:0.03125 ]",
"[ 1/4 → 9/32 | note:eb3 ]", "[ 1/4 → 1/2 | note:eb3 clip:0.09375 ]",
"[ 1/4 → 9/32 | note:g3 ]", "[ 1/4 → 1/2 | note:g3 clip:0.09375 ]",
"[ 1/2 → 17/32 | note:g2 ]", "[ 1/2 → 3/4 | note:g2 clip:0.15625 ]",
"[ 3/4 → 25/32 | note:g3 ]", "[ 3/4 → 1/1 | note:g3 clip:0.21875 ]",
"[ 3/4 → 25/32 | note:bb3 ]", "[ 3/4 → 1/1 | note:bb3 clip:0.21875 ]",
"[ 1/1 → 35/32 | note:c3 ]", "[ 1/1 → 5/4 | note:c3 clip:0.28125 ]",
"[ 5/4 → 43/32 | note:eb3 ]", "[ 5/4 → 3/2 | note:eb3 clip:0.34375 ]",
"[ 5/4 → 43/32 | note:g3 ]", "[ 5/4 → 3/2 | note:g3 clip:0.34375 ]",
"[ 3/2 → 51/32 | note:g2 ]", "[ 3/2 → 7/4 | note:g2 clip:0.40625 ]",
"[ 7/4 → 59/32 | note:g3 ]", "[ 7/4 → 2/1 | note:g3 clip:0.46875 ]",
"[ 7/4 → 59/32 | note:bb3 ]", "[ 7/4 → 2/1 | note:bb3 clip:0.46875 ]",
"[ 2/1 → 69/32 | note:c3 ]", "[ 2/1 → 9/4 | note:c3 clip:0.53125 ]",
"[ 9/4 → 77/32 | note:eb3 ]", "[ 9/4 → 5/2 | note:eb3 clip:0.59375 ]",
"[ 9/4 → 77/32 | note:g3 ]", "[ 9/4 → 5/2 | note:g3 clip:0.59375 ]",
"[ 5/2 → 85/32 | note:g2 ]", "[ 5/2 → 11/4 | note:g2 clip:0.65625 ]",
"[ 11/4 → 93/32 | note:g3 ]", "[ 11/4 → 3/1 | note:g3 clip:0.71875 ]",
"[ 11/4 → 93/32 | note:bb3 ]", "[ 11/4 → 3/1 | note:bb3 clip:0.71875 ]",
"[ 3/1 → 103/32 | note:c3 ]", "[ 3/1 → 13/4 | note:c3 clip:0.78125 ]",
"[ 13/4 → 111/32 | note:eb3 ]", "[ 13/4 → 7/2 | note:eb3 clip:0.84375 ]",
"[ 13/4 → 111/32 | note:g3 ]", "[ 13/4 → 7/2 | note:g3 clip:0.84375 ]",
"[ 7/2 → 119/32 | note:g2 ]", "[ 7/2 → 15/4 | note:g2 clip:0.90625 ]",
"[ 15/4 → 127/32 | note:g3 ]", "[ 15/4 → 4/1 | note:g3 clip:0.96875 ]",
"[ 15/4 → 127/32 | note:bb3 ]", "[ 15/4 → 4/1 | note:bb3 clip:0.96875 ]",
] ]
`; `;

File diff suppressed because it is too large Load Diff

View File

@ -221,7 +221,7 @@ export const testCycles = {
festivalOfFingers: 16, festivalOfFingers: 16,
festivalOfFingers2: 22, festivalOfFingers2: 22,
undergroundPlumber: 20, undergroundPlumber: 20,
bridgeIsOver: 16, bridgeIsOver: 8,
goodTimes: 16, goodTimes: 16,
echoPiano: 8, echoPiano: 8,
sml1: 48, sml1: 48,

View File

@ -364,7 +364,7 @@ export const customTrigger = `// licensed with CC BY-NC-SA 4.0 https://creativec
// by Felix Roos // by Felix Roos
stack( stack(
freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))), freq("55 [110,165] 110 [220,275]".mul("<1 <3/4 2/3>>").struct("x(3,8)").layer(x=>x.mul("1.006,.995"))),
freq("440(5,8)".legato(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8)) freq("440(5,8)".clip(.18).mul("<1 3/4 2 2/3>")).gain(perlin.range(.2,.8))
).s("<sawtooth square>/2") ).s("<sawtooth square>/2")
.onTrigger((t,hap,ct)=>{ .onTrigger((t,hap,ct)=>{
const ac = Tone.getContext().rawContext; const ac = Tone.getContext().rawContext;

View File

@ -38,6 +38,10 @@ Some of these have equivalent operators in the Mini Notation:
<JsDoc client:idle name="Pattern.legato" h={0} /> <JsDoc client:idle name="Pattern.legato" h={0} />
## clip
<JsDoc client:idle name="clip" h={0} />
## euclid ## euclid
<JsDoc client:idle name="Pattern.euclid" h={0} /> <JsDoc client:idle name="Pattern.euclid" h={0} />

View File

@ -118,7 +118,7 @@ const maxPan = noteToMidi('C8');
const panwidth = (pan, width) => pan * width + (1 - width) / 2; const panwidth = (pan, width) => pan * width + (1 - width) / 2;
Pattern.prototype.piano = function () { Pattern.prototype.piano = function () {
return this.clip(1) return this.fmap((v) => ({ ...v, clip: v.clip ?? 1 })) // set clip if not already set..
.s('piano') .s('piano')
.release(0.1) .release(0.1)
.fmap((value) => { .fmap((value) => {

View File

@ -205,27 +205,24 @@ samples({
} }
}, 'https://loophole-letters.vercel.app/') }, 'https://loophole-letters.vercel.app/')
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', cat('Db major','Db mixolydian')])
stack( stack(
s("<bd sn> <hh hh*2 hh*3>").color('#00B8D4'), s("<bd sn> <hh hh*2 hh*3>").color('#00B8D4'),
"<g4 c5 a4 [ab4 <eb5 f5>]>" "<g4 c5 a4 [ab4 <eb5 f5>]>"
.scale(scales) .scale("<C:major C:mixolydian F:lydian [F:minor <Db:major Db:mixolydian>]>")
.struct("x*8") .struct("x*8")
.scaleTranspose("0 [-5,-2] -7 [-9,-2]") .scaleTranspose("0 [-5,-2] -7 [-9,-2]")
.legato(.3)
.slow(2) .slow(2)
.note() .note()
.clip(.3)
.s('rhodes') .s('rhodes')
.clip(1)
.room(.5) .room(.5)
.delay(.3) .delay(.3)
.delayfeedback(.4) .delayfeedback(.4)
.delaytime(1/12).gain(.5).color('#7ED321'), .delaytime(1/12).gain(.5).color('#7ED321'),
"<c2 c3 f2 [[F2 C2] db2]>" "<c2 c3 f2 [[F2 C2] db2]>/2"
.legato("<1@3 [.3 1]>") .add("0,.02")
.slow(2).superimpose(x=>x.add(.02))
.note().gain(.3) .note().gain(.3)
.clip("<1@3 [.3 1]>/2")
.s('sawtooth').cutoff(600).color('#F8E71C'), .s('sawtooth').cutoff(600).color('#F8E71C'),
).fast(3/2) ).fast(3/2)
//.pianoroll({fold:1})`; //.pianoroll({fold:1})`;
@ -237,7 +234,7 @@ export const wavyKalimba = `// "Wavy kalimba"
samples({ samples({
'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' } 'kalimba': { c5:'https://freesound.org/data/previews/536/536549_11935698-lq.mp3' }
}) })
const scales = cat('C major', 'C mixolydian', 'F lydian', ['F minor', 'Db major']) const scales = "<C:major C:mixolydian F:lydian [F:minor Db:major]>"
stack( stack(
"[0 2 4 6 9 2 0 -2]*3" "[0 2 4 6 9 2 0 -2]*3"
@ -254,13 +251,11 @@ stack(
.velocity(0.8) .velocity(0.8)
.slow(2) .slow(2)
) )
.legato("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
.fast(1) .fast(1)
.note() .note()
.clip(1) .clip("<.4 .8 1 1.2 1.4 1.6 1.8 2>/8")
.s('kalimba') .s('kalimba')
.delay(.2) .delay(.2)`;
`;
export const festivalOfFingers = `// "Festival of fingers" export const festivalOfFingers = `// "Festival of fingers"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@ -293,19 +288,19 @@ stack(
s("<<bd*2 bd> sn> hh").fast(2).gain(.7), s("<<bd*2 bd> sn> hh").fast(2).gain(.7),
"[c2 a1 bb1 ~] ~" "[c2 a1 bb1 ~] ~"
.echo(2, 1/16, 1) .echo(2, 1/16, 1)
.legato(.4)
.slow(2) .slow(2)
.layer(h) .layer(h)
.note().s('square') .note().s('square')
.clip(.4)
.cutoff(400).decay(.12).sustain(0) .cutoff(400).decay(.12).sustain(0)
, ,
"[g2,[c3 eb3]]".iter(4) "[g2,[c3 eb3]]".iter(4)
.echoWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n))) .echoWith(4, 1/8, (x,n)=>x.transpose(n*12).velocity(Math.pow(.4,n)))
.legato(.1)
.layer(h).note() .layer(h).note()
.clip(.1)
) )
.fast(2/3) .fast(2/3)
.pianoroll({})`; .pianoroll()`;
export const bridgeIsOver = `// "Bridge is over" export const bridgeIsOver = `// "Bridge is over"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@ -314,19 +309,16 @@ export const bridgeIsOver = `// "Bridge is over"
samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'}) samples({mad:'https://freesound.org/data/previews/22/22274_109943-lq.mp3'})
stack( stack(
stack( stack(
"c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>".legato(".5 1".fast(2)).velocity(.8), note("c3*2 [[c3@1.4 bb2] ab2] gb2*2 <[[gb2@1.4 ab2] bb2] gb2>")
"0 ~".scale('c4 whole tone') .gain(.8).clip("[.5 1]*2"),
.euclidLegato(3,8).slow(2).mask("x ~") n("<0 1 2 3 4 3 2 1>")
.stutWith(8, 1/16, (x,n)=>x.scaleTranspose(n).velocity(Math.pow(.7,n))) .clip(.5)
.scaleTranspose("<0 1 2 3 4 3 2 1>") .echoWith(8, 1/32, (x,i)=>x.add(n(i)).velocity(Math.pow(.7,i)))
.fast(2) .scale('c4 whole tone')
.velocity(.7) .echo(3, 1/8, .5)
.legato(.5) ).piano(),
.stut(3, .5, 1/8)
).transpose(-1).note().piano(),
s("mad").slow(2) s("mad").slow(2)
).cpm(78).slow(4) ).cpm(78).slow(4)
.pianoroll() .pianoroll()
`; `;
@ -336,63 +328,39 @@ export const goodTimes = `// "Good times"
const scale = cat('C3 dorian','Bb2 major').slow(4); const scale = cat('C3 dorian','Bb2 major').slow(4);
stack( stack(
"2*4".add(12).scale(scale) n("2*4".add(12)).off(1/8, add(2))
.off(1/8, scaleTranspose("2")).fast(2)
.scaleTranspose("<0 1 2 1>").hush(),
"<0 1 2 3>(3,8,2)"
.scale(scale) .scale(scale)
.off(1/4, scaleTranspose("2,4")), .fast(2)
"<0 4>(5,8,-1)".scale(scale).transpose(-12) .add("<0 1 2 1>").hush(),
"<0 1 2 3>(3,8,2)".off(1/4, add("2,4"))
.n().scale(scale),
n("<0 4>(5,8,-1)").scale(scale).sub(note(12))
) )
.velocity(".6 .7".fast(4)) .velocity(".6 .7".fast(4))
.legato("2") .add(note(4))
.scaleTranspose("<0>".slow(4)) .piano()
.transpose(5) .clip(2)
.note().piano()
.velocity(.8) .velocity(.8)
.slow(2) .slow(2)
.pianoroll({maxMidi:100,minMidi:20})`; .pianoroll()`;
/* // new style notation:
export const goodTimes = `// licensed with CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// by Felix Roos
const scale = cat('C3 dorian','Bb2 major').slow(4);
stack(
n("2*4").add(12)
.off(1/8, add("2")).fast(2)
.add("<0 1 2 1>").hush(),
n("<0 1 2 3>(3,8,2)")
.off(1/4, add("2,4")),
n("<0 4>(5,8,-1)").sub(7)
)
.scale(scale)
.gain(".6 .7".fast(4))
.legato(2)
.add(note(5))
.piano()
.mul(gain(.8))
.slow(2)
.pianoroll({maxMidi:100,minMidi:20})`;
*/
export const echoPiano = `// "Echo piano" export const echoPiano = `// "Echo piano"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
"<0 2 [4 6](3,4,2) 3*2>" n("<0 2 [4 6](3,4,2) 3*2>").color('salmon')
.off(1/4, x=>x.add(2).color('green'))
.off(1/2, x=>x.add(6).color('steelblue'))
.scale('D minor') .scale('D minor')
.color('salmon')
.off(1/4, x=>x.scaleTranspose(2).color('green'))
.off(1/2, x=>x.scaleTranspose(6).color('steelblue'))
.legato(.5)
.echo(4, 1/8, .5) .echo(4, 1/8, .5)
.note().piano() .clip(.5)
.piano()
.pianoroll()`; .pianoroll()`;
export const sml1 = `// Hirokazu Tanaka - World 1-1 export const sml1 = `// Hirokazu Tanaka - World 1-1
stack( stack(
// melody // melody
\`< note(\`<
[e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [e5 f5] [g5 a5] [e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [e5 f5] [g5 a5]
[~ c5] [c5 d5] [e5 [c5@2 c5]] [~ c5] [f5 e5] [c5 d5] [~ g6] [g6 ~] [~ c5] [c5 d5] [e5 [c5@2 c5]] [~ c5] [f5 e5] [c5 d5] [~ g6] [g6 ~]
[e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [a5 g5] [c6 [e5@2 d5]] [e5 ~] [[d5@2 c5] [~@2 e5]] ~ [~ [c5@2 d5]] [e5 e5] [d5 c5] [a5 g5] [c6 [e5@2 d5]]
@ -401,28 +369,28 @@ stack(
[f5 ~] [[g5@2 f5] ~] [[e5 ~] [f5 ~]] [[f#5 ~] [g5 ~]] [f5 ~] [[g5@2 f5] ~] [[e5 ~] [f5 ~]] [[f#5 ~] [g5 ~]]
[~ a5] [b5 c6] [b5@2 ~@2 g5] ~ [~ a5] [b5 c6] [b5@2 ~@2 g5] ~
[eb6 d6] [~ c6] ~!2 [eb6 d6] [~ c6] ~!2
>\` >\`)
.legato(.95), .clip(.95),
// sub melody // sub melody
\`< note(\`<
[~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2 [~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2
[~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2 [~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2
[~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2 [~ g4]!2 [~ ab4]!2 [~ a4]!2 [~ bb4]!2
[~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2 [~ a4]!2 [~ g4]!2 [d4 e4] [f4 gb4] ~!2
[~ c5]!4 [~ a4]!2 [[c4 ~] [d4 ~]] [[eb4 ~] [e4 ~]] [~ c5]!4 [~ a4]!2 [[c4 ~] [d4 ~]] [[eb4 ~] [e4 ~]]
[~ c5]!4 [~ eb5]!2 [g4*2 [f4 ~]] [[e4 ~] [d4 ~]] [~ c5]!4 [~ eb5]!2 [g4*2 [f4 ~]] [[e4 ~] [d4 ~]]
>\`, >\`),
// bass // bass
\`< note(\`<
c3!7 a3 f3!2 c3!7 a3 f3!2
e3!2 ~!4 e3!2 ~!4
c3!7 a3 f3!2 c3!7 a3 f3!2
e3!2 ~!4 e3!2 ~!4
f3!2 e3!2 d3!2 ~!2 f3!2 e3!2 d3!2 ~!2
f3!2 e3!2 ab3!2 ~!2 f3!2 e3!2 ab3!2 ~!2
>\` >\`)
.legato(.5) .clip(.5)
).fast(2).note()`; ).fast(2)`;
export const randomBells = `// "Random bells" export const randomBells = `// "Random bells"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@ -438,16 +406,14 @@ stack(
"0".euclidLegato(3,8) "0".euclidLegato(3,8)
.echo(3, 1/16, .5) .echo(3, 1/16, .5)
.add(rand.range(0,12)) .add(rand.range(0,12))
.scale("D:minor:pentatonic").note()
.velocity(rand.range(.5,1)) .velocity(rand.range(.5,1))
.legato(rand.range(.4,3))
.scale(cat('D minor pentatonic')).note()
.s('bell').gain(.6).delay(.2).delaytime(1/3).delayfeedback(.8), .s('bell').gain(.6).delay(.2).delaytime(1/3).delayfeedback(.8),
// bass // bass
"<D2 A2 G2 F2>".euclidLegatoRot(6,8,4).note().s('bass').clip(1).gain(.8) note("<D2 A2 G2 F2>").euclidLegatoRot(6,8,4).s('bass').clip(1).gain(.8)
) )
.slow(6) .slow(6)
.pianoroll({minMidi:20,maxMidi:120,background:'transparent'}) .pianoroll({vertical:1})`;
`;
export const waa2 = `// "Waa2" export const waa2 = `// "Waa2"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
@ -460,7 +426,7 @@ n(
.off(1/8,x=>x.add(12)) .off(1/8,x=>x.add(12))
) )
.slow(2) .slow(2)
.legato(sine.range(0.3, 2).slow(28)) .clip(sine.range(0.3, 2).slow(28))
.s("sawtooth square".fast(2)) .s("sawtooth square".fast(2))
.cutoff(cosine.range(500,4000).slow(16)) .cutoff(cosine.range(500,4000).slow(16))
.gain(.5) .gain(.5)
@ -524,20 +490,22 @@ export const festivalOfFingers3 = `// "Festival of fingers 3"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/ // @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos // @by Felix Roos
"[-7*3],0,2,6,[8 7]" n("[-7*3],0,2,6,[8 7]")
.echoWith(4,1/4, (x,n)=>x .echoWith(
.add(n*7) 4, // echo 4 times
.velocity(1/(n+1)) 1/4, // 1/4s between echos
.legato(1/(n+1))) (x,i)=>x
.velocity(perlin.range(.5,.9).slow(8)) .add(n(i*7)) // add octaves
.stack("[22 25]*3" .gain(1/(i+1)) // reduce gain
.legato(sine.range(.5,2).slow(8)) .clip(1/(i+1))
.velocity(sine.range(.4,.8).slow(5)) )
.echo(4,1/12,.5)) .velocity(perlin.range(.5,.9).slow(8))
.scale(cat('D dorian','G mixolydian','C dorian','F mixolydian')) .stack(n("[22 25]*3")
.legato(1) .clip(sine.range(.5,2).slow(8))
.slow(2) .gain(sine.range(.4,.8).slow(5))
.note().piano() .echo(4,1/12,.5))
.scale("<D:dorian G:mixolydian C:dorian F:mixolydian>")
.slow(2).piano()
//.pianoroll({maxMidi:160})`; //.pianoroll({maxMidi:160})`;
export const meltingsubmarine = `// "Melting submarine" export const meltingsubmarine = `// "Melting submarine"
@ -897,9 +865,9 @@ stack(
, ,
note("<C2 A1 D2 F2>/2").ply(8).csound('Bass').gain("1 4 1 4") note("<C2 A1 D2 F2>/2").ply(8).csound('Bass').gain("1 4 1 4")
, ,
note("0 7 [4 3] 2".fast(2/3).off(".25 .125",add("<2 4 -3 -1>")) n("0 7 [4 3] 2".fast(2/3).off(".25 .125", add("<2 4 -3 -1>"))
.slow(2).scale('A4 minor')) .slow(2).scale('A4 minor'))
.legato(.25).csound('SynHarp') .clip(.25).csound('SynHarp')
, ,
s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909') s("bd*2,[~ hh]*2,~ cp").bank('RolandTR909')
)`; )`;
@ -910,15 +878,15 @@ export const arpoon = `// "Arpoon"
await samples('github:tidalcycles/Dirt-Samples/master') await samples('github:tidalcycles/Dirt-Samples/master')
"<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings('lefthand') note("<<Am7 C^7> C7 F^7 [Fm7 E7b9]>".voicings('lefthand'))
.arp("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).legato(2) .arp("[0,3] 2 [1,3] 2".fast(3).lastOf(4, fast(2))).clip(2)
.add(perlin.range(0,0.2)).sub("<0 -12>/8") .add(perlin.range(0,0.2).add("<0 12>/8").note())
.note().cutoff(perlin.range(500,4000)).resonance(12) .cutoff(perlin.range(500,4000)).resonance(12)
.gain("<.5 .8>*16") .gain("<.5 .8>*16")
.decay(.16).sustain(0.5) .decay(.16).sustain(0.5)
.delay(.2) .delay(.2)
.room(.5).pan(sine.range(.3,.6)) .room(.5).pan(sine.range(.3,.6))
.s('piano').clip(1) .s('piano')
.stack("<<A1 C2>!2 F2 [F2 E2]>".add.out("0 -5".fast(2)).add("0,.12").note().s('sawtooth').clip(1).cutoff(300)) .stack("<<A1 C2>!2 F2 [F2 E2]>".add.out("0 -5".fast(2)).add("0,.12").note().s('sawtooth').clip(1).cutoff(300))
.slow(4) .slow(4)
.stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").bank('RolandTR909').gain(.5).slow(2)) .stack(s("bd*4, [~ [hh hh? hh?]]*2,~ [sd ~ [sd:2? bd?]]").bank('RolandTR909').gain(.5).slow(2))