Skip to content

Commit

Permalink
LFO: simplifying arguments and minor corrections
Browse files Browse the repository at this point in the history
  • Loading branch information
Bubobubobubobubo committed Jan 15, 2024
1 parent 3314c08 commit d0f6223
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 81 deletions.
82 changes: 31 additions & 51 deletions src/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1655,8 +1655,6 @@ export class UserAPI {
// Low Frequency Oscillators
// =============================================================

public range = (v: number, a: number, b: number): number => v * (b - a) + a;

public line = (start: number, end: number, step: number = 1): number[] => {
/**
* Returns an array of values between start and end, with a given step.
Expand Down Expand Up @@ -1688,58 +1686,45 @@ export class UserAPI {
return result;
};

public sine = (
freq: number = 1,
times: number = 1,
offset: number = 0,
): number => {
public sine = (freq: number = 1, phase: number = 0): number => {
/**
* Returns a sine wave between -1 and 1.
*
* @param freq - The frequency of the sine wave
* @param offset - The offset of the sine wave
* @param phase - The phase of the sine wave
* @returns A sine wave between -1 and 1
*/
return (
(Math.sin(this.app.clock.ctx.currentTime * Math.PI * 2 * freq) + offset) *
times
);
return Math.sin(2 * Math.PI * freq * (this.app.clock.ctx.currentTime - phase));
};

public usine = (
freq: number = 1,
times: number = 1,
offset: number = 0,
): number => {
public usine = (freq: number = 1, phase: number = 0): number => {
/**
* Returns a sine wave between 0 and 1.
*
* @param freq - The frequency of the sine wave
* @param offset - The offset of the sine wave
* @param phase - The phase of the sine wave
* @returns A sine wave between 0 and 1
* @see sine
*/
return ((this.sine(freq, times, offset) + 1) / 2) * times;
return ((this.sine(freq, phase) + 1) / 2);
};

saw = (freq: number = 1, times: number = 1, offset: number = 0): number => {
saw = (freq: number = 1, phase: number = 0): number => {
/**
* Returns a saw wave between -1 and 1.
*
* @param freq - The frequency of the saw wave
* @param offset - The offset of the saw wave
* @param phase - The phase of the saw wave
* @returns A saw wave between -1 and 1
* @see triangle
* @see square
* @see sine
* @see noise
*/
return (
(((this.app.clock.ctx.currentTime * freq) % 1) * 2 - 1 + offset) * times
);
return (((this.app.clock.ctx.currentTime * freq + phase) % 1) * 2 - 1);
};

usaw = (freq: number = 1, times: number = 1, offset: number = 0): number => {
usaw = (freq: number = 1, phase: number = 0): number => {
/**
* Returns a saw wave between 0 and 1.
*
Expand All @@ -1748,14 +1733,10 @@ export class UserAPI {
* @returns A saw wave between 0 and 1
* @see saw
*/
return ((this.saw(freq, times, offset) + 1) / 2) * times;
return ((this.saw(freq, phase) + 1) / 2);
};

triangle = (
freq: number = 1,
times: number = 1,
offset: number = 0,
): number => {
triangle = (freq: number = 1, phase: number = 0): number => {
/**
* Returns a triangle wave between -1 and 1.
*
Expand All @@ -1765,14 +1746,10 @@ export class UserAPI {
* @see sine
* @see noise
*/
return (Math.abs(this.saw(freq, times, offset)) * 2 - 1) * times;
return (Math.abs(this.saw(freq, phase)) * 2 - 1);
};

utriangle = (
freq: number = 1,
times: number = 1,
offset: number = 0,
): number => {
utriangle = (freq: number = 1, phase: number = 0): number => {
/**
* Returns a triangle wave between 0 and 1.
*
Expand All @@ -1781,13 +1758,11 @@ export class UserAPI {
* @returns A triangle wave between 0 and 1
* @see triangle
*/
return ((this.triangle(freq, times, offset) + 1) / 2) * times;
return ((this.triangle(freq, phase) + 1) / 2);
};

square = (
freq: number = 1,
times: number = 1,
offset: number = 0,
duty: number = 0.5,
): number => {
/**
Expand All @@ -1800,16 +1775,11 @@ export class UserAPI {
* @see noise
*/
const period = 1 / freq;
const t = (Date.now() / 1000 + offset) % period;
return (t / period < duty ? 1 : -1) * times;
const t = (Date.now() / 1000 ) % period;
return (t / period < duty ? 1 : -1);
};

usquare = (
freq: number = 1,
times: number = 1,
offset: number = 0,
duty: number = 0.5,
): number => {
usquare = (freq: number = 1, duty: number = 0.5): number => {
/**
* Returns a square wave between 0 and 1.
*
Expand All @@ -1818,10 +1788,10 @@ export class UserAPI {
* @returns A square wave between 0 and 1
* @see square
*/
return ((this.square(freq, times, offset, duty) + 1) / 2) * times;
return ((this.square(freq, duty) + 1) / 2);
};

noise = (times: number = 1): number => {
noise = (): number => {
/**
* Returns a random value between -1 and 1.
*
Expand All @@ -1832,7 +1802,17 @@ export class UserAPI {
* @see sine
* @see noise
*/
return (this.randomGen() * 2 - 1) * times;
return (this.randomGen() * 2 - 1);
};

unoise = (): number => {
/**
* Returns a random value between 0 and 1.
*
* @returns A random value between 0 and 1
* @see noise
*/
return ((this.noise() + 1) / 2);
};

// =============================================================
Expand Down
19 changes: 19 additions & 0 deletions src/documentation/patterns/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,25 @@ beat(1) :: script(1, 3, 5)
- <ic>mean(...values: number[]): number</ic>: returns the arithmetic mean of a list of numbers.
- <ic>limit(value: number, min: number, max: number): number</ic>: Limits a value between a minimum and a maximum.
### Scaling functions
There are some very useful scaling methods taken from **SuperCollider**. You can call these on any number:
- <ic>.linlin(inMin: number, inMax: number, outMin: number, outMax: number)</ic>: scale linearly from one range to another.
- <ic>.linexp(inMin: number, inMax: number, outMin: number, outMax: number)</ic>: scale a linear range to an exponential range.
- <ic>.explin(inMin: number, inMax: number, outMin: number, outMax: number)</ic>: scale an exponential range to a linear range.
- <ic>.expexp(inMin: number, inMax: number, outMin: number, outMax: number)</ic>: scale an exponential range to another exponential range.
- <ic>.lincurve(inMin: number, inMax: number, outMin: number, outMax: number, curve: number)</ic>: scale a number from one range to another following a specific curve.
- <ic>curve: number</ic>: <ic>0</ic> is linear, <ic>< 0</ic> is concave, negatively curved, <ic>> 0</ic> is convex, positively curved
${makeExample(
"Scaling an LFO",
`usine(1/2).linlin(0, 1, 0, 100)`,
true,
)}
## Delay functions
- <ic>delay(ms: number, func: Function): void</ic>: Delays the execution of a function by a given number of milliseconds.
Expand Down
20 changes: 10 additions & 10 deletions src/documentation/patterns/lfos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,37 @@ export const lfos = (application: Editor): string => {
Low Frequency Oscillators (_LFOs_) are an important piece in any digital audio workstation or synthesizer. Topos implements some basic waveforms you can play with to automatically modulate your paremeters.
- <ic>sine(freq: number = 1, times: number = 1, offset: number= 0): number</ic>: returns a sinusoïdal oscillation between <ic>-1</ic> and <ic>1</ic>.
- <ic>sine(freq: number = 1, phase: number = 0): number</ic>: returns a sinusoïdal oscillation between <ic>-1</ic> and <ic>1</ic>.
- <ic>freq</ic> : frequency in hertz.
- <ic>times</ic> : output value multiplier.
- <ic>offset</ic>: linear offset.
- <ic>usine(freq: number = 1, times: number = 1, offset: number= 0): number</ic>: returns a sinusoïdal oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_.
- <ic>phase</ic> : phase amount (adds or substract from current time point).
- <ic>usine(freq: number = 1, phase: number = 0): number</ic>: returns a sinusoïdal oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_.
${makeExample(
"Modulating the speed of a sample player using a sine LFO",
`beat(.25) && snd('cp').speed(1 + usine(0.25) * 2).out()`,
true,
)};
- <ic>triangle(freq: number = 1, times: number = 1, offset: number= 0): number</ic>: returns a triangle oscillation between <ic>-1</ic> and <ic>1</ic>.
- <ic>utriangle(freq: number = 1, times: number = 1, offset: number= 0): number</ic>: returns a triangle oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_.
- <ic>triangle(freq: number = 1, phase: number = 0): number</ic>: returns a triangle oscillation between <ic>-1</ic> and <ic>1</ic>.
- <ic>utriangle(freq: number = 1, phase: number = 0): number</ic>: returns a triangle oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_.
${makeExample(
"Modulating the speed of a sample player using a triangle LFO",
`beat(.25) && snd('cp').speed(1 + utriangle(0.25) * 2).out()`,
true,
)}
- <ic>saw(freq: number = 1, times: number = 1, offset: number= 0): number</ic>: returns a sawtooth-like oscillation between <ic>-1</ic> and <ic>1</ic>.
- <ic>usaw(freq: number = 1, times: number = 1, offset: number= 0): number</ic>: returns a sawtooth-like oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_.
- <ic>saw(freq: number = 1, phase: number = 0): number</ic>: returns a sawtooth-like oscillation between <ic>-1</ic> and <ic>1</ic>.
- <ic>usaw(freq: number = 1, phase: number = 0): number</ic>: returns a sawtooth-like oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_.
${makeExample(
"Modulating the speed of a sample player using a saw LFO",
`beat(.25) && snd('cp').speed(1 + usaw(0.25) * 2).out()`,
true,
)}
- <ic>square(freq: number = 1, times: number = 1, offset: number= 0, duty: number = .5): number</ic>: returns a square wave oscillation between <ic>-1</ic> and <ic>1</ic>. You can also control the duty cycle using the <ic>duty</ic> parameter.
- <ic>usquare(freq: number = 1, times: number = 1, offset: number= 0, duty: number = .5): number</ic>: returns a square wave oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_. You can also control the duty cycle using the <ic>duty</ic> parameter.
- <ic>square(freq: number = 1, duty: number = .5): number</ic>: returns a square wave oscillation between <ic>-1</ic> and <ic>1</ic>. You can also control the duty cycle using the <ic>duty</ic> parameter.
- <ic>usquare(freq: number = 1, duty: number = .5): number</ic>: returns a square wave oscillation between <ic>0</ic> and <ic>1</ic>. The <ic>u</ic> stands for _unipolar_. You can also control the duty cycle using the <ic>duty</ic> parameter.
${makeExample(
"Modulating the speed of a sample player using a square LFO",
Expand All @@ -48,6 +47,7 @@ ${makeExample(
)};
- <ic>noise(times: number = 1)</ic>: returns a random value between -1 and 1.
- <ic>unoise(times: number = 1)</ic>: returns a random value between 0 and 1.
${makeExample(
"Modulating the speed of a sample player using noise",
Expand Down
Loading

0 comments on commit d0f6223

Please sign in to comment.