Compare commits

..

2 Commits

Author SHA1 Message Date
Felix Roos 50f04e8cc8 fix: echoWith / echoForEach in tests 2025-09-15 22:57:18 +02:00
Felix Roos 5e3218a67b breaking: tidal style echoWith + add echoForEach 2025-09-15 22:41:51 +02:00
8 changed files with 54 additions and 45 deletions
+28 -6
View File
@@ -2354,20 +2354,42 @@ export const jux = register('jux', function (func, pat) {
/**
* Superimpose and offset multiple times, applying the given function each time.
* @name echoWith
* @synonyms echowith, stutWith, stutwith
* @name echoForEach
* @param {number} times how many times to repeat
* @param {number} time cycle offset between iterations
* @param {function} func function to apply, given the pattern and the iteration index
* @example
* "<0 [2 4]>"
* .echoWith(4, 1/8, (p,n) => p.add(n*2))
* .scale("C:minor").note()
* .n().scale("C:minor")
*/
export const { echoForEach } = register(['echoForEach'], function (times, time, func, pat) {
return stack(...listRange(0, times - 1).map((i) => func(pat.late(Fraction(time).mul(i)), i)));
});
/**
* Superimpose and offset multiple times, applying the given function each time.
* @name echoWith
* @synonyms echowith, stutWith, stutwith
* @param {number} times how many times to repeat
* @param {number} time cycle offset between iterations
* @param {function} func function to apply, given the pattern and the iteration index
* @example
* "<0 [2 4]>".echoWith(4, 1/8, add(2))
* .n().scale("C:minor")
*/
export const { echoWith, echowith, stutWith, stutwith } = register(
['echoWith', 'echowith', 'stutWith', 'stutwith'],
function (times, time, func, pat) {
return stack(...listRange(0, times - 1).map((i) => func(pat.late(Fraction(time).mul(i)), i)));
if (times < 1) {
return silence;
}
let pats = pat;
for (let i = 1; i < times; i++) {
pat = func(pat.late(time));
pats = pats.stack(pat);
}
return pats;
},
);
@@ -2383,7 +2405,7 @@ export const { echoWith, echowith, stutWith, stutwith } = register(
* s("bd sd").echo(3, 1/6, .8)
*/
export const echo = register('echo', function (times, time, feedback, pat) {
return pat._echoWith(times, time, (pat, i) => pat.gain(Math.pow(feedback, i)));
return pat._echoForEach(times, time, (pat, i) => pat.gain(Math.pow(feedback, i)));
});
/**
@@ -2396,7 +2418,7 @@ export const echo = register('echo', function (times, time, feedback, pat) {
* s("bd sd").stut(3, .8, 1/6)
*/
export const stut = register('stut', function (times, feedback, time, pat) {
return pat._echoWith(times, time, (pat, i) => pat.gain(Math.pow(feedback, i)));
return pat._echoForEach(times, time, (pat, i) => pat.gain(Math.pow(feedback, i)));
});
export const applyN = register('applyN', function (n, func, p) {
+22 -8
View File
@@ -3301,20 +3301,28 @@ exports[`runs examples > example "echo" example index 0 1`] = `
]
`;
exports[`runs examples > example "echoForEach" example index 0 1`] = `[]`;
exports[`runs examples > example "echoWith" example index 0 1`] = `
[
"[ -3/8 ⇜ (0/1 → 1/8) | note:Bb3 ]",
"[ -1/4 ⇜ (0/1 → 1/4) | note:D4 ]",
"[ -1/8 ⇜ (0/1 → 3/8) | note:F4 ]",
"[ -1/4 ⇜ (0/1 → 1/8) ⇝ 1/4 | note:D4 ]",
"[ -1/8 ⇜ (0/1 → 1/8) ⇝ 3/8 | note:F4 ]",
"[ 0/1 → 1/1 | note:C3 ]",
"[ -1/4 ⇜ (1/8 → 1/4) | note:D4 ]",
"[ -1/8 ⇜ (1/8 → 1/4) ⇝ 3/8 | note:F4 ]",
"[ (1/8 → 1/1) ⇝ 9/8 | note:Eb3 ]",
"[ -1/8 ⇜ (1/4 → 3/8) | note:F4 ]",
"[ (1/4 → 1/1) ⇝ 5/4 | note:G3 ]",
"[ (3/8 → 1/1) ⇝ 11/8 | note:Bb3 ]",
"[ 1/8 ⇜ (1/1 → 9/8) | note:Eb3 ]",
"[ 1/4 ⇜ (1/1 → 5/4) | note:G3 ]",
"[ 3/8 ⇜ (1/1 → 11/8) | note:Bb3 ]",
"[ 1/4 ⇜ (1/1 → 9/8) ⇝ 5/4 | note:G3 ]",
"[ 3/8 ⇜ (1/1 → 9/8) ⇝ 11/8 | note:Bb3 ]",
"[ 1/1 → 3/2 | note:Eb3 ]",
"[ 1/4 ⇜ (9/8 → 5/4) | note:G3 ]",
"[ 3/8 ⇜ (9/8 → 5/4) ⇝ 11/8 | note:Bb3 ]",
"[ 9/8 → 13/8 | note:G3 ]",
"[ 3/8 ⇜ (5/4 → 11/8) | note:Bb3 ]",
"[ 5/4 → 7/4 | note:Bb3 ]",
"[ 11/8 → 15/8 | note:D4 ]",
"[ 3/2 → 2/1 | note:G3 ]",
@@ -3322,17 +3330,23 @@ exports[`runs examples > example "echoWith" example index 0 1`] = `
"[ (7/4 → 2/1) ⇝ 9/4 | note:D4 ]",
"[ (15/8 → 2/1) ⇝ 19/8 | note:F4 ]",
"[ 13/8 ⇜ (2/1 → 17/8) | note:Bb3 ]",
"[ 7/4 ⇜ (2/1 → 9/4) | note:D4 ]",
"[ 15/8 ⇜ (2/1 → 19/8) | note:F4 ]",
"[ 7/4 ⇜ (2/1 → 17/8) ⇝ 9/4 | note:D4 ]",
"[ 15/8 ⇜ (2/1 → 17/8) ⇝ 19/8 | note:F4 ]",
"[ 2/1 → 3/1 | note:C3 ]",
"[ 7/4 ⇜ (17/8 → 9/4) | note:D4 ]",
"[ 15/8 ⇜ (17/8 → 9/4) ⇝ 19/8 | note:F4 ]",
"[ (17/8 → 3/1) ⇝ 25/8 | note:Eb3 ]",
"[ 15/8 ⇜ (9/4 → 19/8) | note:F4 ]",
"[ (9/4 → 3/1) ⇝ 13/4 | note:G3 ]",
"[ (19/8 → 3/1) ⇝ 27/8 | note:Bb3 ]",
"[ 17/8 ⇜ (3/1 → 25/8) | note:Eb3 ]",
"[ 9/4 ⇜ (3/1 → 13/4) | note:G3 ]",
"[ 19/8 ⇜ (3/1 → 27/8) | note:Bb3 ]",
"[ 9/4 ⇜ (3/1 → 25/8) ⇝ 13/4 | note:G3 ]",
"[ 19/8 ⇜ (3/1 → 25/8) ⇝ 27/8 | note:Bb3 ]",
"[ 3/1 → 7/2 | note:Eb3 ]",
"[ 9/4 ⇜ (25/8 → 13/4) | note:G3 ]",
"[ 19/8 ⇜ (25/8 → 13/4) ⇝ 27/8 | note:Bb3 ]",
"[ 25/8 → 29/8 | note:G3 ]",
"[ 19/8 ⇜ (13/4 → 27/8) | note:Bb3 ]",
"[ 13/4 → 15/4 | note:Bb3 ]",
"[ 27/8 → 31/8 | note:D4 ]",
"[ 7/2 → 4/1 | note:G3 ]",
-5
View File
@@ -1,5 +0,0 @@
The FontStruction “TIC-80 wide font”
(https://fontstruct.com/fontstructions/show/1388526) by “nesbox” is licensed
under a Creative Commons CC0 Public Domain Dedication license
(http://creativecommons.org/publicdomain/zero/1.0/).
[ancestry]
-16
View File
@@ -1,16 +0,0 @@
The font file in this archive was created using Fontstruct the free, online
font-building tool.
This font was created by “nesbox”.
This font has a homepage where this archive and other versions may be found:
https://fontstruct.com/fontstructions/show/1388526
[ancestry]
Try Fontstruct at https://fontstruct.com
It’s easy and it’s fun.
Fontstruct is copyright ©2017-2025 Rob Meek
LEGAL NOTICE:
In using this font you must comply with the licensing terms described in the
file “license.txt” included with this archive.
If you redistribute the font file in this archive, it must be accompanied by all
the other files from this archive, including this one.
Binary file not shown.
@@ -74,7 +74,6 @@ const fontFamilyOptions = {
FiraCode: 'FiraCode',
'FiraCode-SemiBold': 'FiraCode SemiBold',
teletext: 'teletext',
tic80: 'tic80',
mode7: 'mode7',
BigBlueTerminal: 'BigBlueTerminal',
x3270: 'x3270',
+4 -4
View File
@@ -285,7 +285,7 @@ stack(
.mul(gain(sine.struct("x*8").add(3/5).mul(2/5).fast(8)))
.piano()`;
// iter, echo, echoWith
// iter, echo, echoForEach
export const undergroundPlumber = `// "Underground plumber"
// @license CC BY-NC-SA 4.0 https://creativecommons.org/licenses/by-nc-sa/4.0/
// @by Felix Roos
@@ -307,7 +307,7 @@ stack(
.cutoff(400).decay(.12).sustain(0)
,
"[g2,[c3 eb3]]".iter(4)
.echoWith(4, 1/8, (x,n)=>x.transpose(n*12).gain(Math.pow(.4,n)))
.echoForEach(4, 1/8, (x,n)=>x.transpose(n*12).gain(Math.pow(.4,n)))
.note().layer(h)
.clip(.1)
)
@@ -432,7 +432,7 @@ export const festivalOfFingers3 = `// "Festival of fingers 3"
setcps(1)
n("[-7*3],0,2,6,[8 7]")
.echoWith(
.echoForEach(
4, // echo 4 times
1/4, // 1/4s between echos
(x,i)=>x
@@ -485,7 +485,7 @@ stack(
.decay(.1).sustain(0) // make notes short
.s('triangle') // waveform
.degradeBy(perlin.range(0,.5)) // randomly controlled random removal :)
.echoWith(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes
.echoForEach(4,.125,(x,n)=>x.gain(.15*1/(n+1))) // echo notes
//.hush()
)
.slow(3/2)`;
-5
View File
@@ -50,11 +50,6 @@
src: url('/fonts/teletext/EuropeanTeletext.ttf');
size-adjust: 90%;
}
@font-face {
font-family: 'tic80';
src: url('/fonts/tic80/tic-80-wide-font.otf');
size-adjust: 60%;
}
@font-face {
font-family: 'mode7';
src: url('/fonts/mode7/MODE7GX3.TTF');