diff --git a/index.html b/index.html index f9bc378..3b4f2e3 100644 --- a/index.html +++ b/index.html @@ -127,6 +127,7 @@

Basics

Introduction

Interface

+

Interaction

Keyboard

Coding

diff --git a/src/Documentation.ts b/src/Documentation.ts index 05fc9fe..c3d30fb 100644 --- a/src/Documentation.ts +++ b/src/Documentation.ts @@ -3,6 +3,7 @@ import { introduction } from "./documentation/introduction"; import { samples } from "./documentation/samples"; import { chaining } from "./documentation/chaining"; import { software_interface } from "./documentation/interface"; +import { interaction } from "./documentation/interaction"; import { time } from "./documentation/time"; import { midi } from "./documentation/midi"; import { code } from "./documentation/code"; @@ -53,6 +54,7 @@ export const documentation_factory = (application: Editor) => { return { introduction: introduction(application), interface: software_interface(application), + interaction: interaction(application), code: code(application), time: time(application), sound: sound(application), diff --git a/src/documentation/functions.ts b/src/documentation/functions.ts index c9a3c6f..f14a6c5 100644 --- a/src/documentation/functions.ts +++ b/src/documentation/functions.ts @@ -17,21 +17,21 @@ By default, each script is independant from each other. Scripts live in their ow **Note:** since this example is running in the documentation, we cannot take advantage of the multiple scripts paradigm. Try to send a variable from the global file to the local file n°6. ${makeExample( - "Setting a global variable", - ` + "Setting a global variable", + ` v('my_cool_variable', 2) `, - true -)} + true + )} ${makeExample( - "Getting that variable back and printing!", - ` + "Getting that variable back and printing!", + ` // Note that we just use one argument log(v('my_cool_variable')) `, - false -)} + false + )} ## Counter and iterators @@ -50,30 +50,30 @@ You will often need to use iterators and/or counters to index over data structur **Note:** Counters also come with a secret syntax. They can be called with the **$** symbol! ${makeExample( - "Iterating over a list of samples using a counter", - ` + "Iterating over a list of samples using a counter", + ` rhythm(.25, 6, 8) :: sound('dr').n($(1)).end(.25).out() `, - true -)} + true + )} ${makeExample( - "Using a more complex counter", - ` + "Using a more complex counter", + ` // Limit is 20, step is 5 rhythm(.25, 6, 8) :: sound('dr').n($(1, 20, 5)).end(.25).out() `, - false -)} + false + )} ${makeExample( - "Calling the drunk mechanism", - ` + "Calling the drunk mechanism", + ` // Limit is 20, step is 5 rhythm(.25, 6, 8) :: sound('dr').n(drunk()).end(.25).out() `, - false -)} + false + )} ## Scripts @@ -84,61 +84,23 @@ You can control scripts programatically. This is the core concept of Topos after - copy_script(from: number, to: number): copies a local script denoted by its number to another local script. **This is a destructive operation!** ${makeExample( - "Calling a script! The most important feature!", - ` + "Calling a script! The most important feature!", + ` beat(1) :: script(1) `, - true -)} + true + )} ${makeExample( - "Calling mutliple scripts at the same time.", - ` + "Calling mutliple scripts at the same time.", + ` beat(1) :: script(1, 3, 5) `, - false -)} + false + )} -## Mouse - -You can get the current position of the mouse on the screen by using the following functions: - -- mouseX(): the horizontal position of the mouse on the screen (as a floating point number). -- mouseY(): the vertical position of the mouse on the screen (as a floating point number). - -${makeExample( - "FM Synthesizer controlled using the mouse", - ` -beat(.25) :: sound('sine') - .fmi(mouseX() / 100) - .fmh(mouseY() / 100) - .vel(0.2) - .room(0.9).out() -`, - true -)} - -Current mouse position can also be used to generate notes: - -- noteX(): returns a MIDI note number (0-127) based on the horizontal position of the mouse on the screen. -- noteY(): returns a MIDI note number (0-127) based on the vertical position of the mouse on the screen. - - -${makeExample( - "The same synthesizer, with note control!", - ` -beat(.25) :: sound('sine') - .fmi(mouseX() / 100) - .note(noteX()) - .fmh(mouseY() / 100) - .vel(0.2) - .room(0.9).out() -`, - true -)} - ## Low Frequency Oscillators 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. @@ -147,47 +109,47 @@ Low Frequency Oscillators (_LFOs_) are an important piece in any digital audio w - usine(freq: number = 1, offset: number= 0): number: returns a sinusoïdal oscillation between 0 and 1. The u 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 -)}; + "Modulating the speed of a sample player using a sine LFO", + `beat(.25) && snd('cp').speed(1 + usine(0.25) * 2).out()`, + true + )}; - triangle(freq: number = 1, offset: number= 0): number: returns a triangle oscillation between -1 and 1. - utriangle(freq: number = 1, offset: number= 0): number: returns a triangle oscillation between 0 and 1. The u 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 -)} + "Modulating the speed of a sample player using a triangle LFO", + `beat(.25) && snd('cp').speed(1 + utriangle(0.25) * 2).out()`, + true + )} - saw(freq: number = 1, offset: number= 0): number: returns a sawtooth-like oscillation between -1 and 1. - usaw(freq: number = 1, offset: number= 0): number: returns a sawtooth-like oscillation between 0 and 1. The u 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 -)} + "Modulating the speed of a sample player using a saw LFO", + `beat(.25) && snd('cp').speed(1 + usaw(0.25) * 2).out()`, + true + )} - square(freq: number = 1, offset: number= 0, duty: number = .5): number: returns a square wave oscillation between -1 and 1. You can also control the duty cycle using the duty parameter. - usquare(freq: number = 1, offset: number= 0, duty: number = .5): number: returns a square wave oscillation between 0 and 1. The u stands for _unipolar_. You can also control the duty cycle using the duty parameter. ${makeExample( - "Modulating the speed of a sample player using a square LFO", - `beat(.25) && snd('cp').speed(1 + usquare(0.25, 0, 0.25) * 2).out()`, - true -)}; + "Modulating the speed of a sample player using a square LFO", + `beat(.25) && snd('cp').speed(1 + usquare(0.25, 0, 0.25) * 2).out()`, + true + )}; - noise(): returns a random value between -1 and 1. ${makeExample( - "Modulating the speed of a sample player using noise", - `beat(.25) && snd('cp').speed(1 + noise() * 2).out()`, - true -)}; + "Modulating the speed of a sample player using noise", + `beat(.25) && snd('cp').speed(1 + noise() * 2).out()`, + true + )}; ## Probabilities @@ -197,12 +159,12 @@ There are some simple functions to play with probabilities. - irand(min: number, max:number): returns a random integer between min and max. Shorthands _ir()_ or _rI()_. ${makeExample( - "Bleep bloop, what were you expecting?", - ` + "Bleep bloop, what were you expecting?", + ` rhythm(0.125, 10, 16) :: sound('sid').n(4).note(50 + irand(50, 62) % 8).out() `, - true -)} + true + )} - prob(p: number): return true _p_% of time, false in other cases. @@ -210,14 +172,14 @@ rhythm(0.125, 10, 16) :: sound('sid').n(4).note(50 + irand(50, 62) % 8).out() ${makeExample( - "The Teletype experience!", - ` + "The Teletype experience!", + ` prob(50) :: script(1); prob(60) :: script(2); prob(80) :: script(toss() ? script(3) : script(4)) `, - true -)} + true + )} - seed(val: number|string): sets the seed of the random number generator. You can use a number or a string. The same seed will always return the same sequence of random numbers. @@ -242,28 +204,28 @@ By default chance operators will be evaluated 48 times within a beat. You can ch Examples: ${makeExample( - "Using chance operators", - ` + "Using chance operators", + ` rarely() :: sound('hh').out(); // Rarely 48 times is still a lot rarely(4) :: sound('bd').out(); // Rarely in 4 beats is bit less rarely(8) :: sound('east').out(); // Rarely in 8 beats is even less `, - true -)} + true + )} ${makeExample( - "Using chance with other operators", - ` + "Using chance with other operators", + ` frequently() :: beat(1) :: sound('kick').out(); often() :: beat(0.5) :: sound('hh').out(); sometimes() :: onbeat(1,3) :: sound('snare').out(); `, - true -)} + true + )} ${makeExample( - "Using chance with chaining", - ` + "Using chance with chaining", + ` beat(0.5) && sound("bd") .freq(100) .sometimes(s=>s.crush(2.5)) @@ -275,8 +237,8 @@ ${makeExample( .almostNever(n=>n.freq(400)) .out() `, - true -)} + true + )} ## Math functions @@ -290,24 +252,24 @@ ${makeExample( - delay(ms: number, func: Function): void: Delays the execution of a function by a given number of milliseconds. ${makeExample( - "Phased woodblocks", - ` + "Phased woodblocks", + ` // Some very low-budget version of phase music beat(.5) :: delay(usine(.125) * 80, () => sound('east').out()) beat(.5) :: delay(50, () => sound('east').out()) `, - true -)} + true + )} - delayr(ms: number, nb: number, func: Function): void: Delays the execution of a function by a given number of milliseconds, repeated a given number of times. ${makeExample( - "Another woodblock texture", - ` + "Another woodblock texture", + ` beat(1) :: delayr(50, 4, () => sound('east').speed([0.5,.25].beat()).out()) flip(2) :: beat(2) :: delayr(150, 4, () => sound('east').speed([0.5,.25].beat() * 4).out()) `, - true -)}; + true + )}; `; }; diff --git a/src/documentation/interaction.ts b/src/documentation/interaction.ts new file mode 100644 index 0000000..d48bdb7 --- /dev/null +++ b/src/documentation/interaction.ts @@ -0,0 +1,54 @@ +import { type Editor } from "../main"; +import { makeExampleFactory } from "../Documentation"; + +// @ts-ignore +export const interaction = (application: Editor): string => { + const makeExample = makeExampleFactory(application); + return ` +# Interaction + +Topos can interact with the physical world or react to events coming from outside the system (_MIDI_, physical control, etc). + + +## Mouse + +You can get the current position of the mouse on the screen by using the following functions: + +- mouseX(): the horizontal position of the mouse on the screen (as a floating point number). +- mouseY(): the vertical position of the mouse on the screen (as a floating point number). + +${makeExample( + "FM Synthesizer controlled using the mouse", + ` +beat(.25) :: sound('sine') + .fmi(mouseX() / 100) + .fmh(mouseY() / 100) + .vel(0.2) + .room(0.9).out() +`, + true + )} + +Current mouse position can also be used to generate notes: + +- noteX(): returns a MIDI note number (0-127) based on the horizontal position of the mouse on the screen. +- noteY(): returns a MIDI note number (0-127) based on the vertical position of the mouse on the screen. + + +${makeExample( + "The same synthesizer, with note control!", + ` +beat(.25) :: sound('sine') + .fmi(mouseX() / 100) + .note(noteX()) + .fmh(mouseY() / 100) + .vel(0.2) + .room(0.9).out() +`, + true + )} + + + +` +} diff --git a/src/main.ts b/src/main.ts index f9cb995..aa87386 100644 --- a/src/main.ts +++ b/src/main.ts @@ -37,7 +37,7 @@ import { makeStringExtensions } from "./StringExtensions"; localStorage.openpages = Date.now(); window.addEventListener( "storage", - function (e) { + function(e) { if (e.key == "openpages") { // Listen if anybody else is opening the same page! localStorage.page_available = Date.now(); @@ -827,6 +827,7 @@ export class Editor { [ "introduction", "interface", + "interaction", "code", "time", "sound",