split documentation with new files
This commit is contained in:
@ -133,6 +133,7 @@
|
|||||||
<p rel="noopener noreferrer" id="docs_interface" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Interface</p>
|
<p rel="noopener noreferrer" id="docs_interface" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Interface</p>
|
||||||
<p rel="noopener noreferrer" id="docs_interaction" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Interaction</p>
|
<p rel="noopener noreferrer" id="docs_interaction" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Interaction</p>
|
||||||
<p rel="noopener noreferrer" id="docs_shortcuts" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Keyboard</p>
|
<p rel="noopener noreferrer" id="docs_shortcuts" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Keyboard</p>
|
||||||
|
<p rel="noopener noreferrer" id="docs_mouse" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Mouse</p>
|
||||||
<p rel="noopener noreferrer" id="docs_code" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Coding</p>
|
<p rel="noopener noreferrer" id="docs_code" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Coding</p>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
@ -164,6 +165,7 @@
|
|||||||
<details class="space-y-2" open=true>
|
<details class="space-y-2" open=true>
|
||||||
<summary class="font-semibold lg:text-xl text-orange-300">More</summary>
|
<summary class="font-semibold lg:text-xl text-orange-300">More</summary>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
|
<a rel="noopener noreferrer" id="docs_synchronisation" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Synchronisation</a>
|
||||||
<a rel="noopener noreferrer" id="docs_oscilloscope" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Oscilloscope</a>
|
<a rel="noopener noreferrer" id="docs_oscilloscope" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Oscilloscope</a>
|
||||||
<a rel="noopener noreferrer" id="docs_bonus" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Bonus/Trivia</a>
|
<a rel="noopener noreferrer" id="docs_bonus" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">Bonus/Trivia</a>
|
||||||
<a rel="noopener noreferrer" id="docs_about" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">About Topos</a>
|
<a rel="noopener noreferrer" id="docs_about" class="pl-2 pr-2 lg:text-xl text-sm hover:bg-neutral-800 py-1 my-1 rounded-lg">About Topos</a>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { type Editor } from "./main";
|
import { type Editor } from "./main";
|
||||||
import { introduction } from "./documentation/introduction";
|
import { introduction } from "./documentation/introduction";
|
||||||
import { oscilloscope } from "./documentation/oscilloscope";
|
import { oscilloscope } from "./documentation/oscilloscope";
|
||||||
|
import { synchronisation } from "./documentation/synchronisation";
|
||||||
import { samples } from "./documentation/samples";
|
import { samples } from "./documentation/samples";
|
||||||
import { chaining } from "./documentation/chaining";
|
import { chaining } from "./documentation/chaining";
|
||||||
import { software_interface } from "./documentation/interface";
|
import { software_interface } from "./documentation/interface";
|
||||||
@ -11,6 +12,7 @@ import { code } from "./documentation/code";
|
|||||||
import { about } from "./documentation/about";
|
import { about } from "./documentation/about";
|
||||||
import { sound } from "./documentation/engine";
|
import { sound } from "./documentation/engine";
|
||||||
import { shortcuts } from "./documentation/keyboard";
|
import { shortcuts } from "./documentation/keyboard";
|
||||||
|
import { mouse } from "./documentation/mouse";
|
||||||
import { patterns } from "./documentation/patterns";
|
import { patterns } from "./documentation/patterns";
|
||||||
import { functions } from "./documentation/functions";
|
import { functions } from "./documentation/functions";
|
||||||
import { variables } from "./documentation/variables";
|
import { variables } from "./documentation/variables";
|
||||||
@ -58,7 +60,6 @@ export const makeExampleFactory = (application: Editor): Function => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const documentation_factory = (application: Editor) => {
|
export const documentation_factory = (application: Editor) => {
|
||||||
|
|
||||||
// Initialize a data structure to store code examples by their unique IDs
|
// Initialize a data structure to store code examples by their unique IDs
|
||||||
application.api.codeExamples = {};
|
application.api.codeExamples = {};
|
||||||
|
|
||||||
@ -80,15 +81,16 @@ export const documentation_factory = (application: Editor) => {
|
|||||||
probabilities: probabilities(application),
|
probabilities: probabilities(application),
|
||||||
functions: functions(application),
|
functions: functions(application),
|
||||||
reference: reference(),
|
reference: reference(),
|
||||||
shortcuts: shortcuts(),
|
shortcuts: shortcuts(application),
|
||||||
|
mouse: mouse(application),
|
||||||
oscilloscope: oscilloscope(application),
|
oscilloscope: oscilloscope(application),
|
||||||
|
synchronisation: synchronisation(application),
|
||||||
bonus: bonus(application),
|
bonus: bonus(application),
|
||||||
about: about(),
|
about: about(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const showDocumentation = (app: Editor) => {
|
export const showDocumentation = (app: Editor) => {
|
||||||
|
|
||||||
if (document.getElementById("app")?.classList.contains("hidden")) {
|
if (document.getElementById("app")?.classList.contains("hidden")) {
|
||||||
document.getElementById("app")?.classList.remove("hidden");
|
document.getElementById("app")?.classList.remove("hidden");
|
||||||
document.getElementById("documentation")?.classList.add("hidden");
|
document.getElementById("documentation")?.classList.add("hidden");
|
||||||
|
|||||||
@ -39,7 +39,8 @@ export const installInterfaceLogic = (app: Editor) => {
|
|||||||
(app.interface.time_position_checkbox as HTMLInputElement).checked =
|
(app.interface.time_position_checkbox as HTMLInputElement).checked =
|
||||||
app.settings.time_position;
|
app.settings.time_position;
|
||||||
(app.interface.tips_checkbox as HTMLInputElement).checked = app.settings.tips;
|
(app.interface.tips_checkbox as HTMLInputElement).checked = app.settings.tips;
|
||||||
(app.interface.completion_checkbox as HTMLInputElement).checked = app.settings.completions;
|
(app.interface.completion_checkbox as HTMLInputElement).checked =
|
||||||
|
app.settings.completions;
|
||||||
|
|
||||||
(app.interface.midi_clock_checkbox as HTMLInputElement).checked =
|
(app.interface.midi_clock_checkbox as HTMLInputElement).checked =
|
||||||
app.settings.send_clock;
|
app.settings.send_clock;
|
||||||
@ -392,7 +393,8 @@ export const installInterfaceLogic = (app: Editor) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.interface.completion_checkbox.addEventListener("change", () => {
|
app.interface.completion_checkbox.addEventListener("change", () => {
|
||||||
let checked = (app.interface.completion_checkbox as HTMLInputElement).checked
|
let checked = (app.interface.completion_checkbox as HTMLInputElement)
|
||||||
|
.checked
|
||||||
? true
|
? true
|
||||||
: false;
|
: false;
|
||||||
app.settings.completions = checked;
|
app.settings.completions = checked;
|
||||||
@ -470,6 +472,8 @@ export const installInterfaceLogic = (app: Editor) => {
|
|||||||
"probabilities",
|
"probabilities",
|
||||||
"variables",
|
"variables",
|
||||||
// "reference",
|
// "reference",
|
||||||
|
"synchronisation",
|
||||||
|
"mouse",
|
||||||
"shortcuts",
|
"shortcuts",
|
||||||
"about",
|
"about",
|
||||||
"bonus",
|
"bonus",
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../main";
|
import { type Editor } from "../main";
|
||||||
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const interaction = (application: Editor): string => {
|
export const interaction = (application: Editor): string => {
|
||||||
@ -7,18 +7,8 @@ export const interaction = (application: Editor): string => {
|
|||||||
return `
|
return `
|
||||||
# Interaction
|
# Interaction
|
||||||
|
|
||||||
Topos can interact with the physical world or react to events coming from outside the system (_MIDI_, physical control, etc).
|
Topos can interact with the physical world or react to events coming from outside the system (_MIDI_, physical control, etc). By creating interactions with your mouse, keyboard or controllers, you can make your performance more dynamic and/or easier to control.
|
||||||
|
|
||||||
## Fill
|
|
||||||
|
|
||||||
By pressing the ${key_shortcut('Alt')} key, you can trigger the <ic>Fill</ic> mode which can either be <ic>true</ic> or <ic>false</ic>. The fill will be set to <ic>true</ic> as long as the key is held. Try pressing ${key_shortcut('Alt')} when playing this example:
|
|
||||||
|
|
||||||
${makeExample(
|
|
||||||
"Claping twice as fast with fill",
|
|
||||||
`
|
|
||||||
beat(fill() ? 1/4 : 1/2)::sound('cp').out()
|
|
||||||
`, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
## MIDI input
|
## MIDI input
|
||||||
|
|
||||||
@ -28,74 +18,81 @@ Topos can use MIDI input to estimate the BPM from incoming Clock messages and to
|
|||||||
|
|
||||||
MIDI input can be enabled in the settings panel. Once you have done that, you can use the following functions to control values. All methods have channel parameter as optional value to receive only notes from a certain channel:
|
MIDI input can be enabled in the settings panel. Once you have done that, you can use the following functions to control values. All methods have channel parameter as optional value to receive only notes from a certain channel:
|
||||||
* <ic>active_notes(channel?: number)</ic>: returns array of the active notes / pressed keys as an array of MIDI note numbers (0-127). Returns undefined if no notes are active.
|
* <ic>active_notes(channel?: number)</ic>: returns array of the active notes / pressed keys as an array of MIDI note numbers (0-127). Returns undefined if no notes are active.
|
||||||
* <ic>sticky_notes(channel?: number)</ic>: returns array of the last pressed keys as an array of MIDI note numbers (0-127). Notes are added and removed from the list with the "Note on"-event. Returns undefined if no keys have been pressed.
|
|
||||||
* <ic>last_note(channel?: number)</ic>: returns the last note that has been received. Returns 60 if no other notes have been received.
|
|
||||||
* <ic>buffer()</ic>: return true if there are notes in the buffer.
|
|
||||||
* <ic>buffer_note(channel?: number)</ic>: returns last unread note that has been received. Note is fetched and removed from start of the buffer once this is called. Returns undefined if no notes have been received.
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play active notes as chords",
|
"Play active notes as chords",
|
||||||
`
|
`
|
||||||
beat(1) && active_notes() && sound('sine').chord(active_notes()).out()
|
beat(1) && active_notes() && sound('sine').chord(active_notes()).out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play active notes as arpeggios",
|
"Play active notes as arpeggios",
|
||||||
`
|
`
|
||||||
beat(0.25) && active_notes() && sound('juno').note(
|
beat(0.25) && active_notes() && sound('juno').note(
|
||||||
active_notes().beat(0.5)+[12,24].beat(0.25)
|
active_notes().beat(0.5)+[12,24].beat(0.25)
|
||||||
).cutoff(300 + usine(1/4) * 2000).out()
|
).cutoff(300 + usine(1/4) * 2000).out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
* <ic>sticky_notes(channel?: number)</ic>: returns array of the last pressed keys as an array of MIDI note numbers (0-127). Notes are added and removed from the list with the "Note on"-event. Returns undefined if no keys have been pressed.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play continous arpeggio with sticky notes",
|
"Play continous arpeggio with sticky notes",
|
||||||
`
|
`
|
||||||
beat(0.25) && sticky_notes() && sound('arp')
|
beat(0.25) && sticky_notes() && sound('arp')
|
||||||
.note(sticky_notes().palindrome().beat(0.25)).out()
|
.note(sticky_notes().palindrome().beat(0.25)).out()
|
||||||
`,
|
`,
|
||||||
false
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
* <ic>last_note(channel?: number)</ic>: returns the last note that has been received. Returns 60 if no other notes have been received.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play last note",
|
"Play last note",
|
||||||
`
|
`
|
||||||
beat(0.5) && sound('sawtooth').note(last_note())
|
beat(0.5) && sound('sawtooth').note(last_note())
|
||||||
.vib([1, 3, 5].beat(1))
|
.vib([1, 3, 5].beat(1))
|
||||||
.vibmod([1,3,2,4].beat(2)).out()
|
.vibmod([1,3,2,4].beat(2)).out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
* <ic>buffer()</ic>: return true if there are notes in the buffer.
|
||||||
|
* <ic>buffer_note(channel?: number)</ic>: returns last unread note that has been received. Note is fetched and removed from start of the buffer once this is called. Returns undefined if no notes have been received.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play buffered note",
|
"Play buffered note",
|
||||||
`
|
`
|
||||||
beat(1) && buffer() && sound('sine').note(buffer_note()).out()
|
beat(1) && buffer() && sound('sine').note(buffer_note()).out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### MIDI CC Input
|
### MIDI CC Input
|
||||||
|
|
||||||
Midi CC messages can be used to control any value in Topos. MIDI input can be defined in Settings and last received CC message can be used to control any numeric value within Topos.
|
Midi CC messages can be used to control any value in Topos. MIDI input can be defined in Settings and last received CC message can be used to control any numeric value within Topos.
|
||||||
|
|
||||||
Currently supported methods for CC input are:
|
Currently supported methods for CC input are:
|
||||||
* <ic>last_cc(control: number, channel?: number): Returns last received CC value for given control number (and optional channel). By default last CC value is last value from ANY channel or 64 if no CC messages have been received.
|
* <ic>last_cc(control: number, channel?: number)</ic>: Returns last received CC value for given control number (and optional channel). By default last CC value is last value from ANY channel or 64 if no CC messages have been received.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play notes with cc",
|
"Play notes with cc",
|
||||||
`
|
`
|
||||||
beat(0.5) && sound('arp').note(last_cc(74)).out()
|
beat(0.5) && sound('arp').note(last_cc(74)).out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Control everything with CCs",
|
"Control everything with CCs",
|
||||||
`
|
`
|
||||||
beat(0.5) :: sound('sine')
|
beat(0.5) :: sound('sine')
|
||||||
.freq(last_cc(75)*3)
|
.freq(last_cc(75)*3)
|
||||||
.cutoff(last_cc(76)*2*usine())
|
.cutoff(last_cc(76)*2*usine())
|
||||||
@ -108,59 +105,20 @@ beat(last_cc(74)/127*.5) :: sound('sine')
|
|||||||
.sustain(last_cc(74)/127*.25)
|
.sustain(last_cc(74)/127*.25)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
### Run scripts with MIDI
|
## Run scripts with MIDI
|
||||||
|
|
||||||
MIDI note messages with channels can also be used to trigger scripts.
|
MIDI note messages with channels can also be used to trigger scripts. This can be enabled in the settings panel by setting _Route channels to scripts_.
|
||||||
This can be enabled in the settings panel by setting _Route channels to scripts_.
|
|
||||||
|
|
||||||
### MIDI clock Synchronisation
|
## MIDI clock Synchronisation
|
||||||
|
|
||||||
Topos can controlled from external hadware or software using MIDI clock messages. To enable this feature, you need to connect a MIDI input as Midi Clock in the settings panel.
|
Topos can controlled from external hadware or software using MIDI clock messages. To enable this feature, you need to connect a MIDI input as Midi Clock in the settings panel.
|
||||||
Once you have done that, Topos will listen to incoming Clock messages and will use them to estimate the current BPM. Topos will also listen to <ic>Start</ic>, <ic>Stop</ic> and <ic>Continue</ic> messages to start and stop the evaluation.
|
Once you have done that, Topos will listen to incoming Clock messages and will use them to estimate the current BPM. Topos will also listen to <ic>Start</ic>, <ic>Stop</ic> and <ic>Continue</ic> messages to start and stop the evaluation.
|
||||||
Different MIDI devices can send clock at different resolution, define Clock PPQN in settings to match the resolution of your device.
|
Different MIDI devices can send clock at different resolution, define Clock PPQN in settings to match the resolution of your device.
|
||||||
|
|
||||||
## Mouse Input
|
|
||||||
|
|
||||||
You can get the current position of the mouse on the screen by using the following functions:
|
|
||||||
|
|
||||||
- <ic>mouseX()</ic>: the horizontal position of the mouse on the screen (as a floating point number).
|
|
||||||
- <ic>mouseY()</ic>: 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:
|
|
||||||
|
|
||||||
- <ic>noteX()</ic>: returns a MIDI note number (0-127) based on the horizontal position of the mouse on the screen.
|
|
||||||
- <ic>noteY()</ic>: 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
|
|
||||||
)}
|
|
||||||
|
|
||||||
## Scale output for lighted keys
|
## Scale output for lighted keys
|
||||||
|
|
||||||
Topos can output scales to external keyboards lighted keys using the following functions:
|
Topos can output scales to external keyboards lighted keys using the following functions:
|
||||||
@ -168,18 +126,13 @@ Topos can output scales to external keyboards lighted keys using the following f
|
|||||||
- <ic>show_scale(key: string, scale: string|int, channel?: number, port?: string|number, soundOff?: boolean): void</ic>: sends the scale as midi on messages to specified port and channel to light the keys of external keyboard. If soundOff is true, all sound off message will be sent after every note on message. This can be useful with some keyboards not supporting external channel for lightning or routing for the midi in to suppress the sound from incoming note on messages.
|
- <ic>show_scale(key: string, scale: string|int, channel?: number, port?: string|number, soundOff?: boolean): void</ic>: sends the scale as midi on messages to specified port and channel to light the keys of external keyboard. If soundOff is true, all sound off message will be sent after every note on message. This can be useful with some keyboards not supporting external channel for lightning or routing for the midi in to suppress the sound from incoming note on messages.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Show scale on external keyboard",
|
"Show scale on external keyboard",
|
||||||
`show_scale("F","aeolian",0,4)`,
|
`show_scale("F","aeolian",0,4)`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample("Hide scale", `hide_scale("F","aeolian",0,4)`, true)}
|
||||||
"Hide scale",
|
|
||||||
`hide_scale("F","aeolian",0,4)`,
|
|
||||||
true
|
|
||||||
)}
|
|
||||||
|
|
||||||
|
|
||||||
`
|
`;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
||||||
import { type Editor } from "../main";
|
import { type Editor } from "../main";
|
||||||
import topos_arch from './topos_arch.svg';
|
import topos_arch from "./topos_arch.svg";
|
||||||
import many_universes from './many_universes.svg';
|
import many_universes from "./many_universes.svg";
|
||||||
|
|
||||||
export const software_interface = (application: Editor): string => {
|
export const software_interface = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
return `
|
return `
|
||||||
# Interface
|
# Interface
|
||||||
|
|
||||||
The Topos interface is entirely dedicated to highlight the core concepts at play: _scripts_ and _universes_. By understanding the interface, you will already understand quite a lot about Topos and how to play music with it. Make sure to learn the dedicated keybindings as well and you will fly!
|
The Topos interface is modeled around the core concepts at play: _scripts_ and _universes_. By understanding the interface, you will already understand quite a lot about Topos and how to play music with it. Make sure to learn the dedicated keybindings as well and you will fly!
|
||||||
|
|
||||||
<object type="image/svg+xml" data=${topos_arch} style="width: 100%; height: auto; background-color: transparent"></object>
|
<object type="image/svg+xml" data=${topos_arch} style="width: 100%; height: auto; background-color: transparent"></object>
|
||||||
|
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
Every Topos session is composed of several small scripts. A set of scripts is called a _universe_. Every script is written using the JavaScript programming language and describes a musical or algorithmic process that takes place over time.
|
Every Topos session is composed of several scripts: **local**, **global** and **init** scripts. Considered as a whole, these scripts form a structure called a "_universe_". A "universe" is a set of functions, a song, a sketch from an improvisation, or whatever you would like to do with **Topos**. All the scripts are written using the JavaScript programming language. They describe a musical or algorithmic process. You can call them anytime.
|
||||||
|
|
||||||
- **the global script** (${key_shortcut(
|
- **the global script** (${key_shortcut(
|
||||||
"Ctrl + G"
|
"Ctrl + G"
|
||||||
@ -38,28 +38,34 @@ Every Topos session is composed of several small scripts. A set of scripts is ca
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"To take the most out of Topos...",
|
"Calling scripts to form a musical piece",
|
||||||
`// Write your code in multiple scripts. Use all the code buffers!
|
`
|
||||||
|
// Write your code in multiple scripts.
|
||||||
|
// Use all the code buffers!
|
||||||
beat(1) :: script(1)
|
beat(1) :: script(1)
|
||||||
flip(4) :: beat(.5) :: script(2)
|
flip(4) :: beat(.5) :: script(2)
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Script execution can become musical too!",
|
"Script execution can become musical too!",
|
||||||
`// You can play your scripts... algorithmically.
|
`
|
||||||
|
// You can play your scripts... algorithmically.
|
||||||
beat(1) :: script([1,3,5].pick())
|
beat(1) :: script([1,3,5].pick())
|
||||||
flip(4) :: beat([.5, .25].beat(16)) :: script([5,6,7,8].loop($(2)))
|
flip(4) :: beat([.5, .25].beat(16)) :: script([5,6,7,8].beat())
|
||||||
`,
|
`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
## Navigating the interface
|
||||||
|
|
||||||
There are some useful functions to help you manage your scripts:
|
The interface is centered around the manipulation of scripts. Take a look at the left bar:
|
||||||
|
- **pencil icon:** notes. Used to take project notes about your "_universe_".
|
||||||
|
- **down arrow**: init script. Runs once when the project is loaded.
|
||||||
|
- **text with note**: global script, it acts as the **conductor** for your piece.
|
||||||
|
- **folder icon**: local scripts (from 1 to 9).
|
||||||
|
|
||||||
- <ic>copy_script(from: number, to: number)</ic>: copy the content of a script to another.
|
|
||||||
- <ic>delete_script(index: number)</ic>: clear the content of a script. Warning: this is irreversible!
|
|
||||||
|
|
||||||
## Universes
|
## Universes
|
||||||
|
|
||||||
@ -87,5 +93,14 @@ There are some useful functions to help you manage your universes:
|
|||||||
- Topos will automatically fetch and switch to the universe that was sent to you. Your previous universe is still accessible if you switch to it, don't worry!
|
- Topos will automatically fetch and switch to the universe that was sent to you. Your previous universe is still accessible if you switch to it, don't worry!
|
||||||
|
|
||||||
**Note:** links are currently super long and unsharable! Sorry about that, minifying takes a server and we don't have one yet. We will fix that soon. In the meantime, you can use a service like [tinyurl](https://tinyurl.com/) to shorten your links.
|
**Note:** links are currently super long and unsharable! Sorry about that, minifying takes a server and we don't have one yet. We will fix that soon. In the meantime, you can use a service like [tinyurl](https://tinyurl.com/) to shorten your links.
|
||||||
|
|
||||||
|
## More
|
||||||
|
|
||||||
|
There are some useful functions to help you manage your scripts:
|
||||||
|
|
||||||
|
- <ic>copy_script(from: number, to: number)</ic>: copy the content of a script to another.
|
||||||
|
- <ic>delete_script(index: number)</ic>: clear the content of a script. Warning: this is irreversible!
|
||||||
|
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,50 +12,48 @@ Welcome to the **Topos** documentation. You can jump here anytime by pressing ${
|
|||||||
)}. Press again to make the documentation disappear. Contributions are much appreciated! The documentation [lives here](https://github.com/Bubobubobubobubo/topos/tree/main/src/documentation).
|
)}. Press again to make the documentation disappear. Contributions are much appreciated! The documentation [lives here](https://github.com/Bubobubobubobubo/topos/tree/main/src/documentation).
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Welcome! Eval to get started",
|
"Welcome! Eval to get started",
|
||||||
examples[Math.floor(Math.random() * examples.length)],
|
examples[Math.floor(Math.random() * examples.length)],
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## What is Topos?
|
## What is Topos?
|
||||||
|
|
||||||
Topos is an _algorithmic_ sequencer. Topos is a _live coding_ environment. Think making music in real time through code. Code used as an expressive medium for musical improvisation! Topos uses small algorithms to represent musical sequences and processes.
|
Topos is an _algorithmic_ sequencer. Topos is also a _live coding_ environment. To sum it up, think: "making music in real time through code". Code used as an expressive medium for musical improvisation! Topos uses small algorithms to represent musical sequences and processes.
|
||||||
|
|
||||||
The syntax is voluntarily terse. The software is designed like this to encourage the user to write complex musical expressions very fast while on stage. The _live coder_ strives for the constant interaction with algorithms and sound during a musical performance. Topos is aiming to be a digital playground for live algorithmic music.
|
The syntax is voluntarily terse. The software is designed to encourage the user to write complex musical expressions very fast while on stage. The _live coder_ strives for the constant interaction with algorithms and sound during a musical performance. Topos is aiming to be a digital playground for live algorithmic music.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Small algorithms for direct musical expression",
|
"Small algorithms for direct musical expression",
|
||||||
`
|
`
|
||||||
beat(1) :: sound(['kick', 'hat', 'snare', 'hat'].beat(1)).out()
|
beat(1) :: sound(['kick', 'hat', 'snare', 'hat'].beat(1)).out()
|
||||||
beat(.5) :: sound('jvbass').note(35 + [0,12].beat()).out()
|
beat(.5) :: sound('jvbass').note(35 + [0,12].beat()).out()
|
||||||
beat([0.5, 0.25].beat(1)) :: sound('east')
|
beat([0.5, 0.25].beat(1)) :: sound('east')
|
||||||
.room(.9).speed(flip(4) ? 1 : 0.95).size(0.9).o(2).n($(1)).out()`,
|
.room(.9).speed(flip(4) ? 1 : 0.95).size(0.9).o(2).n($(1)).out()`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Computer music should be immediate and intuitive",
|
"Computer music should be immediate and intuitive",
|
||||||
`beat(.5)::snd('sine')
|
`beat(.5)::snd('sine')
|
||||||
.delay(0.5).delayt(0.25).delayfb(0.7)
|
.delay(0.5).delayt(0.25).delayfb(0.7)
|
||||||
.room(0.8).size(0.8)
|
.room(0.8).size(0.8)
|
||||||
.freq(mouseX()).out()`,
|
.freq(mouseX()).out()`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Making the web less dreadful, one beep at at time",
|
"Making the web less dreadful, one beep at at time",
|
||||||
`
|
`
|
||||||
beat(.5) :: sound('sid').n($(2))
|
beat(.5) :: sound('sid').n($(2))
|
||||||
.room(1).speed([1,2].pick()).out()
|
.room(1).speed([1,2].pick()).out()
|
||||||
beat(.25) :: sound('sid').note(
|
beat(.25) :: sound('sid').note(
|
||||||
[34, 36, 41].beat(.25) + [[0,-24].pick(),12].beat())
|
[34, 36, 41].beat(.25) + [[0,-24].pick(),12].beat())
|
||||||
.room(0.9).size(0.9).n(4).out()`,
|
.room(0.9).size(0.9).n(4).out()`,
|
||||||
false
|
false
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Teletype is/was an open source hardware module for Eurorack synthesizers. While the Teletype was initially born as an hardware module, Topos aims to be a web-browser based software sequencer from the same family! It is a sequencer, a scriptable interface, a companion for algorithmic music-making. Topos wishes to fullfill the same goal as the Teletype, keeping the same spirit alive on the web. It is free, open-source, and made to be shared and used by everyone.
|
Topos is deeply inspired by the [Monome Teletype](https://monome.org/). The Teletype is/was an open source hardware module for Eurorack synthesizers. While the Teletype was initially born as an hardware module, Topos aims to be a web-browser based cousin of it! It is a sequencer, a scriptable interface, a companion for algorithmic music-making. Topos wishes to fullfill the same goal as the Teletype, keeping the same spirit alive on the web. It is free, open-source, and made to be shared and used by everyone. Learn more about live coding on [livecoding.fr](https://livecoding.fr).
|
||||||
|
|
||||||
Learn more about live coding on [livecoding.fr](https://livecoding.fr).
|
|
||||||
|
|
||||||
## Demo Songs
|
## Demo Songs
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { key_shortcut } from "../Documentation";
|
import { key_shortcut } from "../Documentation";
|
||||||
|
import { type Editor } from "../main";
|
||||||
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const shortcuts = (): string => {
|
export const shortcuts = (app: Editor): string => {
|
||||||
|
let makeExample = makeExampleFactory(app);
|
||||||
return `
|
return `
|
||||||
# Keybindings
|
# Keybindings
|
||||||
|
|
||||||
@ -40,13 +43,34 @@ Topos is made to be controlled entirely with a keyboard. It is recommanded to st
|
|||||||
| Shortcut | Key | Description |
|
| Shortcut | Key | Description |
|
||||||
|----------|-------|------------------------------------------------------------|
|
|----------|-------|------------------------------------------------------------|
|
||||||
|Evaluate|${key_shortcut("Ctrl + Enter")}| Evaluate the current script |
|
|Evaluate|${key_shortcut("Ctrl + Enter")}| Evaluate the current script |
|
||||||
|Local Eval|${key_shortcut("Ctrl + F1")} to ${key_shortcut("Ctrl + F9")}|Local File Evaluation|
|
|Local Eval|${key_shortcut("Ctrl + F1")} to ${key_shortcut(
|
||||||
|Force Eval|${key_shortcut("Ctrl + Shift + Enter")}|Force evaluation of the current script|
|
"Ctrl + F9"
|
||||||
|
)}|Local File Evaluation|
|
||||||
|
|Force Eval|${key_shortcut(
|
||||||
|
"Ctrl + Shift + Enter"
|
||||||
|
)}|Force evaluation of the current script|
|
||||||
|
|
||||||
## Special
|
## Special
|
||||||
|
|
||||||
| Shortcut | Key | Description |
|
| Shortcut | Key | Description |
|
||||||
|----------|-------|------------------------------------------------------------|
|
|----------|-------|------------------------------------------------------------|
|
||||||
|Vim Mode|${key_shortcut("Ctrl + V")}| Switch between Vim and Normal Mode|
|
|Vim Mode|${key_shortcut("Ctrl + V")}| Switch between Vim and Normal Mode|
|
||||||
|
|
||||||
|
## Keyboard Fill
|
||||||
|
|
||||||
|
By pressing the ${key_shortcut(
|
||||||
|
"Alt"
|
||||||
|
)} key, you can trigger the <ic>Fill</ic> mode which can either be <ic>true</ic> or <ic>false</ic>. The fill will be set to <ic>true</ic> as long as the key is held. Try pressing ${key_shortcut(
|
||||||
|
"Alt"
|
||||||
|
)} when playing this example:
|
||||||
|
|
||||||
|
${makeExample(
|
||||||
|
"Claping twice as fast with fill",
|
||||||
|
`
|
||||||
|
beat(fill() ? 1/4 : 1/2)::sound('cp').out()
|
||||||
|
`,
|
||||||
|
true
|
||||||
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
70
src/documentation/mouse.ts
Normal file
70
src/documentation/mouse.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { type Editor } from "../main";
|
||||||
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
|
export const mouse = (app: Editor): string => {
|
||||||
|
let makeExample = makeExampleFactory(app);
|
||||||
|
return `
|
||||||
|
## Mouse
|
||||||
|
|
||||||
|
Using the mouse is a fun way to control reactive code. It's basically an X/Y controller that you don't have to pay for! There are clever actions you can do with the mouse from generating notes to activating scripts conditionally!
|
||||||
|
|
||||||
|
## Mouse position
|
||||||
|
|
||||||
|
You can get the current position of the mouse on the screen by using the following functions:
|
||||||
|
|
||||||
|
- <ic>mouseX()</ic>: the horizontal position of the mouse on the screen (as a floating point number).
|
||||||
|
- <ic>mouseY()</ic>: 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:
|
||||||
|
|
||||||
|
- <ic>noteX()</ic>: returns a MIDI note number (0-127) based on the horizontal position of the mouse on the screen.
|
||||||
|
- <ic>noteY()</ic>: 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
|
||||||
|
)}
|
||||||
|
|
||||||
|
## Mouse and Arrays
|
||||||
|
|
||||||
|
You can use the mouse to explore the valuesq contained in an Array:
|
||||||
|
|
||||||
|
- <ic>mouseX()</ic>: returns a value from a list by splitting the horizontal space of the screen in _n_ sections.
|
||||||
|
- <ic>mouseY()</ic>: returns a value from a list by splitting the vertical space of the screen in _n_ sections.
|
||||||
|
|
||||||
|
|
||||||
|
${makeExample(
|
||||||
|
"Taking values out of an Array with the mouse",
|
||||||
|
`
|
||||||
|
log([1,2,3,4].mouseX())
|
||||||
|
log([4,5,6,7].mouseY())
|
||||||
|
|
||||||
|
`,
|
||||||
|
true
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
`;
|
||||||
|
};
|
||||||
30
src/documentation/synchronisation.ts
Normal file
30
src/documentation/synchronisation.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { type Editor } from "../main";
|
||||||
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
|
export const synchronisation = (app: Editor): string => {
|
||||||
|
// @ts-ignore
|
||||||
|
let makeExample = makeExampleFactory(app);
|
||||||
|
return `
|
||||||
|
# Synchronisation
|
||||||
|
|
||||||
|
Synchronisation is currently a work in progress. If you are a programmer and if you know something about the topic, please help us to make it work! In the meantime, Topos can already be synchronised but it takes some getting used to.
|
||||||
|
|
||||||
|
## MIDI clock Synchronisation
|
||||||
|
|
||||||
|
Topos can be controlled from external hadware or software using MIDI clock messages. The options to do so are located in the settings menu. You will need to connect an external MIDI controller or to ready virtual MIDI port.
|
||||||
|
|
||||||
|
1) Connect a MIDI input as MIDI Clock in the settings panel.
|
||||||
|
2) Topos will listen to incoming Clock messages and will use them to estimate the current BPM.
|
||||||
|
3) Topos will also listen to <ic>Start</ic>, <ic>Stop</ic> and <ic>Continue</ic> messages.
|
||||||
|
|
||||||
|
Different MIDI devices can send clock at different resolution, define Clock PPQN in settings to match the resolution of your device.
|
||||||
|
|
||||||
|
## Clock nudge
|
||||||
|
|
||||||
|
In the settings menu, you will find two ways to _nudge_ the clock, allowing you to finetune synchronisation:
|
||||||
|
- **clock nudge**: nudge the event clock backwards or forward in time (in milliseconds).
|
||||||
|
- **audio nudge**: nudge the **synths** and **sampler** forward (in milliseconds).
|
||||||
|
- note that you need to give some time to the system (2ms+) in order to give it enough time to load and play sounds.
|
||||||
|
|
||||||
|
`;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user