Add missing bar function + documentation
This commit is contained in:
33
src/API.ts
33
src/API.ts
@ -63,7 +63,7 @@ export class UserAPI {
|
||||
private errorTimeoutID: number = 0;
|
||||
private printTimeoutID: number = 0;
|
||||
public MidiConnection: MidiConnection;
|
||||
public scale_aid: string|number|undefined = undefined;
|
||||
public scale_aid: string | number | undefined = undefined;
|
||||
load: samples;
|
||||
|
||||
constructor(public app: Editor) {
|
||||
@ -588,21 +588,21 @@ export class UserAPI {
|
||||
};
|
||||
|
||||
public show_scale = (
|
||||
root: number|string,
|
||||
scale: number|string,
|
||||
root: number | string,
|
||||
scale: number | string,
|
||||
channel: number = 0,
|
||||
port: number|string = (this.MidiConnection.currentOutputIndex || 0),
|
||||
port: number | string = (this.MidiConnection.currentOutputIndex || 0),
|
||||
soundOff: boolean = false): void => {
|
||||
/**
|
||||
* Sends given scale to midi output for visual aid
|
||||
*/
|
||||
if (!this.scale_aid || scale !== this.scale_aid) {
|
||||
this.hide_scale(root,scale,channel,port);
|
||||
this.hide_scale(root, scale, channel, port);
|
||||
const scaleNotes = getAllScaleNotes(scale, root);
|
||||
// Send each scale note to current midi out
|
||||
scaleNotes.forEach(note => {
|
||||
this.MidiConnection.sendMidiOn(note, channel, 1, port);
|
||||
if(soundOff) this.MidiConnection.sendAllSoundOff(channel, port);
|
||||
if (soundOff) this.MidiConnection.sendAllSoundOff(channel, port);
|
||||
});
|
||||
|
||||
this.scale_aid = scale;
|
||||
@ -611,11 +611,11 @@ export class UserAPI {
|
||||
|
||||
public hide_scale = (
|
||||
// @ts-ignore
|
||||
root: number|string=0,
|
||||
root: number | string = 0,
|
||||
// @ts-ignore
|
||||
scale: number|string=0,
|
||||
scale: number | string = 0,
|
||||
channel: number = 0,
|
||||
port: number|string = (this.MidiConnection.currentOutputIndex || 0)): void => {
|
||||
port: number | string = (this.MidiConnection.currentOutputIndex || 0)): void => {
|
||||
/**
|
||||
* Hides all notes by sending all notes off to midi output
|
||||
*/
|
||||
@ -628,14 +628,14 @@ export class UserAPI {
|
||||
|
||||
}
|
||||
|
||||
midi_notes_off = (channel: number = 0, port: number|string = (this.MidiConnection.currentOutputIndex || 0)): void => {
|
||||
midi_notes_off = (channel: number = 0, port: number | string = (this.MidiConnection.currentOutputIndex || 0)): void => {
|
||||
/**
|
||||
* Sends all notes off to midi output
|
||||
*/
|
||||
this.MidiConnection.sendAllNotesOff(channel, port);
|
||||
}
|
||||
|
||||
midi_sound_off = (channel: number = 0, port: number|string = (this.MidiConnection.currentOutputIndex || 0)): void => {
|
||||
midi_sound_off = (channel: number = 0, port: number | string = (this.MidiConnection.currentOutputIndex || 0)): void => {
|
||||
/**
|
||||
* Sends all sound off to midi output
|
||||
*/
|
||||
@ -1269,6 +1269,17 @@ export class UserAPI {
|
||||
};
|
||||
b = this.beat;
|
||||
|
||||
|
||||
public bar = (...n: number[]): boolean => {
|
||||
const results: boolean[] = n.map(
|
||||
(value) =>
|
||||
this.app.clock.pulses_since_origin % Math.floor((value * this.ppqn()) * this.app.clock.time_signature[1]) ===
|
||||
0
|
||||
);
|
||||
return results.some((value) => value === true);
|
||||
};
|
||||
B = this.bar;
|
||||
|
||||
public pulse = (...n: number[]): boolean => {
|
||||
const results: boolean[] = n.map(
|
||||
(value) => this.app.clock.pulses_since_origin % value === 0
|
||||
|
||||
@ -20,7 +20,7 @@ To change the tempo, use the <ic>bpm(number)</ic> function. The transport is con
|
||||
|
||||
Let's study two very simple rhythmic functions, <ic>mod(n: ...number[])</ic> and <ic>onbeat(...n:number[])</ic>. They are both easy to understand and powerful enough to get you to play your first rhythms.
|
||||
|
||||
- <ic>beat(...n: number[])</ic>: this function will return true every _n_ beats. The value <ic>1</ic> will return <ic>true</ic> at the beginning of each beat. Floating point numbers like <ic>0.5</ic> or <ic>0.25</ic> are also accepted. Multiple values can be passed to <ic>beat</ic> to generate more complex rhythms.
|
||||
- <ic>beat(...n: number[])</ic>: return true every _n_ beats. The value <ic>1</ic> will return <ic>true</ic> at the beginning of each beat. Floating point numbers like <ic>0.5</ic> or <ic>0.25</ic> are also accepted. Multiple values can be passed to <ic>beat</ic> to generate more complex rhythms.
|
||||
|
||||
${makeExample(
|
||||
"Using different mod values",
|
||||
@ -29,7 +29,7 @@ ${makeExample(
|
||||
beat([1,1/2,1/4,1/8].beat(2)) :: sound('hat').n(0).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Some sort of ringtone",
|
||||
@ -49,8 +49,7 @@ flip(3) :: beat(1/6) :: blip(800).pan(r(0,1)).out();
|
||||
beat([1,0.75].beat(2)) :: blip([50, 100].beat(2)).pan(r(0,1)).out();
|
||||
`,
|
||||
false
|
||||
)}
|
||||
|
||||
)}
|
||||
|
||||
- <ic>pulse(...n: number[])</ic>: faster version of the <ic>beat</ic> 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 rhythms.
|
||||
|
||||
@ -64,7 +63,7 @@ pulse([48/2, 48/3].beat(4)) :: snd('hand')
|
||||
.n([2,4].add(5).beat(1)).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"pulse is the OG rhythmic function in Topos",
|
||||
`
|
||||
@ -72,7 +71,18 @@ pulse([48, 24, 16].beat(4)) :: sound('linnhats').out()
|
||||
beat(1)::snd(['bd', '808oh'].beat(1)).out()
|
||||
`,
|
||||
false
|
||||
)};
|
||||
)};
|
||||
|
||||
- <ic>bar(...n: number[])</ic>: return true every _n_ bars.
|
||||
|
||||
${makeExample(
|
||||
"Four beats per bar: proof",
|
||||
`
|
||||
bar(1)::sound('kick').out()
|
||||
beat(1)::sound('hat').speed(2).out()
|
||||
`, true
|
||||
)}
|
||||
|
||||
|
||||
- <ic>onbeat(...n: number[])</ic>: The <ic>onbeat</ic> 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 <ic>4/4</ic> bar meaning that you can target any of these beats (or in-between) with this function.
|
||||
|
||||
@ -84,7 +94,7 @@ onbeat(2,4)::snd('snare').n([8,4].beat(4)).out() // Snare on acccentuated beats
|
||||
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Let's do something more complex",
|
||||
@ -96,7 +106,7 @@ beat([.25, 1/8].beat(1.5))::snd('hat').n(2)
|
||||
.pan(usine()).out()
|
||||
`,
|
||||
false
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>oncount(beats: number[], meter: number)</ic>: This function is similar to <ic>onbeat</ic> but it allows you to specify a custom number of beats as the last argument.
|
||||
|
||||
@ -111,7 +121,7 @@ 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()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Using oncount to create rhythms with a custom meter",
|
||||
@ -123,7 +133,7 @@ oncount([2, 3, 3.5, 6, 7, 10, 15],16) :: sound('hh').n(8).gain(0.8).out()
|
||||
oncount([1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16],16) :: sound('hh').out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
## Rhythm generators
|
||||
|
||||
@ -144,7 +154,7 @@ beat(.25) && euclid($(3), 6, 8) && snd('shaker')
|
||||
.speed(2).n(11).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"And now something a bit more complex",
|
||||
@ -156,7 +166,7 @@ beat(.5) && euclid($(2), [1,0].beat(8), 8)
|
||||
beat(.5) && euclid($(6), [6,7].beat(8), 8) :: sound('hh').out()
|
||||
`,
|
||||
false
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Adding more rhythmic density",
|
||||
@ -169,7 +179,7 @@ beat(.5) && euclid($(3), 6, 9, 1) && snd('dr').end(0.5).n(2).freq(200).speed(1)
|
||||
beat(.25) && euclid($(4), 7, 9, 1) && snd('hh').out()
|
||||
`,
|
||||
false
|
||||
)}
|
||||
)}
|
||||
|
||||
Alternatively, you can <ic>oneuclid</ic> or <ic>rhythm</ic> without the _iterators_:
|
||||
|
||||
@ -183,7 +193,7 @@ ${makeExample(
|
||||
oneuclid(7,16) :: snd('east').end(0.5).n(irand(3,5)).out()
|
||||
`,
|
||||
false
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>rhythm(divisor: number, pulses: number, length: number, rotate: number): boolean</ic>: generates <ic>true</ic> or <ic>false</ic> values from an euclidian rhythm sequence. This is another version of <ic>euclid</ic> that does not take an iterator.
|
||||
${makeExample(
|
||||
@ -196,7 +206,7 @@ rhythm(speed, 3, 12) :: snd('linnhats').n(4).pan(noise()).out()
|
||||
rhythm(speed, 7, 12) :: snd('east').n(9).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>bin(iterator: number, n: number): boolean</ic>: a binary rhythm generator. It transforms the given number into its binary representation (_e.g_ <ic>34</ic> becomes <ic>100010</ic>). It then returns a boolean value based on the iterator in order to generate a rhythm.
|
||||
- <ic>binrhythm(divisor: number, n: number): boolean: boolean</ic>: iterator-less version of the binary rhythm generator.
|
||||
@ -209,7 +219,7 @@ beat(.5) && bin($(1), 12) && snd('kick').n([4,9].beat(1.5)).out()
|
||||
beat(.5) && bin($(2), 34) && snd('snare').n([3,5].beat(1)).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"binrhythm for fast cool binary rhythms!",
|
||||
@ -223,7 +233,7 @@ binrhythm([.5, .25].beat(1), 30) && snd('wt_granular').n(a)
|
||||
.room(1).size(1).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Submarine jungle music",
|
||||
@ -235,7 +245,7 @@ beat(.5) && bin($(1), 911) && snd('ST69').n([2,3,4].beat())
|
||||
beat(.5) && sound('amencutup').n(irand(2,7)).shape(0.3).out()
|
||||
`,
|
||||
false
|
||||
)}
|
||||
)}
|
||||
|
||||
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.
|
||||
|
||||
@ -249,7 +259,7 @@ prob(60)::beat(.5) && euclid($(2), 3, 8) && snd('mash')
|
||||
prob(80)::beat(.5) && sound(['hh', 'hat'].pick()).out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
## Time Warping
|
||||
|
||||
@ -274,7 +284,7 @@ flip(3) :: beat([.25,.5].beat(.5)) :: sound('dr')
|
||||
beat(.25) :: warp([12, 48, 24, 1, 120, 30].pick())
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>beat_warp(beat: number)</ic>: this function jumps to the _n_ beat of the clock. The first beat is <ic>1</ic>.
|
||||
|
||||
@ -296,7 +306,7 @@ beat(.5) :: snd('arpy').note(
|
||||
beat(1) :: beat_warp([2,4,5,10,11].pick())
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
## Larger time divisions
|
||||
|
||||
@ -311,7 +321,7 @@ ${makeExample(
|
||||
flip(4) :: beat(1) :: snd('kick').out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Clapping on the edge",
|
||||
@ -323,7 +333,7 @@ flip(2.5) :: beat(.5) :: snd('bd').out()
|
||||
beat(.25) :: sound('hat').end(0.1).cutoff(1200).pan(usine(1/4)).out()
|
||||
`,
|
||||
false
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Good old true and false",
|
||||
@ -335,7 +345,7 @@ if (flip(4, 75)) {
|
||||
}
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
<ic>flip</ic> 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 <ic>flip</ic> to generate a 4 bars long pattern.
|
||||
|
||||
@ -360,7 +370,7 @@ if (flip(8)) {
|
||||
}
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
You can use it everywhere to spice things up, including as a method parameter picker:
|
||||
|
||||
@ -370,7 +380,7 @@ ${makeExample(
|
||||
beat(.5)::snd(flip(2) ? 'kick' : 'hat').out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>flipbar(n: number = 1)</ic>: this method works just like <ic>flip</ic> but counts in bars instead of beats. It allows you to think about even larger time cycles. You can also pair it with regular <ic>flip</ic> for writing complex and long-spanning algorithmic beats.
|
||||
|
||||
@ -389,7 +399,7 @@ flipbar(2) && a()
|
||||
flipbar(3) && b()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"Alternating over four bars",
|
||||
`
|
||||
@ -398,7 +408,7 @@ flipbar(2)
|
||||
: beat(.5) && snd(['east', 'east:2'].beat(1)).out()
|
||||
`,
|
||||
false
|
||||
)};
|
||||
)};
|
||||
|
||||
|
||||
- <ic>onbar(bars: number | number[], n: number)</ic>: The second argument, <ic>n</ic>, is used to divide the time in a period of <ic>n</ic> consecutive bars. The first argument should be a bar number or a list of bar numbers to play on. For example, <ic>onbar([1, 4], 5)</ic> will return <ic>true</ic> on bar <ic>1</ic> and <ic>4</ic> but return <ic>false</ic> the rest of the time. You can easily divide time that way.
|
||||
@ -422,7 +432,7 @@ if (onbar([1,2], 4)) {
|
||||
rhythm(.5, 2, 7) :: snd('snare').n(3).out();
|
||||
}`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
|
||||
## What are pulses?
|
||||
|
||||
@ -471,6 +481,6 @@ if((cbar() % 4) > 1) {
|
||||
beat([.5, .5, 1, .25].beat(0.5)) :: sound('shaker').out()
|
||||
`,
|
||||
true
|
||||
)}
|
||||
)}
|
||||
`;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user