diff --git a/src/API.ts b/src/API.ts
index cc27754..c45f884 100644
--- a/src/API.ts
+++ b/src/API.ts
@@ -236,7 +236,7 @@ export class UserAPI {
}
};
- public midi = (value: number|object = 60): NoteEvent => {
+ public midi = (value: number | object = 60): NoteEvent => {
/**
* Sends a MIDI note to the current MIDI output.
*
@@ -491,6 +491,12 @@ export class UserAPI {
return current_chunk % 2 === 0;
};
+ public babou = (chunk: number): boolean => {
+ const time_pos = this.epulse();
+ const chunkSize = Math.floor(chunk * this.ppqn());
+ return time_pos % chunkSize === 0;
+ };
+
public divbar = (chunk: number): boolean => {
const time_pos = this.bar() - 1;
const current_chunk = Math.floor(time_pos / chunk);
@@ -869,10 +875,8 @@ export class UserAPI {
};
onbar = (n: number, ...bar: number[]): boolean => {
- // n is acting as a modulo on the bar number
- const bar_list = [...Array(n).keys()].map((i) => i + 1);
- console.log(bar.some((b) => bar_list.includes(b % n)));
- return bar.some((b) => bar_list.includes(b % n));
+ let bar_modulo = (this.bar() % n) + 1;
+ return bar.some((b) => b == bar_modulo);
};
onbeat = (...beat: number[]): boolean => {
@@ -1237,10 +1241,10 @@ export class UserAPI {
// Trivial functions
// =============================================================
- sound = (sound: string|object) => {
+ sound = (sound: string | object) => {
return new SoundEvent(sound, this.app);
};
-
+
snd = this.sound;
samples = samples;
soundMap = soundMap;
diff --git a/src/Documentation.ts b/src/Documentation.ts
index bf1d596..5ecd621 100644
--- a/src/Documentation.ts
+++ b/src/Documentation.ts
@@ -93,16 +93,69 @@ Click on the Topos logo in the top bar. Your URL will change to something much l
const time: string = `
# Time
-Time in Topos can be **paused** and/or **resetted**. Musical time is flowing at a given **BPM** (_beats per minute_) like a regular drum machine. There are three core values that you will often interact with in one form or another:
+Time in Topos is flowing just like on a drum machine. Topos is counting bars, beats and pulses. The time can be **paused**, **resumed** and/or **resetted**. Pulses are flowing at a given **BPM** (_beats per minute_). There are three core values that you will often interact with in one form or another:
- **bars**: how many bars have elapsed since the origin of time.
- **beats**: how many beats have elapsed since the beginning of the bar.
- **pulse**: how many pulses have elapsed since the last beat.
-To change the tempo, use the bpm(number) function. You can interact with time using interface buttons, keyboard shortcuts but also by using the play(), pause() and stop() functions. You will soon learn how to manipulate time to your liking for backtracking, jumping forward, etc... The traditional timeline model has little value when you can script everything.
+To change the tempo, use the bpm(number) function. The transport is controlled by the interface buttons, by the keyboard shortcuts or using the play(), pause() and stop() functions. You will soon learn how to manipulate time to your liking for backtracking, jumping forward, etc... The traditional timeline model has little value when you can script everything.
**Note:** the bpm(number) function can serve both for getting and setting the **BPM** value.
+## Simple rhythms
+
+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.
+
+- mod(...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 mod to generate more complex rhythms.
+
+
+\`\`\`javascript
+ mod(1) :: sound('kick').out() // A kickdrum played every beat
+ mod(.5) :: sound('kick').out() // A kickdrum played twice per beat
+ mod(.25) :: sound('kick').out() // A kickdrum played four times every beat
+ mod(1/3) :: sound('kick').out() // A funnier ratio!
+ mod(1, 2.5)::sound('hh').out() // A great high-hat pattern
+ mod(1,3.25,2.5)::snd('hh').out() // A somewhat weirder pattern
+\`\`\`
+
+- 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.
+
+\`\`\`javascript
+ onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
+ onbeat(2,4)::snd('snare').out() // Snare on acccentuated beats
+ onbeat(1.5,2.5,3.5, 3.75)::snd('hat').out() // Cool high-hats
+\`\`\`
+
+## Rhythm generators
+
+We included a bunch of popular rhythm generators in Topos such as the euclidian rhythms algorithms or the one to generate rhythms based on a binary sequence. They all work using _iterators_ that you will gradually learn to use for iterating over lists. Note that they are levaraging mod(...n:number[]) that you just learned about!
+
+- euclid(iterator: number, pulses: number, length: number, rotate: number): boolean: generates true or false values from an euclidian rhythm sequence. This algorithm is very popular in the electronic music making world.
+
+\`\`\`javascript
+ mod(.5) && euclid($(1), 5, 8) && snd('kick').out()
+ mod(.5) && euclid($(2), 2, 8) && snd('sd').out()
+\`\`\`
+
+- bin(iterator: number, n: number): boolean: a binary rhythm generator. It transforms the given number into its binary representation (_e.g_ 34 becomes 100010). It then returns a boolean value based on the iterator in order to generate a rhythm.
+
+
+\`\`\`javascript
+ mod(.5) && bin($(1), 34) && snd('kick').out()
+ mod(.5) && bin($(2), 48) && snd('sd').out()
+\`\`\`
+
+If you don't find it spicy enough, you can add some more probabilities to your rhythms by taking advantage of the probability functions. See the functions documentation page to learn more about them.
+
+\`\`\`javascript
+ prob(60)::mod(.5) && euclid($(1), 5, 8) && snd('kick').out()
+ prob(60)::mod(.5) && euclid($(2), 3, 8) && snd('sd').out()
+ prob(80)::mod(.5) && sound('hh').out()
+\`\`\`
+
+## Larger time divisions
+
## Pulses
To make a beat, you need a certain number of time grains or **pulses**. The **pulse** is also known as the [PPQN](https://en.wikipedia.org/wiki/Pulses_per_quarter_note). By default, Topos is using a _pulses per quarter note_ of 48. You can change it by using the ppqn(number) function. It means that the lowest possible rhythmic value is 1/48 of a quarter note. That's plenty of time already.
@@ -129,25 +182,7 @@ Every script can access the current time by using the following functions:
These values are **extremely useful** to craft more complex syntax or to write musical scores. However, Topos is also offering more high-level sequencing functions to make it easier to play music.
-## Useful Basic Functions
-
-Some functions can be leveraged to play rhythms without thinking too much about the clock. Learn them well:
-
-- beat(...values: number[]): returns true on the given beat. You can add any number of beat values, (_e.g._ onbeat(1.2,1.5,2.3,2.5)). The function will return true only for a given pulse, which makes this function very useful for drumming.
-
-\`\`\`javascript
- onbeat(1,2,3,4) && sound('bd').out()
- onbeat(.5,.75,1) && sound('hh').out()
- onbeat(3) && sound('sd').out()
-\`\`\`
-
-- mod(...values: number[]): returns true if the current pulse is a multiple of the given value. You can add any number of values, (_e.g._ mod(.25,.75)). Note that 1 will equal to ppqn() pulses by default. Thus, mod(.5) for a **PPQN** of 48 will be 24 pulses.
-
-\`\`\`javascript
- mod(1) && sound('bd').out()
- mod(pick(.25,.5)) && sound('hh').out()
- mod(.5) && sound('jvbass').out()
-\`\`\`
+## To document!
- onbar(...values: number[]): returns true if the bar is currently equal to any of the specified values.
- modbar(...values: number[]) or bmod(...): returns true if the bar is currently a multiple of any of the specified values.
@@ -157,25 +192,6 @@ Some functions can be leveraged to play rhythms without thinking too much about
- divbar(chunk: number): returns true for every pulse in intervals of given number of bars
- divseq(...values: number[]): returns true for every pulse in intervals of given number of beats returning different value each time.
-## Rhythm generators
-
-We included a bunch of popular rhythm generators in Topos such as the euclidian rhythms algorithms or the one to generate rhythms based on a binary sequence. They all work using _iterators_ that you will gradually learn to use for iterating over lists.
-
-- euclid(iterator: number, pulses: number, length: number, rotate: number): boolean: generates true or false values from an euclidian rhythm sequence. This algorithm is very popular in the electronic music making world.
-
-\`\`\`javascript
- mod(.5) && euclid($(1), 5, 8) && snd('kick').out()
- mod(.5) && euclid($(2), 2, 8) && snd('sd').out()
-\`\`\`
-
-- bin(iterator: number, n: number): boolean: a binary rhythm generator. It transforms the given number into its binary representation (_e.g_ 34 becomes 100010). It then returns a boolean value based on the iterator in order to generate a rhythm.
-
-
-\`\`\`javascript
- mod(.5) && euclid($(1), 34) && snd('kick').out()
- mod(.5) && euclid($(2), 48) && snd('sd').out()
-\`\`\`
-
## Using time as a conditional
You can use the time functions as conditionals. The following example will play a pattern A for 2 bars and a pattern B for 2 bars: