diff --git a/src/API.ts b/src/API.ts index cbe0448..0a916b5 100644 --- a/src/API.ts +++ b/src/API.ts @@ -1025,17 +1025,9 @@ export class UserAPI { }; // ============================================================= - // Modulo basd time filters + // Modulo based time filters // ============================================================= - public modbar = (...n: number[]): boolean => { - const results: boolean[] = n.map( - (value) => - this.app.clock.time_position.bar % Math.floor(value * this.ppqn()) === 0 - ); - return results.some((value) => value === true); - }; - // ============================================================= // Other core temporal functions // ============================================================= @@ -1056,7 +1048,7 @@ export class UserAPI { return pos_within_chunk < threshold; }; - public divbar = (chunk: number): boolean => { + public flipbar = (chunk: number = 1): boolean => { const time_pos = this.app.clock.time_position.bar; const current_chunk = Math.floor(time_pos / chunk); return current_chunk % 2 === 0; diff --git a/src/documentation/inlineHelp.ts b/src/documentation/inlineHelp.ts index 1d34ec3..9ed59b5 100644 --- a/src/documentation/inlineHelp.ts +++ b/src/documentation/inlineHelp.ts @@ -504,12 +504,12 @@ const completionDatabase: CompletionDatabase = { description: "jumps to the n beat of the clock.", example: "beat_warp(1) :: log('back to the first beat!')", }, - divbar: { - name: "divbar", + flipbar: { + name: "flipbar", category: "time", description: - "works just like flip but at the level of bars instead of beats", - example: "divbar(2)::beat(1)::snd('kick').out()", + "works just like flip at the level of bars instead of beats", + example: "flipbar(2)::beat(1)::snd('kick').out()", }, onbar: { name: "onbar", diff --git a/src/documentation/time.ts b/src/documentation/time.ts index 16d0152..98a3883 100644 --- a/src/documentation/time.ts +++ b/src/documentation/time.ts @@ -20,7 +20,7 @@ To change the tempo, use the bpm(number) function. The transport is con Let's study two very simple rhythmic functions, mod(n: ...number[]) and onbeat(...n:number[]). They are both easy to understand and powerful enough to get you to play your first rhythms. -- beat(...n: number[]): this function will return true every _n_ pulsations. The value 1 will return true at the beginning of each beat. Floating point numbers like 0.5 or 0.25 are also accepted. Multiple values can be passed to beat to generate more complex rhythms. +- beat(...n: number[]): this function will return true every _n_ beats. The value 1 will return true at the beginning of each beat. Floating point numbers like 0.5 or 0.25 are also accepted. Multiple values can be passed to beat to generate more complex rhythms. ${makeExample( "Using different mod values", @@ -44,7 +44,7 @@ beat([1,0.75].beat(2)) :: blip([50, 100].beat(2)).out(); )} -- pulse(...n: number[]): extreme version of the beat function. Instead of returning true for every beat, this function is returning true every _n_ clock ticks! It can be used to generate very unexpected results or to sequence by using your arithmetic ninja skills. +- pulse(...n: number[]): faster version of the beat function. Instead of returning true for every beat, this function is returning true every _n_ clock ticks! It can be used to generate very unexpected results or to sequence by using your arithmetic ninja skills. ${makeExample( "Intriguing rhythms", @@ -65,7 +65,7 @@ beat(1)::snd('bd').out() false )}; -- onbeat(...n: number[]): By default, the bar is set in 4/4 with four beats per bar. The onbeat function allows you to lock on to a specific beat to execute some code. It can accept multiple arguments. It's usage is very straightforward and not hard to understand. You can pass integers or floating point numbers. +- onbeat(...n: number[]): The onbeat function allows you to lock on to a specific beat from the clock to execute code. It can accept multiple arguments. It's usage is very straightforward and not hard to understand. You can pass either integers or floating point numbers. By default, topos is using a 4/4 bar meaning that you can target any of these beats (or in-between) with this function. ${makeExample( "Some simple yet detailed rhythms", @@ -89,13 +89,14 @@ beat([.25, 1/8].beat(1.5))::snd('hat').n(2) false )} -- oncount(beats: number[], meter: number): This function is similar to onbeat but it allows you to specify a custom meter (time signature denominator) for the beats. +- oncount(beats: number[], meter: number): This function is similar to onbeat but it allows you to specify a custom number of beats as the last argument. ${makeExample( "Using oncount to create more variation in the rhythm", ` bpm(120) - z1('q (0 4 2 9)+(0 3 1 5)').sound('sine').cutoff(400).delay(0.5).out() + z1('q (0 4 2 9)+(0 3 1 5)').sound('sawtooth').cutoff([400,500,1000,2000].beat(1)) + .delay(0.5).delayt(0.25).room(0.9).size(0.9).out() onbeat(1,1.5,2,3,4) :: sound('bd').gain(2.0).out() oncount([1,3,5.5,7,7.5,8],8) :: sound('hh').gain(irand(1.0,4.0)).out() `, @@ -126,6 +127,7 @@ ${makeExample( ` beat(.5) && euclid($(1), 5, 8) && snd('kick').out() beat(.5) && euclid($(2), 2, 8) && snd('sd').out() +beat(4) :: sound('cp').out() `, true )} @@ -145,8 +147,8 @@ ${makeExample( "Adding more rhythmic density", ` beat(.5) && euclid($(1), 5, 9) && snd('kick').out() -beat(.5) && euclid($(2), 2, 3, 1) && snd('east').end(0.5).n(5).out() -beat(.5) && euclid($(3), 6, 9, 1) && snd('east').end(0.5).n(5).freq(200).out() +beat(.5) && euclid($(2), 2, 3, 1) && snd('east').end(0.5).n(5).speed([1,2].beat(2)).out() +beat(.5) && euclid($(3), 6, 9, 1) && snd('east').end(0.5).n(5).freq(200).speed([2,1].beat(2)).out() beat(.25) && euclid($(4), 7, 9, 1) && snd('hh').out() `, false @@ -159,7 +161,7 @@ ${makeExample( "Using oneuclid to create a rhythm without iterators", ` // Change speed using bpm - // bpm(250) + bpm(250) oneuclid(5, 9) :: snd('kick').out() oneuclid(7,16) :: snd('east').end(0.5).n(irand(3,5)).out() `, @@ -170,7 +172,7 @@ ${makeExample( ${makeExample( "rhythm is a beginner friendly rhythmic function!", ` -let speed = [0.5, 0.25].beat(8); +let speed = [0.5, 0.25].beat(8); bpm(140); rhythm(speed, 5, 12) :: snd('east').n(2).out() rhythm(speed, 2, 12) :: snd('east').out() rhythm(speed, 3, 12) :: snd('east').n(4).out() @@ -201,16 +203,17 @@ binrhythm(.5, 18) && snd('sd').out() )} ${makeExample( - "Calling 911", + "Submarine jungle music", ` -beat(.5) && bin($(1), 911) && snd('subroc3d').n($(2)).delay(0.5).delayt(0.25).end(0.5).out() -beat(.5) && sound('less').n(irand(1, 10)).out() +beat(.5) && bin($(1), 911) && snd('ST69').n([2,3,4].beat()) + .delay(0.125).delayt(0.25).end(0.25).speed(1/3).out() +beat(.5) && sound('amencutup').n(irand(2,7)).shape(0.3).out() `, false )} ${makeExample( - "Playing around with simple numbers", + "Using tabla to play unpredictable rhythms", ` beat(.5) && bin($(1), [123, 456, 789].beat(4)) && snd('tabla').n($(2)).delay(0.5).delayt(0.25).out() @@ -233,13 +236,13 @@ prob(80)::beat(.5) && sound('hh').out() ## Time Warping -Time is cool. But it's even cooler when you can manipulate it to your liking. Think about jumping back or forward in time. Think about looping a specific part of your current pattern or song. This is all possible thanks to two simple functions: warp(n: number) and beat_warp(n: number). They are both very easy to use and very powerful. Let's see how they work. +Time generally flows from the past to the future. However, it's even cooler when you can manipulate it to your liking by jumping back and forth. Think about looping a specific part of your current pattern or song or jumping all of the sudden in the future. This is entirely possible thanks to two simple functions: warp(n: number) and beat_warp(n: number). They are both very easy to use and very powerful. Let's see how they work. -- warp(n: number): this function jumps to the _n_ tick of the clock. 1 is the first pulsation ever, and the number keeps increasing to the infinite. +- warp(n: number): this function jumps to the _n_ tick of the clock. 1 is the first pulsation ever and the number keeps increasing indefinitely. You are most likely currently listening to tick n°12838123. ${makeExample( - "Jumping back and forth in time", + "Time is now super elastic!", ` // Obscure Shenanigans - Bubobubobubo beat([1/4,1/8,1/16].beat(8)):: sound('sine') @@ -250,7 +253,7 @@ beat(1) :: sound('kick').out() beat(2) :: sound('dr').n(5).out() flip(3) :: beat([.25,.5].beat(.5)) :: sound('dr') .n([8,9].pick()).gain([.8,.5,.25,.1,.0].beat(.25)).out() -// Time is elastic now! +// Jumping back and forth in time beat(.25) :: warp([12, 48, 24, 1, 120, 30].pick()) `, true @@ -298,7 +301,8 @@ ${makeExample( ` flip(2.5, 10) :: beat(.25) :: snd('cp').out() flip(2.5, 75) :: beat(.25) :: snd('click').speed(2).end(0.2).out() -flip(2.5) :: mod(.5) :: snd('bd').out() +flip(2.5) :: beat(.5) :: snd('bd').out() +beat(.25) :: sound('hh').out() `, false )} @@ -315,7 +319,7 @@ if (flip(4, 75)) { true )} -flip is extremely powerful and is used internally for a lot of other Topos functions. You can also use it to think about **longer durations** spanning over multiple bars. +flip is extremely powerful and is used internally for a lot of other Topos functions. You can also use it to think about **longer durations** spanning over multiple bars. Here is a silly composition that is using flip to generate a 4 bars long pattern. ${makeExample( "Clunky algorithmic rap music", @@ -343,27 +347,27 @@ if (flip(16)) { You can use it everywhere to spice things up, including as a method parameter picker: ${makeExample( - "div is great for parameter variation", + "flip is great for parameter variation", ` beat(.5)::snd(flip(4) ? 'kick' : 'hat').out() `, true )} -- divbar(n: number): works just like div but at the level of bars instead of beats. It allows you to think about even bigger time cycles. You can also pair it with regular div for making complex algorithmic beats. +- flipbar(n: number = 1): this method works just like flip but counts in bars instead of beats. It allows you to think about even larger time cycles. You can also pair it with regular flip for writing complex and long-spanning algorithmic beats. ${makeExample( "Thinking music over bars", ` -divbar(2)::beat(1)::snd('kick').out() -divbar(3)::beat(.5)::snd('hat').out() +flipbar(2) :: beat(1):: snd('kick').out() +flipbar(3) :: beat(.5):: snd('hat').out() `, true )} ${makeExample( "Alternating over four bars", ` -divbar(2) +flipbar(2) ? beat(.5) && snd(['kick', 'hh'].beat(1)).out() : beat(.5) && snd(['east', 'snare'].beat(1)).out() `, diff --git a/src/examples/excerpts.ts b/src/examples/excerpts.ts index 4ca8fe3..171d374 100644 --- a/src/examples/excerpts.ts +++ b/src/examples/excerpts.ts @@ -4,7 +4,7 @@ let frequencies = [200,400,600,800,1000,2000].beat(2); beat(2) :: sound('sine').freq(frequencies) .delay(0.5).delayt(usine(.5)).delayfb(0.8).size(0.9).room(0.9).out() beat(2) :: app.hydra.osc(frequencies/100, 0.25, 0.5) - .posterize([32,4,8,16].beat(2)).rotate(pulse()) + .posterize([32,4,8,16].beat(2)).rotate(cpulse()) .kaleid([1,2,3].beat()).out()`, `// The real internet of things - Bubobubobubo beat(.5) :: sound('STA6').cut(1).vel(0.4)