First batch of code cleaning
This commit is contained in:
@ -2,14 +2,14 @@ import { type Editor } from "./main";
|
|||||||
|
|
||||||
export type ElementMap = {
|
export type ElementMap = {
|
||||||
[key: string]:
|
[key: string]:
|
||||||
| HTMLElement
|
| HTMLElement
|
||||||
| HTMLButtonElement
|
| HTMLButtonElement
|
||||||
| HTMLDivElement
|
| HTMLDivElement
|
||||||
| HTMLInputElement
|
| HTMLInputElement
|
||||||
| HTMLSelectElement
|
| HTMLSelectElement
|
||||||
| HTMLCanvasElement
|
| HTMLCanvasElement
|
||||||
| HTMLFormElement
|
| HTMLFormElement
|
||||||
| HTMLInputElement;
|
| HTMLInputElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const singleElements = {
|
export const singleElements = {
|
||||||
@ -57,7 +57,6 @@ export const singleElements = {
|
|||||||
hydra_canvas: "hydra-bg",
|
hydra_canvas: "hydra-bg",
|
||||||
feedback: "feedback",
|
feedback: "feedback",
|
||||||
drawings: "drawings",
|
drawings: "drawings",
|
||||||
scope: "scope",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buttonGroups = {
|
export const buttonGroups = {
|
||||||
|
|||||||
@ -321,7 +321,7 @@ export const installEditor = (app: Editor) => {
|
|||||||
),
|
),
|
||||||
editorSetup,
|
editorSetup,
|
||||||
app.themeCompartment.of(
|
app.themeCompartment.of(
|
||||||
getCodeMirrorTheme(app.getColorScheme("Tomorrow Night Burns")),
|
getCodeMirrorTheme(app.getColorScheme("Batman")),
|
||||||
// debug
|
// debug
|
||||||
),
|
),
|
||||||
app.chosenLanguage.of(javascript()),
|
app.chosenLanguage.of(javascript()),
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import type { Editor } from "./main";
|
import type { Editor } from "./main";
|
||||||
import type { File } from "./FileManagement";
|
import type { File } from "./FileManagement";
|
||||||
|
|
||||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||||
const codeReplace = (code: string): string => {
|
const codeReplace = (code: string): string => code.replace(/->|::/g, "&&");
|
||||||
return code.replace(/->|::/g, "&&");
|
const cache = new Map<string, Function>();
|
||||||
};
|
const MAX_CACHE_SIZE = 40;
|
||||||
|
|
||||||
const tryCatchWrapper = async (
|
async function tryCatchWrapper(application: Editor, code: string): Promise<boolean> {
|
||||||
application: Editor,
|
|
||||||
code: string,
|
|
||||||
): Promise<boolean> => {
|
|
||||||
/**
|
/**
|
||||||
* Wraps the provided code in a try-catch block and executes it.
|
* Wraps the provided code in a try-catch block and executes it.
|
||||||
*
|
*
|
||||||
@ -17,21 +14,15 @@ const tryCatchWrapper = async (
|
|||||||
* @param code - The code to be executed.
|
* @param code - The code to be executed.
|
||||||
* @returns A promise that resolves to a boolean indicating whether the code executed successfully or not.
|
* @returns A promise that resolves to a boolean indicating whether the code executed successfully or not.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await new Function(`"use strict"; ${codeReplace(code)}`).call(
|
await new Function(`"use strict"; ${codeReplace(code)}`).call(application.api);
|
||||||
application.api,
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
application.interface.error_line.innerHTML = error as string;
|
application.interface.error_line.innerHTML = error as string;
|
||||||
application.api._reportError(error as string);
|
application.api._reportError(error as string);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
const cache = new Map<string, Function>();
|
|
||||||
const MAX_CACHE_SIZE = 40;
|
|
||||||
|
|
||||||
const addFunctionToCache = (code: string, fn: Function) => {
|
const addFunctionToCache = (code: string, fn: Function) => {
|
||||||
/**
|
/**
|
||||||
@ -45,11 +36,8 @@ const addFunctionToCache = (code: string, fn: Function) => {
|
|||||||
cache.set(code, fn);
|
cache.set(code, fn);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tryEvaluate = async (
|
|
||||||
application: Editor,
|
export async function tryEvaluate(application: Editor, code: File, timeout = 5000): Promise<void> {
|
||||||
code: File,
|
|
||||||
timeout = 5000,
|
|
||||||
): Promise<void> => {
|
|
||||||
/**
|
/**
|
||||||
* Tries to evaluate the provided code within a specified timeout period.
|
* Tries to evaluate the provided code within a specified timeout period.
|
||||||
* Increments the evaluation count of the code file.
|
* Increments the evaluation count of the code file.
|
||||||
@ -63,39 +51,30 @@ export const tryEvaluate = async (
|
|||||||
code.evaluations!++;
|
code.evaluations!++;
|
||||||
const candidateCode = code.candidate;
|
const candidateCode = code.candidate;
|
||||||
|
|
||||||
try {
|
const cachedFunction = cache.get(candidateCode);
|
||||||
const cachedFunction = cache.get(candidateCode);
|
if (cachedFunction) {
|
||||||
if (cachedFunction) {
|
cachedFunction.call(application.api);
|
||||||
cachedFunction.call(application.api);
|
return;
|
||||||
} else {
|
|
||||||
const wrappedCode = `let i = ${code.evaluations}; ${candidateCode}`;
|
|
||||||
const isCodeValid = await Promise.race([
|
|
||||||
tryCatchWrapper(application, wrappedCode),
|
|
||||||
delay(timeout),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (isCodeValid) {
|
|
||||||
code.committed = code.candidate;
|
|
||||||
const newFunction = new Function(
|
|
||||||
`"use strict"; ${codeReplace(wrappedCode)}`,
|
|
||||||
);
|
|
||||||
addFunctionToCache(candidateCode, newFunction);
|
|
||||||
} else {
|
|
||||||
application.api.logOnce("Compilation error!");
|
|
||||||
await evaluate(application, code, timeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
application.interface.error_line.innerHTML = error as string;
|
|
||||||
application.api._reportError(error as string);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
export const evaluate = async (
|
const wrappedCode = `let i = ${code.evaluations}; ${candidateCode}`;
|
||||||
application: Editor,
|
const isCodeValid = await Promise.race([
|
||||||
code: File,
|
tryCatchWrapper(application, wrappedCode),
|
||||||
timeout = 1000,
|
delay(timeout)
|
||||||
): Promise<void> => {
|
]);
|
||||||
|
|
||||||
|
if (isCodeValid) {
|
||||||
|
code.committed = candidateCode;
|
||||||
|
const newFunction = new Function(`"use strict"; ${codeReplace(wrappedCode)}`);
|
||||||
|
addFunctionToCache(candidateCode, newFunction);
|
||||||
|
} else {
|
||||||
|
application.api.logOnce("Compilation error!");
|
||||||
|
await delay(100);
|
||||||
|
await tryEvaluate(application, code, timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function evaluate(application: Editor, code: File, timeout = 1000): Promise<void> {
|
||||||
/**
|
/**
|
||||||
* Evaluates the given code using the provided application and timeout.
|
* Evaluates the given code using the provided application and timeout.
|
||||||
* @param application The editor application.
|
* @param application The editor application.
|
||||||
@ -103,18 +82,17 @@ export const evaluate = async (
|
|||||||
* @param timeout The timeout value in milliseconds (default: 1000).
|
* @param timeout The timeout value in milliseconds (default: 1000).
|
||||||
* @returns A Promise that resolves when the evaluation is complete.
|
* @returns A Promise that resolves when the evaluation is complete.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await Promise.race([
|
await Promise.race([
|
||||||
tryCatchWrapper(application, code.committed as string),
|
tryCatchWrapper(application, code.committed as string),
|
||||||
delay(timeout),
|
delay(timeout)
|
||||||
]);
|
]);
|
||||||
if (code.evaluations) code.evaluations++;
|
code.evaluations!++;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
application.interface.error_line.innerHTML = error as string;
|
application.interface.error_line.innerHTML = error as string;
|
||||||
console.log(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const evaluateOnce = async (
|
export const evaluateOnce = async (
|
||||||
application: Editor,
|
application: Editor,
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
// import { tutorial_universe } from "./universes/tutorial";
|
|
||||||
import { gzipSync, decompressSync, strFromU8 } from "fflate";
|
import { gzipSync, decompressSync, strFromU8 } from "fflate";
|
||||||
// import { examples } from "./examples/excerpts";
|
|
||||||
import { type Editor } from "./main";
|
import { type Editor } from "./main";
|
||||||
import { uniqueNamesGenerator, colors, animals } from "unique-names-generator";
|
import { uniqueNamesGenerator, colors, animals } from "unique-names-generator";
|
||||||
import { tryEvaluate } from "./Evaluator";
|
import { tryEvaluate } from "./Evaluator";
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { type Editor } from "./main";
|
import { type Editor } from "./main";
|
||||||
import { vim } from "@replit/codemirror-vim";
|
import { vim } from "@replit/codemirror-vim";
|
||||||
import { tryEvaluate } from "./Evaluator";
|
import { tryEvaluate } from "./Evaluator";
|
||||||
import { hideDocumentation, showDocumentation } from "./Documentation";
|
import { hideDocumentation, showDocumentation } from "./documentation/Documentation";
|
||||||
import { openSettingsModal, openUniverseModal } from "./FileManagement";
|
import { openSettingsModal, openUniverseModal } from "./FileManagement";
|
||||||
|
|
||||||
export const registerFillKeys = (app: Editor) => {
|
export const registerFillKeys = (app: Editor) => {
|
||||||
@ -1,47 +0,0 @@
|
|||||||
class TransportProcessor extends AudioWorkletProcessor {
|
|
||||||
constructor(options) {
|
|
||||||
super(options);
|
|
||||||
this.port.addEventListener("message", this.handleMessage);
|
|
||||||
this.port.start();
|
|
||||||
this.nudge = 0;
|
|
||||||
this.started = false;
|
|
||||||
this.bpm = 120;
|
|
||||||
this.ppqn = 48;
|
|
||||||
this.currentPulsePosition = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMessage = (message) => {
|
|
||||||
if (message.data && message.data.type === "ping") {
|
|
||||||
this.port.postMessage(message.data);
|
|
||||||
} else if (message.data.type === "start") {
|
|
||||||
this.started = true;
|
|
||||||
} else if (message.data.type === "pause") {
|
|
||||||
this.started = false;
|
|
||||||
} else if (message.data.type === "stop") {
|
|
||||||
this.started = false;
|
|
||||||
} else if (message.data.type === "bpm") {
|
|
||||||
this.bpm = message.data.value;
|
|
||||||
this.currentPulsePosition = currentTime;
|
|
||||||
} else if (message.data.type === "ppqn") {
|
|
||||||
this.ppqn = message.data.value;
|
|
||||||
this.currentPulsePosition = currentTime;
|
|
||||||
} else if (message.data.type === "nudge") {
|
|
||||||
this.nudge = message.data.value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process(inputs, outputs, parameters) {
|
|
||||||
if (this.started) {
|
|
||||||
const adjustedCurrentTime = currentTime + this.nudge / 100;
|
|
||||||
const beatNumber = adjustedCurrentTime / (60 / this.bpm);
|
|
||||||
const currentPulsePosition = Math.ceil(beatNumber * this.ppqn);
|
|
||||||
if (currentPulsePosition > this.currentPulsePosition) {
|
|
||||||
this.currentPulsePosition = currentPulsePosition;
|
|
||||||
this.port.postMessage({ type: "bang", bpm: this.bpm });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerProcessor("transport", TransportProcessor);
|
|
||||||
@ -8,7 +8,7 @@ import {
|
|||||||
hideDocumentation,
|
hideDocumentation,
|
||||||
showDocumentation,
|
showDocumentation,
|
||||||
updateDocumentationContent,
|
updateDocumentationContent,
|
||||||
} from "./Documentation";
|
} from "./documentation/Documentation";
|
||||||
import {
|
import {
|
||||||
type Universe,
|
type Universe,
|
||||||
template_universe,
|
template_universe,
|
||||||
@ -161,10 +161,10 @@ export const installInterfaceLogic = (app: Editor) => {
|
|||||||
app.interface.sample_indicator.innerText = "Loading...";
|
app.interface.sample_indicator.innerText = "Loading...";
|
||||||
app.interface.sample_indicator.classList.add("animate-pulse");
|
app.interface.sample_indicator.classList.add("animate-pulse");
|
||||||
await uploadSamplesToDB(samplesDBConfig, fileInput.files).then(() => {
|
await uploadSamplesToDB(samplesDBConfig, fileInput.files).then(() => {
|
||||||
registerSamplesFromDB(samplesDBConfig, () => {
|
registerSamplesFromDB(samplesDBConfig, () => {
|
||||||
app.interface.sample_indicator.innerText = "Import samples";
|
app.interface.sample_indicator.innerText = "Import samples";
|
||||||
app.interface.sample_indicator.classList.remove("animate-pulse");
|
app.interface.sample_indicator.classList.remove("animate-pulse");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
// @ts-ignore
|
import { TransportNode } from "./ClockNode";
|
||||||
import { TransportNode } from "./TransportNode";
|
import TransportProcessor from "./ClockProcessor?worker&url";
|
||||||
import TransportProcessor from "./TransportProcessor?worker&url";
|
import { Editor } from "../main";
|
||||||
import { Editor } from "./main";
|
|
||||||
|
|
||||||
export interface TimePosition {
|
export interface TimePosition {
|
||||||
/**
|
/**
|
||||||
@ -57,7 +56,7 @@ export class Clock {
|
|||||||
this.logicalTime = 0;
|
this.logicalTime = 0;
|
||||||
this.tick = 0;
|
this.tick = 0;
|
||||||
this._bpm = 120;
|
this._bpm = 120;
|
||||||
this._ppqn = 48;
|
this._ppqn = 48 * 2;
|
||||||
this.transportNode = null;
|
this.transportNode = null;
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
this.running = true;
|
this.running = true;
|
||||||
@ -189,6 +188,11 @@ export class Clock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public incrementTick(bpm: number) {
|
public incrementTick(bpm: number) {
|
||||||
|
/**
|
||||||
|
* Increment the clock tick by 1.
|
||||||
|
* @param bpm - The current beats per minute value
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
this.tick++;
|
this.tick++;
|
||||||
this.logicalTime += this.pulse_duration_at_bpm(bpm);
|
this.logicalTime += this.pulse_duration_at_bpm(bpm);
|
||||||
}
|
}
|
||||||
53
src/clock/ClockNode.d.ts
vendored
Normal file
53
src/clock/ClockNode.d.ts
vendored
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
export class TransportNode {
|
||||||
|
constructor(context: AudioContext, something, app: Editor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the clock.
|
||||||
|
*/
|
||||||
|
start(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the clock.
|
||||||
|
*/
|
||||||
|
stop(): void;
|
||||||
|
|
||||||
|
connect(destionation: AudioNode);
|
||||||
|
|
||||||
|
setNudge(nudge: number): void;
|
||||||
|
|
||||||
|
setPPQN(ppq: number): void;
|
||||||
|
|
||||||
|
setBPM(bpm: number): void;
|
||||||
|
|
||||||
|
pause(): void;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the clock to its initial state.
|
||||||
|
*/
|
||||||
|
reset(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the interval at which the clock updates.
|
||||||
|
* @param interval The interval in milliseconds.
|
||||||
|
*/
|
||||||
|
setInterval(interval: number): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current time of the clock.
|
||||||
|
* @returns The current time as a number.
|
||||||
|
*/
|
||||||
|
getTime(): number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClockNodeConfig {
|
||||||
|
/**
|
||||||
|
* The initial time for the clock.
|
||||||
|
*/
|
||||||
|
startTime?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval in milliseconds at which the clock should update.
|
||||||
|
*/
|
||||||
|
updateInterval?: number;
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { tryEvaluate } from "./Evaluator";
|
import { tryEvaluate } from "../Evaluator";
|
||||||
const zeroPad = (num, places) => String(num).padStart(places, "0");
|
const zeroPad = (num, places) => String(num).padStart(places, "0");
|
||||||
|
|
||||||
export class TransportNode extends AudioWorkletNode {
|
export class TransportNode extends AudioWorkletNode {
|
||||||
@ -12,9 +12,9 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
|
|
||||||
/** @type {(this: MessagePort, ev: MessageEvent<any>) => any} */
|
/** @type {(this: MessagePort, ev: MessageEvent<any>) => any} */
|
||||||
handleMessage = (message) => {
|
handleMessage = (message) => {
|
||||||
if(message.data) {
|
if (message.data) {
|
||||||
if (message.data.type === "bang") {
|
if (message.data.type === "bang") {
|
||||||
if(this.app.clock.running) {
|
if (this.app.clock.running) {
|
||||||
if (this.app.settings.send_clock) {
|
if (this.app.settings.send_clock) {
|
||||||
this.app.api.MidiConnection.sendMidiClock();
|
this.app.api.MidiConnection.sendMidiClock();
|
||||||
}
|
}
|
||||||
@ -60,6 +60,6 @@ export class TransportNode extends AudioWorkletNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
this.port.postMessage({type: "stop" });
|
this.port.postMessage({ type: "stop" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
47
src/clock/ClockProcessor.js
Normal file
47
src/clock/ClockProcessor.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
class TransportProcessor extends AudioWorkletProcessor {
|
||||||
|
constructor(options) {
|
||||||
|
super(options);
|
||||||
|
this.port.addEventListener("message", this.handleMessage);
|
||||||
|
this.port.start();
|
||||||
|
this.nudge = 0;
|
||||||
|
this.started = false;
|
||||||
|
this.bpm = 120;
|
||||||
|
this.ppqn = 48 * 2;
|
||||||
|
this.currentPulsePosition = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMessage = (message) => {
|
||||||
|
if (message.data && message.data.type === "ping") {
|
||||||
|
this.port.postMessage(message.data);
|
||||||
|
} else if (message.data.type === "start") {
|
||||||
|
this.started = true;
|
||||||
|
} else if (message.data.type === "pause") {
|
||||||
|
this.started = false;
|
||||||
|
} else if (message.data.type === "stop") {
|
||||||
|
this.started = false;
|
||||||
|
} else if (message.data.type === "bpm") {
|
||||||
|
this.bpm = message.data.value;
|
||||||
|
this.currentPulsePosition = currentTime;
|
||||||
|
} else if (message.data.type === "ppqn") {
|
||||||
|
this.ppqn = message.data.value;
|
||||||
|
this.currentPulsePosition = currentTime;
|
||||||
|
} else if (message.data.type === "nudge") {
|
||||||
|
this.nudge = message.data.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
process(inputs, outputs, parameters) {
|
||||||
|
if (this.started) {
|
||||||
|
const adjustedCurrentTime = currentTime + this.nudge / 100;
|
||||||
|
const beatNumber = adjustedCurrentTime / (60 / this.bpm);
|
||||||
|
const currentPulsePosition = Math.ceil(beatNumber * this.ppqn);
|
||||||
|
if (currentPulsePosition > this.currentPulsePosition) {
|
||||||
|
this.currentPulsePosition = currentPulsePosition;
|
||||||
|
this.port.postMessage({ type: "bang", bpm: this.bpm });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerProcessor("transport", TransportProcessor);
|
||||||
1229
src/colors.json
1229
src/colors.json
File diff suppressed because it is too large
Load Diff
@ -1,51 +1,29 @@
|
|||||||
import { Editor } from "./main";
|
import { Editor } from "../main";
|
||||||
// Basics
|
import { introduction, atelier, software_interface, shortcuts, code, mouse, interaction } from "./basics";
|
||||||
import { introduction } from "./documentation/basics/welcome";
|
import { amplitude, effects, sampler, synths, filters, audio_basics } from "./learning/audio_engine";
|
||||||
import { atelier } from "./documentation/basics/atelier";
|
import { lfos, functions, generators, variables, probabilities } from './patterns';
|
||||||
import { loading_samples } from "./documentation/learning/samples/loading_samples";
|
import { ziffers_basics, ziffers_scales, ziffers_rhythm, ziffers_algorithmic, ziffers_tonnetz, ziffers_syncing } from "./patterns/ziffers";
|
||||||
import { amplitude } from "./documentation/learning/audio_engine/amplitude";
|
import { loading_samples } from "./learning/samples/loading_samples";
|
||||||
import { effects } from "./documentation/learning/audio_engine/effects";
|
import { sample_banks } from "./learning/samples/sample_banks";
|
||||||
import { sampler } from "./documentation/learning/audio_engine/sampler";
|
import { sample_list } from "./learning/samples/sample_list";
|
||||||
import { sample_banks } from "./documentation/learning/samples/sample_banks";
|
import { oscilloscope } from "./more/oscilloscope";
|
||||||
import { audio_basics } from "./documentation/learning/audio_engine/audio_basics";
|
import { synchronisation } from "./more/synchronisation";
|
||||||
import { sample_list } from "./documentation/learning/samples/sample_list";
|
import { about } from "./more/about";
|
||||||
import { software_interface } from "./documentation/basics/interface";
|
import { bonus } from "./more/bonus";
|
||||||
import { shortcuts } from "./documentation/basics/keyboard";
|
import { visualization } from "./more/visualization";
|
||||||
import { code } from "./documentation/basics/code";
|
import { chaining } from "./patterns/chaining";
|
||||||
import { mouse } from "./documentation/basics/mouse";
|
import { time } from "./learning/time/time";
|
||||||
// More
|
import { linear_time } from "./learning/time/linear_time";
|
||||||
import { oscilloscope } from "./documentation/more/oscilloscope";
|
import { cyclical_time } from "./learning/time/cyclical_time";
|
||||||
import { synchronisation } from "./documentation/more/synchronisation";
|
import { long_forms } from "./learning/time/long_forms";
|
||||||
import { about } from "./documentation/more/about";
|
import { midi } from "./learning/midi";
|
||||||
import { bonus } from "./documentation/more/bonus";
|
import { osc } from "./learning/osc";
|
||||||
import { visualization } from "./documentation/more/visualization";
|
import { patterns } from "./patterns/patterns";
|
||||||
import { chaining } from "./documentation/patterns/chaining";
|
|
||||||
import { interaction } from "./documentation/basics/interaction";
|
|
||||||
import { time } from "./documentation/learning/time/time";
|
|
||||||
import { linear_time } from "./documentation/learning/time/linear_time";
|
|
||||||
import { cyclical_time } from "./documentation/learning/time/cyclical_time";
|
|
||||||
import { long_forms } from "./documentation/learning/time/long_forms";
|
|
||||||
import { midi } from "./documentation/learning/midi";
|
|
||||||
import { osc } from "./documentation/learning/osc";
|
|
||||||
import { patterns } from "./documentation/patterns/patterns";
|
|
||||||
import { functions } from "./documentation/patterns/functions";
|
|
||||||
import { generators } from "./documentation/patterns/generators";
|
|
||||||
import { variables } from "./documentation/patterns/variables";
|
|
||||||
import { probabilities } from "./documentation/patterns/probabilities";
|
|
||||||
import { lfos } from "./documentation/patterns/lfos";
|
|
||||||
import { ziffers_basics } from "./documentation/patterns/ziffers/ziffers_basics";
|
|
||||||
import { ziffers_scales } from "./documentation/patterns/ziffers/ziffers_scales";
|
|
||||||
import { ziffers_rhythm } from "./documentation/patterns/ziffers/ziffers_rhythm";
|
|
||||||
import { ziffers_algorithmic } from "./documentation/patterns/ziffers/ziffers_algorithmic";
|
|
||||||
import { ziffers_tonnetz } from "./documentation/patterns/ziffers/ziffers_tonnetz";
|
|
||||||
import { ziffers_syncing } from "./documentation/patterns/ziffers/ziffers_syncing";
|
|
||||||
import { synths } from "./documentation/learning/audio_engine/synths";
|
|
||||||
// Setting up the Markdown converter with syntax highlighting
|
// Setting up the Markdown converter with syntax highlighting
|
||||||
import showdown from "showdown";
|
import showdown from "showdown";
|
||||||
import showdownHighlight from "showdown-highlight";
|
import showdownHighlight from "showdown-highlight";
|
||||||
import "highlight.js/styles/atom-one-dark-reasonable.min.css";
|
import "highlight.js/styles/atom-one-dark-reasonable.min.css";
|
||||||
import { createDocumentationStyle } from "./DomElements";
|
import { createDocumentationStyle } from "../DomElements";
|
||||||
import { filters } from "./documentation/learning/audio_engine/filters";
|
|
||||||
showdown.setFlavor("github");
|
showdown.setFlavor("github");
|
||||||
|
|
||||||
type StyleBinding = {
|
type StyleBinding = {
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const atelier = (application: Editor): string => {
|
export const atelier = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory, key_shortcut } from "../../Documentation";
|
import { makeExampleFactory, key_shortcut } from "../Documentation";
|
||||||
|
|
||||||
export const code = (application: Editor): string => {
|
export const code = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -31,8 +31,8 @@ The code you enter in any of the scripts is evaluated in strict mode. This tells
|
|||||||
There are some techniques to keep code short and tidy. Don't try to write the shortest possible code! Use shortcuts when it makes sense. Take a look at the following examples:
|
There are some techniques to keep code short and tidy. Don't try to write the shortest possible code! Use shortcuts when it makes sense. Take a look at the following examples:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Shortening your if conditions",
|
"Shortening your if conditions",
|
||||||
`
|
`
|
||||||
// The && symbol (overriden by :: in Topos) is very often used for conditions!
|
// The && symbol (overriden by :: in Topos) is very often used for conditions!
|
||||||
beat(.75) :: snd('linnhats').n([1,4,5].beat()).out()
|
beat(.75) :: snd('linnhats').n([1,4,5].beat()).out()
|
||||||
beat(1) :: snd('bd').out()
|
beat(1) :: snd('bd').out()
|
||||||
@ -42,42 +42,42 @@ beat(1) :: snd('bd').out()
|
|||||||
//// beat(1) :: snd('bd').out()
|
//// beat(1) :: snd('bd').out()
|
||||||
|
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"More complex conditions using ?",
|
"More complex conditions using ?",
|
||||||
`
|
`
|
||||||
// The ? symbol can be used to write a if/true/false condition
|
// The ? symbol can be used to write a if/true/false condition
|
||||||
beat(4) ? snd('kick').out() : beat(2) :: snd('snare').out()
|
beat(4) ? snd('kick').out() : beat(2) :: snd('snare').out()
|
||||||
// (true) ? log('very true') : log('very false')
|
// (true) ? log('very true') : log('very false')
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using not and other short symbols",
|
"Using not and other short symbols",
|
||||||
`
|
`
|
||||||
// The ! symbol can be used to reverse a condition
|
// The ! symbol can be used to reverse a condition
|
||||||
beat(4) ? snd('kick').out() : beat(2) :: snd('snare').out()
|
beat(4) ? snd('kick').out() : beat(2) :: snd('snare').out()
|
||||||
!beat(2) :: beat(0.5) :: snd('clap').out()
|
!beat(2) :: beat(0.5) :: snd('clap').out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
# About crashes and bugs
|
# About crashes and bugs
|
||||||
|
|
||||||
Things will crash! It's part of the show! You will learn progressively to avoid mistakes and to write safer code. Do not hesitate to kill the page or to stop the transport if you feel overwhelmed by an algorithm blowing up. There is no safeguard to stop you from doing most things. This is to ensure that you have all the available possible room to write bespoke code and experiment with your ideas through code.
|
Things will crash! It's part of the show! You will learn progressively to avoid mistakes and to write safer code. Do not hesitate to kill the page or to stop the transport if you feel overwhelmed by an algorithm blowing up. There is no safeguard to stop you from doing most things. This is to ensure that you have all the available possible room to write bespoke code and experiment with your ideas through code.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"This example will crash! Who cares?",
|
"This example will crash! Who cares?",
|
||||||
`
|
`
|
||||||
// This is crashing. See? No harm!
|
// This is crashing. See? No harm!
|
||||||
qjldfqsdklqsjdlkqjsdlqkjdlksjd
|
qjldfqsdklqsjdlkqjsdlqkjdlksjd
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
7
src/documentation/basics/index.ts
Normal file
7
src/documentation/basics/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export { introduction } from './welcome';
|
||||||
|
export { atelier } from './atelier';
|
||||||
|
export { software_interface } from './interface';
|
||||||
|
export { shortcuts } from './keyboard';
|
||||||
|
export { code } from './code';
|
||||||
|
export { mouse } from './mouse';
|
||||||
|
export { interaction } from './interaction';
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
export const interaction = (application: Editor): string => {
|
export const interaction = (application: Editor): string => {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
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";
|
||||||
@ -38,24 +38,24 @@ Every Topos session is composed of **local**, **global** and **init** scripts. T
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Calling scripts to form a musical piece",
|
"Calling scripts to form a musical piece",
|
||||||
`
|
`
|
||||||
beat(1) :: script(1) // Calling local script n°1
|
beat(1) :: script(1) // Calling local script n°1
|
||||||
flip(4) :: beat(.5) :: script(2) // Calling script n°2
|
flip(4) :: beat(.5) :: script(2) // Calling script n°2
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Script execution can become musical too!",
|
"Script execution can become musical too!",
|
||||||
`
|
`
|
||||||
// Use algorithms to pick a script.
|
// Use algorithms to pick a script.
|
||||||
beat(1) :: script([1, 3, 5].pick())
|
beat(1) :: script([1, 3, 5].pick())
|
||||||
flip(4) :: beat([.5, .25].beat(16)) :: script(
|
flip(4) :: beat([.5, .25].beat(16)) :: script(
|
||||||
[5, 6, 7, 8].beat())
|
[5, 6, 7, 8].beat())
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Navigating the interface
|
### Navigating the interface
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { key_shortcut } from "../../Documentation";
|
import { key_shortcut } from "../Documentation";
|
||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const shortcuts = (app: Editor): string => {
|
export const shortcuts = (app: Editor): string => {
|
||||||
let makeExample = makeExampleFactory(app);
|
let makeExample = makeExampleFactory(app);
|
||||||
@ -69,12 +69,12 @@ By pressing the ${key_shortcut(
|
|||||||
)} when playing this example:
|
)} when playing this example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Claping twice as fast with fill",
|
"Claping twice as fast with fill",
|
||||||
`
|
`
|
||||||
beat(fill() ? 1/4 : 1/2)::sound('cp').out()
|
beat(fill() ? 1/4 : 1/2)::sound('cp').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const mouse = (app: Editor): string => {
|
export const mouse = (app: Editor): string => {
|
||||||
let makeExample = makeExampleFactory(app);
|
let makeExample = makeExampleFactory(app);
|
||||||
@ -16,8 +16,8 @@ You can get the current position of the mouse on the screen by using the followi
|
|||||||
- <ic>mouseY()</ic>: the vertical 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(
|
${makeExample(
|
||||||
"Vibrato controlled by mouse",
|
"Vibrato controlled by mouse",
|
||||||
`
|
`
|
||||||
beat(.25) :: sound('sine')
|
beat(.25) :: sound('sine')
|
||||||
.note([0,4,5,10,11,15,16]
|
.note([0,4,5,10,11,15,16]
|
||||||
.palindrome()
|
.palindrome()
|
||||||
@ -27,8 +27,8 @@ beat(.25) :: sound('sine')
|
|||||||
.pan(r(0, 1))
|
.pan(r(0, 1))
|
||||||
.room(0.35).size(4).out()
|
.room(0.35).size(4).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
@ -39,15 +39,15 @@ Current mouse position can also be used to generate notes:
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using the mouse to output a note!",
|
"Using the mouse to output a note!",
|
||||||
`
|
`
|
||||||
beat(.25) :: sound('sine')
|
beat(.25) :: sound('sine')
|
||||||
.lpf(7000)
|
.lpf(7000)
|
||||||
.delay(0.5).delayt(1/6).delayfb(0.2)
|
.delay(0.5).delayt(1/6).delayfb(0.2)
|
||||||
.note(noteX())
|
.note(noteX())
|
||||||
.room(0.35).size(4).out()`,
|
.room(0.35).size(4).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Mouse and Arrays
|
## Mouse and Arrays
|
||||||
|
|
||||||
@ -58,14 +58,14 @@ You can use the mouse to explore the valuesq contained in an Array:
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Taking values out of an Array with the mouse",
|
"Taking values out of an Array with the mouse",
|
||||||
`
|
`
|
||||||
log([1,2,3,4].mouseX())
|
log([1,2,3,4].mouseX())
|
||||||
log([4,5,6,7].mouseY())
|
log([4,5,6,7].mouseY())
|
||||||
|
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { makeExampleFactory, key_shortcut } from "../../Documentation";
|
import { makeExampleFactory, key_shortcut } from "../Documentation";
|
||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { examples } from "../../examples/excerpts";
|
import { examples } from "../excerpts";
|
||||||
|
|
||||||
export const introduction = (application: Editor): string => {
|
export const introduction = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const amplitude = (application: Editor): string => {
|
export const amplitude = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -17,11 +17,11 @@ Controlling the volume is probably the most important concept you need to know a
|
|||||||
| <ic>dbgain</ic> | db | Attenuation in dB from <ic>-inf</ic> to <ic>+10</ic> (acts as a sound mixer fader).|
|
| <ic>dbgain</ic> | db | Attenuation in dB from <ic>-inf</ic> to <ic>+10</ic> (acts as a sound mixer fader).|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Velocity manipulated by a counter",
|
"Velocity manipulated by a counter",
|
||||||
`
|
`
|
||||||
beat(.5)::snd('cp').vel($(1)%10 / 10).out()`,
|
beat(.5)::snd('cp').vel($(1)%10 / 10).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Amplitude Enveloppe
|
## Amplitude Enveloppe
|
||||||
|
|
||||||
@ -38,8 +38,8 @@ beat(.5)::snd('cp').vel($(1)%10 / 10).out()`,
|
|||||||
Note that the **sustain** value is not a duration but an amplitude value (how loud). The other values are the time for each stage to take place. Here is a fairly complete example using the <ic>sawtooth</ic> basic waveform.
|
Note that the **sustain** value is not a duration but an amplitude value (how loud). The other values are the time for each stage to take place. Here is a fairly complete example using the <ic>sawtooth</ic> basic waveform.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Simple synthesizer",
|
"Simple synthesizer",
|
||||||
`
|
`
|
||||||
register("smooth", x => x.cutoff(r(100,500))
|
register("smooth", x => x.cutoff(r(100,500))
|
||||||
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
|
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
|
||||||
.gain(r(0.25, 0.4)).adsr(0, r(.2,.4), r(0,0.5), 0)
|
.gain(r(0.25, 0.4)).adsr(0, r(.2,.4), r(0,0.5), 0)
|
||||||
@ -51,15 +51,15 @@ beat(.25)::sound('sawtooth')
|
|||||||
.note([50,57,55,60].add(12).beat(1.5))
|
.note([50,57,55,60].add(12).beat(1.5))
|
||||||
.smooth().out();
|
.smooth().out();
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
Sometimes, using a full ADSR envelope is a bit overkill. There are other simpler controls to manipulate the envelope like the <ic>.ad</ic> method:
|
Sometimes, using a full ADSR envelope is a bit overkill. There are other simpler controls to manipulate the envelope like the <ic>.ad</ic> method:
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Replacing .adsr by .ad",
|
"Replacing .adsr by .ad",
|
||||||
`
|
`
|
||||||
register("smooth", x => x.cutoff(r(100,500))
|
register("smooth", x => x.cutoff(r(100,500))
|
||||||
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
|
.lpadsr(usaw(1/8) * 8, 0.05, .125, 0, 0)
|
||||||
.gain(r(0.25, 0.4)).ad(0, 0.25)
|
.gain(r(0.25, 0.4)).ad(0, 0.25)
|
||||||
@ -71,8 +71,8 @@ beat(.25)::sound('sawtooth')
|
|||||||
.note([50,57,55,60].add(12).beat(1.5))
|
.note([50,57,55,60].add(12).beat(1.5))
|
||||||
.smooth().out();
|
.smooth().out();
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const audio_basics = (application: Editor): string => {
|
export const audio_basics = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -17,13 +17,13 @@ Use the <ic>sound(name: string)</ic> function to play a sound. You can also writ
|
|||||||
Whatever you choose, the syntax stays the same. See the following example:
|
Whatever you choose, the syntax stays the same. See the following example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing sounds is easy",
|
"Playing sounds is easy",
|
||||||
`
|
`
|
||||||
beat(1) && sound('bd').out()
|
beat(1) && sound('bd').out()
|
||||||
beat(0.5) && sound('hh').out()
|
beat(0.5) && sound('hh').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
These commands, in plain english, can be translated to:
|
These commands, in plain english, can be translated to:
|
||||||
|
|
||||||
@ -33,13 +33,13 @@ These commands, in plain english, can be translated to:
|
|||||||
Let's make this example a bit more complex:
|
Let's make this example a bit more complex:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Adding some effects",
|
"Adding some effects",
|
||||||
`
|
`
|
||||||
beat(1) && sound('bd').coarse(0.25).room(0.5).orbit(2).out();
|
beat(1) && sound('bd').coarse(0.25).room(0.5).orbit(2).out();
|
||||||
beat(0.5) && sound('hh').delay(0.25).delaytime(0.125).out();
|
beat(0.5) && sound('hh').delay(0.25).delaytime(0.125).out();
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Now, it translates as follows:
|
Now, it translates as follows:
|
||||||
|
|
||||||
@ -54,13 +54,13 @@ If you remove <ic>beat</ic> instruction, you will end up with a deluge of kick d
|
|||||||
To play a sound, you always need the <ic>.out()</ic> method at the end of your chain. THis method tells **Topos** to send the chain to the audio engine. The <ic>.out</ic> method can take an optional argument to send the sound to a numbered effect bus, from <ic>0</ic> to <ic>n</ic> :
|
To play a sound, you always need the <ic>.out()</ic> method at the end of your chain. THis method tells **Topos** to send the chain to the audio engine. The <ic>.out</ic> method can take an optional argument to send the sound to a numbered effect bus, from <ic>0</ic> to <ic>n</ic> :
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using the .out method",
|
"Using the .out method",
|
||||||
`
|
`
|
||||||
// Playing a clap on the third bus (0-indexed)
|
// Playing a clap on the third bus (0-indexed)
|
||||||
beat(1)::sound('cp').out(2)
|
beat(1)::sound('cp').out(2)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Try to remove <ic>.out</ic>. You will see that no sound is playing at all!
|
Try to remove <ic>.out</ic>. You will see that no sound is playing at all!
|
||||||
|
|
||||||
@ -69,16 +69,16 @@ Try to remove <ic>.out</ic>. You will see that no sound is playing at all!
|
|||||||
- Sounds are **composed** by adding qualifiers/parameters that modify the sound or synthesizer you have picked (_e.g_ <ic>sound('...').blabla(...)..something(...).out()</ic>. Think of it as _audio chains_.
|
- Sounds are **composed** by adding qualifiers/parameters that modify the sound or synthesizer you have picked (_e.g_ <ic>sound('...').blabla(...)..something(...).out()</ic>. Think of it as _audio chains_.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Complex sonic object",
|
"Complex sonic object",
|
||||||
`
|
`
|
||||||
beat(1) :: sound('pad').n(1)
|
beat(1) :: sound('pad').n(1)
|
||||||
.begin(rand(0, 0.4))
|
.begin(rand(0, 0.4))
|
||||||
.freq([50,52].beat())
|
.freq([50,52].beat())
|
||||||
.size(0.9).room(0.9)
|
.size(0.9).room(0.9)
|
||||||
.velocity(0.25)
|
.velocity(0.25)
|
||||||
.pan(usine()).release(2).out()`,
|
.pan(usine()).release(2).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Picking a specific sound
|
## Picking a specific sound
|
||||||
|
|
||||||
@ -102,12 +102,12 @@ If you choose the sound <ic>kick</ic>, you are asking for the first sample in th
|
|||||||
|
|
||||||
The <ic>.n(number)</ic> method can be used to pick a sample from the currently selected sample folder. For instance, the following script will play a random sample from the _kick_ folder:
|
The <ic>.n(number)</ic> method can be used to pick a sample from the currently selected sample folder. For instance, the following script will play a random sample from the _kick_ folder:
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Picking a sample",
|
"Picking a sample",
|
||||||
`
|
`
|
||||||
beat(1) && sound('kick').n([1,2,3,4,5,6,7,8].pick()).out()
|
beat(1) && sound('kick').n([1,2,3,4,5,6,7,8].pick()).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
You can also use the <ic>:</ic> to pick a sample number directly from the <ic>sound</ic> function:
|
You can also use the <ic>:</ic> to pick a sample number directly from the <ic>sound</ic> function:
|
||||||
|
|
||||||
@ -122,12 +122,12 @@ beat(1) && sound('kick:3').out()
|
|||||||
You can use any number to pick a sound. Don't be afraid of using a number too big. If the number exceeds the number of available samples, it will simply wrap around and loop infinitely over the folder. Let's demonstrate this by using the mouse over a very large sample folder:
|
You can use any number to pick a sound. Don't be afraid of using a number too big. If the number exceeds the number of available samples, it will simply wrap around and loop infinitely over the folder. Let's demonstrate this by using the mouse over a very large sample folder:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Picking a sample... with the mouse!",
|
"Picking a sample... with the mouse!",
|
||||||
`
|
`
|
||||||
// Move your mouse to change the sample being used!
|
// Move your mouse to change the sample being used!
|
||||||
beat(.25) && sound('ST09').n(Math.floor(mouseX())).out()`,
|
beat(.25) && sound('ST09').n(Math.floor(mouseX())).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
The <ic>.n</ic> method is also used for synthesizers but it behaves differently. When using a synthesizer, this method can help you determine the number of harmonics in your waveform. See the **Synthesizers** section to learn more about this.
|
The <ic>.n</ic> method is also used for synthesizers but it behaves differently. When using a synthesizer, this method can help you determine the number of harmonics in your waveform. See the **Synthesizers** section to learn more about this.
|
||||||
@ -150,8 +150,8 @@ There is a special method to choose the _orbit_ that your sound is going to use:
|
|||||||
You can play a sound _dry_ and another sound _wet_. Take a look at this example where the reverb is only affecting one of the sounds:
|
You can play a sound _dry_ and another sound _wet_. Take a look at this example where the reverb is only affecting one of the sounds:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Dry and wet",
|
"Dry and wet",
|
||||||
`
|
`
|
||||||
|
|
||||||
// This sound is dry
|
// This sound is dry
|
||||||
beat(1)::sound('hh').out()
|
beat(1)::sound('hh').out()
|
||||||
@ -159,23 +159,23 @@ beat(1)::sound('hh').out()
|
|||||||
// This sound is wet (reverb)
|
// This sound is wet (reverb)
|
||||||
beat(2)::sound('cp').orbit(2).room(0.5).size(8).out()
|
beat(2)::sound('cp').orbit(2).room(0.5).size(8).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## The art of chaining
|
## The art of chaining
|
||||||
|
|
||||||
Learning to create complex chains is very important when using **Topos**. It can take some time to learn all the possible parameters. Don't worry, it's actually rather easy to learn.
|
Learning to create complex chains is very important when using **Topos**. It can take some time to learn all the possible parameters. Don't worry, it's actually rather easy to learn.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Complex chain",
|
"Complex chain",
|
||||||
`
|
`
|
||||||
beat(0.25) && sound('fhh')
|
beat(0.25) && sound('fhh')
|
||||||
.sometimes(s=>s.speed([2, 0.5].pick()))
|
.sometimes(s=>s.speed([2, 0.5].pick()))
|
||||||
.room(0.9).size(0.9).gain(1)
|
.room(0.9).size(0.9).gain(1)
|
||||||
.cutoff(usine(1/2) * 5000)
|
.cutoff(usine(1/2) * 5000)
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Most audio parameters can be used both for samples and synthesizers. This is quite unconventional if you are familiar with a more traditional music software.
|
Most audio parameters can be used both for samples and synthesizers. This is quite unconventional if you are familiar with a more traditional music software.
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const distortion = (application: Editor): string => {
|
export const distortion = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -18,13 +18,13 @@ Three additional effects that are easy enough to understand. These effects are d
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Crunch... crunch... crunch!",
|
"Crunch... crunch... crunch!",
|
||||||
`
|
`
|
||||||
beat(.5)::snd('pad').coarse($(1) % 16).clip(.5).out(); // Comment me
|
beat(.5)::snd('pad').coarse($(1) % 16).clip(.5).out(); // Comment me
|
||||||
beat(.5)::snd('pad').crush([16, 8, 4].beat(2)).clip(.5).out()
|
beat(.5)::snd('pad').crush([16, 8, 4].beat(2)).clip(.5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const effects = (application: Editor): string => {
|
export const effects = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -24,12 +24,12 @@ For that reason, it is often a good idea to set fixed reverb values per orbit. D
|
|||||||
| <ic>roomdim</ic> | | Reverb lowpass frequency at -60db (in hertz) |
|
| <ic>roomdim</ic> | | Reverb lowpass frequency at -60db (in hertz) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Clapping in the cavern",
|
"Clapping in the cavern",
|
||||||
`
|
`
|
||||||
beat(2)::snd('cp').room(0.5).size(4).out()
|
beat(2)::snd('cp').room(0.5).size(4).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
## Delay
|
## Delay
|
||||||
|
|
||||||
@ -42,13 +42,13 @@ A good sounding delay unit that can go into feedback territory. Use it without m
|
|||||||
| <ic>delayfeedback</ic> | delayfb | Delay feedback (between <ic>0</ic> and <ic>1</ic>) |
|
| <ic>delayfeedback</ic> | delayfb | Delay feedback (between <ic>0</ic> and <ic>1</ic>) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Who doesn't like delay?",
|
"Who doesn't like delay?",
|
||||||
`
|
`
|
||||||
beat(2)::snd('cp').delay(0.5).delaytime(0.75).delayfb(0.8).out()
|
beat(2)::snd('cp').delay(0.5).delaytime(0.75).delayfb(0.8).out()
|
||||||
beat(4)::snd('snare').out()
|
beat(4)::snd('snare').out()
|
||||||
beat(1)::snd('kick').out()`,
|
beat(1)::snd('kick').out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Phaser
|
## Phaser
|
||||||
|
|
||||||
@ -60,16 +60,16 @@ beat(1)::snd('kick').out()`,
|
|||||||
| <ic>phaserCenter</ic> | <ic>phascenter</ic> | Phaser center frequency (default to 1000) |
|
| <ic>phaserCenter</ic> | <ic>phascenter</ic> | Phaser center frequency (default to 1000) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Super cool phaser lick",
|
"Super cool phaser lick",
|
||||||
`
|
`
|
||||||
rhythm(.5, 7, 8)::sound('wt_stereo')
|
rhythm(.5, 7, 8)::sound('wt_stereo')
|
||||||
.phaser(0.75).phaserSweep(3000)
|
.phaser(0.75).phaserSweep(3000)
|
||||||
.phaserCenter(1500).phaserDepth(1)
|
.phaserCenter(1500).phaserDepth(1)
|
||||||
.note([0, 1, 2, 3, 4, 5, 6].scale('pentatonic', 50).beat(0.25))
|
.note([0, 1, 2, 3, 4, 5, 6].scale('pentatonic', 50).beat(0.25))
|
||||||
.room(0.5).size(4).out()
|
.room(0.5).size(4).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Distorsion, saturation, destruction
|
## Distorsion, saturation, destruction
|
||||||
|
|
||||||
@ -83,29 +83,29 @@ Three additional effects that are easy enough to understand. These effects are d
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Crunch... crunch... crunch!",
|
"Crunch... crunch... crunch!",
|
||||||
`
|
`
|
||||||
beat(.5)::snd('pad').coarse($(1) % 16).clip(.5).out(); // Comment me
|
beat(.5)::snd('pad').coarse($(1) % 16).clip(.5).out(); // Comment me
|
||||||
beat(.5)::snd('pad').crush([16, 8, 4].beat(2)).clip(.5).out()
|
beat(.5)::snd('pad').crush([16, 8, 4].beat(2)).clip(.5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
## Vibrato
|
## Vibrato
|
||||||
|
|
||||||
You can also add some amount of vibrato to the sound using the <ic>vib</ic> and <ic>vibmod</ic> methods. These can turn any oscillator into something more lively and/or into a sound effect when used with a high amount of modulation.
|
You can also add some amount of vibrato to the sound using the <ic>vib</ic> and <ic>vibmod</ic> methods. These can turn any oscillator into something more lively and/or into a sound effect when used with a high amount of modulation.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Different vibrato settings",
|
"Different vibrato settings",
|
||||||
`
|
`
|
||||||
tempo(140);
|
tempo(140);
|
||||||
beat(1) :: sound('triangle')
|
beat(1) :: sound('triangle')
|
||||||
.freq(400).release(0.2)
|
.freq(400).release(0.2)
|
||||||
.vib([1/2, 1, 2, 4].beat())
|
.vib([1/2, 1, 2, 4].beat())
|
||||||
.vibmod([1,2,4,8].beat(2))
|
.vibmod([1,2,4,8].beat(2))
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Compression
|
## Compression
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const filters = (application: Editor): string => {
|
export const filters = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -13,10 +13,10 @@ Filters can be applied to both synthesizers and samples. They are used to shape
|
|||||||
- **bandpass filter**: filters the low and high frequencies around a frequency band, keeping what's in the middle.
|
- **bandpass filter**: filters the low and high frequencies around a frequency band, keeping what's in the middle.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Filtering the high frequencies of an oscillator",
|
"Filtering the high frequencies of an oscillator",
|
||||||
`beat(.5) :: sound('sawtooth').cutoff(50 + usine(1/8) * 2000).out()`,
|
`beat(.5) :: sound('sawtooth').cutoff(50 + usine(1/8) * 2000).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
These filters all come with their own set of parameters. Note that we are describing the parameters of the three different filter types here. Choose the right parameters depending on the filter type you are using:
|
These filters all come with their own set of parameters. Note that we are describing the parameters of the three different filter types here. Choose the right parameters depending on the filter type you are using:
|
||||||
|
|
||||||
@ -29,10 +29,10 @@ These filters all come with their own set of parameters. Note that we are descri
|
|||||||
| <ic>resonance</ic> | <ic>lpq</ic> | resonance of the lowpass filter (0-1) |
|
| <ic>resonance</ic> | <ic>lpq</ic> | resonance of the lowpass filter (0-1) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Filtering a bass",
|
"Filtering a bass",
|
||||||
`beat(.5) :: sound('jvbass').lpf([250,1000,8000].beat()).out()`,
|
`beat(.5) :: sound('jvbass').lpf([250,1000,8000].beat()).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Highpass filter
|
### Highpass filter
|
||||||
|
|
||||||
@ -42,10 +42,10 @@ ${makeExample(
|
|||||||
| <ic>hresonance</ic> | <ic>hpq</ic> | resonance of the highpass filter (0-1) |
|
| <ic>hresonance</ic> | <ic>hpq</ic> | resonance of the highpass filter (0-1) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Filtering a noise source",
|
"Filtering a noise source",
|
||||||
`beat(.5) :: sound('gtr').hpf([250,1000, 2000, 3000, 4000].beat()).end(0.5).out()`,
|
`beat(.5) :: sound('gtr').hpf([250,1000, 2000, 3000, 4000].beat()).end(0.5).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Bandpass filter
|
### Bandpass filter
|
||||||
|
|
||||||
@ -55,10 +55,10 @@ ${makeExample(
|
|||||||
| <ic>bandq</ic> | <ic>bpq</ic> | resonance of the bandpass filter (0-1) |
|
| <ic>bandq</ic> | <ic>bpq</ic> | resonance of the bandpass filter (0-1) |
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sweeping the filter on the same guitar sample",
|
"Sweeping the filter on the same guitar sample",
|
||||||
`beat(.5) :: sound('gtr').bandf(100 + usine(1/8) * 4000).end(0.5).out()`,
|
`beat(.5) :: sound('gtr').bandf(100 + usine(1/8) * 4000).end(0.5).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Alternatively, <ic>lpf</ic>, <ic>hpf</ic> and <ic>bpf</ic> can take a second argument, the **resonance**.
|
Alternatively, <ic>lpf</ic>, <ic>hpf</ic> and <ic>bpf</ic> can take a second argument, the **resonance**.
|
||||||
|
|
||||||
@ -69,10 +69,10 @@ You can also use the <ic>ftype</ic> method to change the filter type (order). Th
|
|||||||
- <ic>ftype(type: string)</ic>: sets the filter type (order), either <ic>12db</ic> or <ic>24db</ic>.
|
- <ic>ftype(type: string)</ic>: sets the filter type (order), either <ic>12db</ic> or <ic>24db</ic>.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Filtering a bass",
|
"Filtering a bass",
|
||||||
`beat(.5) :: sound('jvbass').ftype(['12db', '24db'].beat(4)).lpf([250,1000,8000].beat()).out()`,
|
`beat(.5) :: sound('jvbass').ftype(['12db', '24db'].beat(4)).lpf([250,1000,8000].beat()).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Filter envelopes
|
## Filter envelopes
|
||||||
|
|
||||||
@ -91,12 +91,12 @@ The examples we have studied so far are static. They filter the sound around a f
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Filtering a sawtooth wave dynamically",
|
"Filtering a sawtooth wave dynamically",
|
||||||
`beat(.5) :: sound('sawtooth').note([48,60].beat())
|
`beat(.5) :: sound('sawtooth').note([48,60].beat())
|
||||||
.cutoff(5000).lpa([0.05, 0.25, 0.5].beat(2))
|
.cutoff(5000).lpa([0.05, 0.25, 0.5].beat(2))
|
||||||
.lpenv(-8).lpq(10).out()`,
|
.lpenv(-8).lpq(10).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Highpass envelope
|
### Highpass envelope
|
||||||
|
|
||||||
@ -111,12 +111,12 @@ ${makeExample(
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Let's use another filter using the same example",
|
"Let's use another filter using the same example",
|
||||||
`beat(.5) :: sound('sawtooth').note([48,60].beat())
|
`beat(.5) :: sound('sawtooth').note([48,60].beat())
|
||||||
.hcutoff(1000).hpa([0.05, 0.25, 0.5].beat(2))
|
.hcutoff(1000).hpa([0.05, 0.25, 0.5].beat(2))
|
||||||
.hpenv(8).hpq(10).out()`,
|
.hpenv(8).hpq(10).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Bandpass envelope
|
### Bandpass envelope
|
||||||
|
|
||||||
@ -131,14 +131,14 @@ ${makeExample(
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"And the bandpass filter, just for fun",
|
"And the bandpass filter, just for fun",
|
||||||
`beat(.5) :: sound('sawtooth').note([48,60].beat())
|
`beat(.5) :: sound('sawtooth').note([48,60].beat())
|
||||||
.bandf([500,1000,2000].beat(2))
|
.bandf([500,1000,2000].beat(2))
|
||||||
.bpa([0.25, 0.125, 0.5].beat(2) * 4)
|
.bpa([0.25, 0.125, 0.5].beat(2) * 4)
|
||||||
.bpenv(-4).release(2).out()
|
.bpenv(-4).release(2).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
6
src/documentation/learning/audio_engine/index.ts
Normal file
6
src/documentation/learning/audio_engine/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export { amplitude } from './amplitude';
|
||||||
|
export { effects } from './effects';
|
||||||
|
export { sampler } from './sampler';
|
||||||
|
export { synths } from './synths';
|
||||||
|
export { filters } from './filters';
|
||||||
|
export { audio_basics } from './audio_basics';
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const sampler = (application: Editor): string => {
|
export const sampler = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -28,8 +28,8 @@ The sampler is a rather complex beast. There is a lot you can do by manipulating
|
|||||||
Let's apply some of these methods naïvely. We will then break everything using simpler examples.
|
Let's apply some of these methods naïvely. We will then break everything using simpler examples.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Complex sampling duties",
|
"Complex sampling duties",
|
||||||
`
|
`
|
||||||
// Using some of the modifiers described above :)
|
// Using some of the modifiers described above :)
|
||||||
beat(.5)::snd('pad').begin(0.2)
|
beat(.5)::snd('pad').begin(0.2)
|
||||||
.speed([1, 0.9, 0.8].beat(4))
|
.speed([1, 0.9, 0.8].beat(4))
|
||||||
@ -38,8 +38,8 @@ beat(.5)::snd('pad').begin(0.2)
|
|||||||
.room(0.8).size(0.5)
|
.room(0.8).size(0.5)
|
||||||
.clip(1).out()
|
.clip(1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
|
|
||||||
## Playback speed / pitching samples
|
## Playback speed / pitching samples
|
||||||
@ -47,37 +47,37 @@ beat(.5)::snd('pad').begin(0.2)
|
|||||||
Let's play with the <ic>speed</ic> parameter to control the pitch of sample playback:
|
Let's play with the <ic>speed</ic> parameter to control the pitch of sample playback:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Controlling the playback speed",
|
"Controlling the playback speed",
|
||||||
`
|
`
|
||||||
beat(0.5)::sound('notes')
|
beat(0.5)::sound('notes')
|
||||||
.speed([1,2,3,4].palindrome().beat(0.5)).out()
|
.speed([1,2,3,4].palindrome().beat(0.5)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
It also works by using negative values. It reverses the playback:
|
It also works by using negative values. It reverses the playback:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing samples backwards",
|
"Playing samples backwards",
|
||||||
`
|
`
|
||||||
beat(0.5)::sound('notes')
|
beat(0.5)::sound('notes')
|
||||||
.speed(-[1,2,3,4].palindrome().beat(0.5)).out()
|
.speed(-[1,2,3,4].palindrome().beat(0.5)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Of course you can play melodies using samples:
|
Of course you can play melodies using samples:
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing melodies using samples",
|
"Playing melodies using samples",
|
||||||
`
|
`
|
||||||
beat(0.5)::sound('notes')
|
beat(0.5)::sound('notes')
|
||||||
.room(0.5).size(4)
|
.room(0.5).size(4)
|
||||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.5)).out()
|
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.5)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Panning
|
## Panning
|
||||||
|
|
||||||
@ -85,14 +85,14 @@ To pan samples, use the <ic>.pan</ic> method with a number between <ic>0</ic> an
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing melodies using samples",
|
"Playing melodies using samples",
|
||||||
`
|
`
|
||||||
beat(0.25)::sound('notes')
|
beat(0.25)::sound('notes')
|
||||||
.room(0.5).size(4).pan(r(0, 1))
|
.room(0.5).size(4).pan(r(0, 1))
|
||||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
## Looping over a sample
|
## Looping over a sample
|
||||||
@ -101,29 +101,29 @@ Using <ic>loop</ic> (<ic>1</ic> for looping), <ic>loopBegin</ic> and <ic>loopEnd
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Granulation using loop",
|
"Granulation using loop",
|
||||||
`
|
`
|
||||||
beat(0.25)::sound('fikea').loop(1)
|
beat(0.25)::sound('fikea').loop(1)
|
||||||
.lpf(ir(2000, 5000))
|
.lpf(ir(2000, 5000))
|
||||||
.loopBegin(0).loopEnd(r(0, 1))
|
.loopBegin(0).loopEnd(r(0, 1))
|
||||||
.room(0.5).size(4).pan(r(0, 1))
|
.room(0.5).size(4).pan(r(0, 1))
|
||||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Stretching a sample
|
## Stretching a sample
|
||||||
|
|
||||||
The <ic>stretch</ic> parameter can help you to stretch long samples like amen breaks:
|
The <ic>stretch</ic> parameter can help you to stretch long samples like amen breaks:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing an amen break",
|
"Playing an amen break",
|
||||||
`
|
`
|
||||||
// Note that stretch has the same value as beat
|
// Note that stretch has the same value as beat
|
||||||
beat(4) :: sound('amen1').n(11).stretch(4).out()
|
beat(4) :: sound('amen1').n(11).stretch(4).out()
|
||||||
beat(1) :: sound('kick').shape(0.35).out()`,
|
beat(1) :: sound('kick').shape(0.35).out()`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
## Cutting samples
|
## Cutting samples
|
||||||
|
|
||||||
@ -132,43 +132,43 @@ Sometimes, you will find it necessary to cut a sample. It can be because the sam
|
|||||||
Know about the <ic>begin</ic> and <ic>end</ic> parameters. They are not related to the sampler itself, but to the length of the event you are playing. Let's cut the granular example:
|
Know about the <ic>begin</ic> and <ic>end</ic> parameters. They are not related to the sampler itself, but to the length of the event you are playing. Let's cut the granular example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Cutting a sample using end",
|
"Cutting a sample using end",
|
||||||
`
|
`
|
||||||
beat(0.25)::sound('notes')
|
beat(0.25)::sound('notes')
|
||||||
.end(usine(1/2)/0.5)
|
.end(usine(1/2)/0.5)
|
||||||
.room(0.5).size(4).pan(r(0, 1))
|
.room(0.5).size(4).pan(r(0, 1))
|
||||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
You can also use <ic>clip</ic> to cut the sample everytime a new sample comes in:
|
You can also use <ic>clip</ic> to cut the sample everytime a new sample comes in:
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Cutting a sample using end",
|
"Cutting a sample using end",
|
||||||
`
|
`
|
||||||
beat(0.125)::sound('notes')
|
beat(0.125)::sound('notes')
|
||||||
.cut(1)
|
.cut(1)
|
||||||
.room(0.5).size(4).pan(r(0, 1))
|
.room(0.5).size(4).pan(r(0, 1))
|
||||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.125)
|
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.125)
|
||||||
+ [-12,12].beat()).out()
|
+ [-12,12].beat()).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Adding vibrato to samples
|
## Adding vibrato to samples
|
||||||
|
|
||||||
You can add vibrato to any sample using <ic>vib</ic> and <ic>vibmod</ic>:
|
You can add vibrato to any sample using <ic>vib</ic> and <ic>vibmod</ic>:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Adding vibrato to a sample",
|
"Adding vibrato to a sample",
|
||||||
`
|
`
|
||||||
|
|
||||||
beat(1)::sound('fhang').vib([1, 2, 4].bar()).vibmod([0.5, 2].beat()).out()
|
beat(1)::sound('fhang').vib([1, 2, 4].bar()).vibmod([0.5, 2].beat()).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const synths = (application: Editor): string => {
|
export const synths = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory, key_shortcut } from "../../Documentation";
|
import { makeExampleFactory, key_shortcut } from "../Documentation";
|
||||||
|
|
||||||
export const midi = (application: Editor): string => {
|
export const midi = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -22,22 +22,22 @@ Your web browser is capable of sending and receiving MIDI information through th
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Listing MIDI outputs",
|
"Listing MIDI outputs",
|
||||||
`
|
`
|
||||||
midi_outputs()
|
midi_outputs()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>midi_output(output_name: string)</ic>: enter your desired output to connect to it.
|
- <ic>midi_output(output_name: string)</ic>: enter your desired output to connect to it.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Changing MIDI output",
|
"Changing MIDI output",
|
||||||
`
|
`
|
||||||
midi_output("MIDI Rocket-Trumpet")
|
midi_output("MIDI Rocket-Trumpet")
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
That's it! You are now ready to play with MIDI.
|
That's it! You are now ready to play with MIDI.
|
||||||
|
|
||||||
@ -48,69 +48,69 @@ The most basic MIDI event is the note. MIDI notes traditionally take three param
|
|||||||
- <ic>midi(note: number|object)</ic>: send a MIDI Note. This function is quite bizarre. It can be written and used in many different ways. You can pass form one up to three arguments in different forms.
|
- <ic>midi(note: number|object)</ic>: send a MIDI Note. This function is quite bizarre. It can be written and used in many different ways. You can pass form one up to three arguments in different forms.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"MIDI note using one parameter: note",
|
"MIDI note using one parameter: note",
|
||||||
`
|
`
|
||||||
// Configure your MIDI first!
|
// Configure your MIDI first!
|
||||||
// => midi_output("MIDI Bus 1")
|
// => midi_output("MIDI Bus 1")
|
||||||
rhythm(.5, 5, 8) :: midi(50).out()
|
rhythm(.5, 5, 8) :: midi(50).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"MIDI note using three parameters: note, velocity, channel",
|
"MIDI note using three parameters: note, velocity, channel",
|
||||||
`
|
`
|
||||||
// MIDI Note 50, Velocity 50 + LFO, Channel 0
|
// MIDI Note 50, Velocity 50 + LFO, Channel 0
|
||||||
rhythm(.5, 5, 8) :: midi(50, 50 + usine(.5) * 20, 0).out()
|
rhythm(.5, 5, 8) :: midi(50, 50 + usine(.5) * 20, 0).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"MIDI note by passing an object",
|
"MIDI note by passing an object",
|
||||||
`
|
`
|
||||||
// MIDI Note 50, Velocity 50 + LFO, Channel 0
|
// MIDI Note 50, Velocity 50 + LFO, Channel 0
|
||||||
rhythm(.5, 5, 8) :: midi({note: 50, velocity: 50 + usine(.5) * 20, channel: 0}).out()
|
rhythm(.5, 5, 8) :: midi({note: 50, velocity: 50 + usine(.5) * 20, channel: 0}).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
We can now have some fun and starting playing a small piano piece:
|
We can now have some fun and starting playing a small piano piece:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing some piano",
|
"Playing some piano",
|
||||||
`
|
`
|
||||||
tempo(80) // Setting a default BPM
|
tempo(80) // Setting a default BPM
|
||||||
beat(.5) && midi(36 + [0,12].beat()).sustain(0.02).out()
|
beat(.5) && midi(36 + [0,12].beat()).sustain(0.02).out()
|
||||||
beat(.25) && midi([64, 76].pick()).sustain(0.05).out()
|
beat(.25) && midi([64, 76].pick()).sustain(0.05).out()
|
||||||
beat(.75) && midi([64, 67, 69].beat()).sustain(0.05).out()
|
beat(.75) && midi([64, 67, 69].beat()).sustain(0.05).out()
|
||||||
beat(.25) && midi([64, 67, 69].beat() + 24).sustain(0.05).out()
|
beat(.25) && midi([64, 67, 69].beat() + 24).sustain(0.05).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Control and Program Changes
|
## Control and Program Changes
|
||||||
|
|
||||||
- <ic>control_change({control: number, value: number, channel: number})</ic>: send a MIDI Control Change. This function takes a single object argument to specify the control message (_e.g._ <ic>control_change({control: 1, value: 127, channel: 1})</ic>).
|
- <ic>control_change({control: number, value: number, channel: number})</ic>: send a MIDI Control Change. This function takes a single object argument to specify the control message (_e.g._ <ic>control_change({control: 1, value: 127, channel: 1})</ic>).
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Imagine that I am tweaking an hardware synthesizer!",
|
"Imagine that I am tweaking an hardware synthesizer!",
|
||||||
`
|
`
|
||||||
control_change({control: [24,25].pick(), value: irand(1,120), channel: 1})
|
control_change({control: [24,25].pick(), value: irand(1,120), channel: 1})
|
||||||
control_change({control: [30,35].pick(), value: irand(1,120) / 2, channel: 1})
|
control_change({control: [30,35].pick(), value: irand(1,120) / 2, channel: 1})
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>program_change(program: number, channel: number)</ic>: send a MIDI Program Change. This function takes two arguments to specify the program and the channel (_e.g._ <ic>program_change(1, 1)</ic>).
|
- <ic>program_change(program: number, channel: number)</ic>: send a MIDI Program Change. This function takes two arguments to specify the program and the channel (_e.g._ <ic>program_change(1, 1)</ic>).
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Crashing old synthesizers: a hobby",
|
"Crashing old synthesizers: a hobby",
|
||||||
`
|
`
|
||||||
program_change([1,2,3,4,5,6,7,8].pick(), 1)
|
program_change([1,2,3,4,5,6,7,8].pick(), 1)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
## System Exclusive Messages
|
## System Exclusive Messages
|
||||||
@ -119,44 +119,44 @@ program_change([1,2,3,4,5,6,7,8].pick(), 1)
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Nobody can say that we don't support Sysex messages!",
|
"Nobody can say that we don't support Sysex messages!",
|
||||||
`
|
`
|
||||||
sysex(0x90, 0x40, 0x7f)
|
sysex(0x90, 0x40, 0x7f)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Clock
|
## Clock
|
||||||
|
|
||||||
- <ic>midi_clock()</ic>: send a MIDI Clock message. This function is used to synchronize Topos with other MIDI devices or DAWs.
|
- <ic>midi_clock()</ic>: send a MIDI Clock message. This function is used to synchronize Topos with other MIDI devices or DAWs.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Tic, tac, tic, tac...",
|
"Tic, tac, tic, tac...",
|
||||||
`
|
`
|
||||||
beat(.25) && midi_clock() // Sending clock to MIDI device from the global buffer
|
beat(.25) && midi_clock() // Sending clock to MIDI device from the global buffer
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Using midi with ziffers
|
## Using midi with ziffers
|
||||||
|
|
||||||
Ziffers offers some shorthands for defining channels within the patterns. See Ziffers for more information.
|
Ziffers offers some shorthands for defining channels within the patterns. See Ziffers for more information.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using midi with ziffers",
|
"Using midi with ziffers",
|
||||||
`
|
`
|
||||||
z1('0 2 e 5 2 q 4 2').midi().port(2).channel(4).out()
|
z1('0 2 e 5 2 q 4 2').midi().port(2).channel(4).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Setting the channel within the pattern",
|
"Setting the channel within the pattern",
|
||||||
`
|
`
|
||||||
z1('(0 2 e 5 2):0 (4 2):1').midi().out()
|
z1('(0 2 e 5 2):0 (4 2):1').midi().out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const osc = (application: Editor): string => {
|
export const osc = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -24,52 +24,52 @@ Send an **OSC** message to the server from another application or device at the
|
|||||||
You can access the last 1000 messages using the <ic>getOsc()</ic> function without any argument. This is raw data, you will need to parse it yourself:
|
You can access the last 1000 messages using the <ic>getOsc()</ic> function without any argument. This is raw data, you will need to parse it yourself:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Reading the last OSC messages",
|
"Reading the last OSC messages",
|
||||||
`
|
`
|
||||||
beat(1)::getOsc()
|
beat(1)::getOsc()
|
||||||
// 0 : {data: Array(2), address: '/lala'}
|
// 0 : {data: Array(2), address: '/lala'}
|
||||||
// 1 : {data: Array(2), address: '/lala'}
|
// 1 : {data: Array(2), address: '/lala'}
|
||||||
// 2 : {data: Array(2), address: '/lala'}`,
|
// 2 : {data: Array(2), address: '/lala'}`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Filtered messages
|
### Filtered messages
|
||||||
|
|
||||||
The <ic>getOsc()</ic> can receive an address filter as an argument. This will return only the messages that match the filter:
|
The <ic>getOsc()</ic> can receive an address filter as an argument. This will return only the messages that match the filter:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Reading the last OSC messages (filtered)",
|
"Reading the last OSC messages (filtered)",
|
||||||
`
|
`
|
||||||
beat(1)::getOsc("/lala")
|
beat(1)::getOsc("/lala")
|
||||||
// 0 : (2) [89, 'bob']
|
// 0 : (2) [89, 'bob']
|
||||||
// 1 : (2) [84, 'bob']
|
// 1 : (2) [84, 'bob']
|
||||||
// 2 : (2) [82, 'bob']
|
// 2 : (2) [82, 'bob']
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Output
|
## Output
|
||||||
|
|
||||||
Once the server is loaded, you are ready to send an **OSC** message:
|
Once the server is loaded, you are ready to send an **OSC** message:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sending a simple OSC message",
|
"Sending a simple OSC message",
|
||||||
`
|
`
|
||||||
beat(1)::sound('cp').speed(2).vel(0.5).osc()
|
beat(1)::sound('cp').speed(2).vel(0.5).osc()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
This is a simple **OSC** message that will inherit all the properties of the sound. You can also send customized OSC messages using the <ic>osc()</ic> function:
|
This is a simple **OSC** message that will inherit all the properties of the sound. You can also send customized OSC messages using the <ic>osc()</ic> function:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sending a customized OSC message",
|
"Sending a customized OSC message",
|
||||||
`
|
`
|
||||||
// osc(address, port, ...message)
|
// osc(address, port, ...message)
|
||||||
osc('/my/osc/address', 5000, 1, 2, 3)
|
osc('/my/osc/address', 5000, 1, 2, 3)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
3
src/documentation/learning/samples/index.ts
Normal file
3
src/documentation/learning/samples/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export { loading_samples } from './loading_samples';
|
||||||
|
export { sample_banks } from './sample_banks';
|
||||||
|
export { sample_list } from './sample_list';
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const loading_samples = (application: Editor): string => {
|
export const loading_samples = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -12,36 +12,36 @@ Topos is exposing the <ic>samples</ic> function that you can use to load your ow
|
|||||||
Samples are loaded on-the-fly from the web. Topos is a web application living in the browser. It is running in a sandboxed environment. Thus, it cannot have access to the files stored on your local system. Loading samples requires building a _map_ of the audio files, where a name is associated to a specific file:
|
Samples are loaded on-the-fly from the web. Topos is a web application living in the browser. It is running in a sandboxed environment. Thus, it cannot have access to the files stored on your local system. Loading samples requires building a _map_ of the audio files, where a name is associated to a specific file:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Loading samples from a map",
|
"Loading samples from a map",
|
||||||
`samples({
|
`samples({
|
||||||
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
bd: ['bd/BT0AADA.wav','bd/BT0AAD0.wav'],
|
||||||
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
sd: ['sd/rytm-01-classic.wav','sd/rytm-00-hard.wav'],
|
||||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||||
}, 'github:tidalcycles/Dirt-Samples/master/');`,
|
}, 'github:tidalcycles/Dirt-Samples/master/');`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
This example is loading two samples from each folder declared in the original repository (in the <ic>strudel.json</ic> file). You can then play with them using the syntax you are already used to:
|
This example is loading two samples from each folder declared in the original repository (in the <ic>strudel.json</ic> file). You can then play with them using the syntax you are already used to:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing with the loaded samples",
|
"Playing with the loaded samples",
|
||||||
`rhythm(.5, 5, 8)::sound('bd').n(ir(1,2)).end(1).out()
|
`rhythm(.5, 5, 8)::sound('bd').n(ir(1,2)).end(1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Internally, Topos is loading samples using a different technique where sample maps are directly taken from the previously mentioned <ic>strudel.json</ic> file that lives in each repository:
|
Internally, Topos is loading samples using a different technique where sample maps are directly taken from the previously mentioned <ic>strudel.json</ic> file that lives in each repository:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"This is how Topos is loading its own samples",
|
"This is how Topos is loading its own samples",
|
||||||
`
|
`
|
||||||
// Visit the concerned repos and search for 'strudel.json'
|
// Visit the concerned repos and search for 'strudel.json'
|
||||||
samples("github:tidalcycles/Dirt-Samples/master");
|
samples("github:tidalcycles/Dirt-Samples/master");
|
||||||
samples("github:Bubobubobubobubo/Dough-Samples/main");
|
samples("github:Bubobubobubobubo/Dough-Samples/main");
|
||||||
samples("github:Bubobubobubobubo/Dough-Amiga/main");
|
samples("github:Bubobubobubobubo/Dough-Amiga/main");
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
To learn more about the audio sample loading mechanism, please refer to [this page](https://strudel.tidalcycles.org/learn/samples) written by Felix Roos who has implemented the sample loading mechanism. The API is absolutely identic in Topos!
|
To learn more about the audio sample loading mechanism, please refer to [this page](https://strudel.tidalcycles.org/learn/samples) written by Felix Roos who has implemented the sample loading mechanism. The API is absolutely identic in Topos!
|
||||||
|
|
||||||
@ -50,16 +50,16 @@ To learn more about the audio sample loading mechanism, please refer to [this pa
|
|||||||
You can load samples coming from [Freesound](https://freesound.org/) using the [Shabda](https://shabda.ndre.gr/) API. To do so, study the following example:
|
You can load samples coming from [Freesound](https://freesound.org/) using the [Shabda](https://shabda.ndre.gr/) API. To do so, study the following example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Loading samples from shabda",
|
"Loading samples from shabda",
|
||||||
`
|
`
|
||||||
// Prepend the sample you want with 'shabda:'
|
// Prepend the sample you want with 'shabda:'
|
||||||
samples("shabda:ocean")
|
samples("shabda:ocean")
|
||||||
|
|
||||||
// Use the sound without 'shabda:'
|
// Use the sound without 'shabda:'
|
||||||
beat(1)::sound('ocean').clip(1).out()
|
beat(1)::sound('ocean').clip(1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
You can also use the <ic>.n</ic> attribute like usual to load a different sample.
|
You can also use the <ic>.n</ic> attribute like usual to load a different sample.
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const sample_banks = (application: Editor): string => {
|
export const sample_banks = (application: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const samples_to_markdown = (
|
export const samples_to_markdown = (
|
||||||
application: Editor,
|
application: Editor,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const cyclical_time = (app: Editor): string => {
|
export const cyclical_time = (app: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -16,17 +16,17 @@ Time as a cycle. A cycle can be quite long (a few bars) or very short (a few pul
|
|||||||
- <ic>offset</ic>: offset (in beats) to apply. An offset of <ic>0.5</ic> will return true against the beat.
|
- <ic>offset</ic>: offset (in beats) to apply. An offset of <ic>0.5</ic> will return true against the beat.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using different mod values",
|
"Using different mod values",
|
||||||
`
|
`
|
||||||
// This code is alternating between different mod values
|
// This code is alternating between different mod values
|
||||||
beat([1,1/2,1/4,1/8].beat(2)) :: sound('hat').n(0).out()
|
beat([1,1/2,1/4,1/8].beat(2)) :: sound('hat').n(0).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Some sort of ringtone",
|
"Some sort of ringtone",
|
||||||
`
|
`
|
||||||
// Blip generator :)
|
// Blip generator :)
|
||||||
let blip = (freq) => {
|
let blip = (freq) => {
|
||||||
return sound('wt_piano')
|
return sound('wt_piano')
|
||||||
@ -41,16 +41,16 @@ beat(1/3) :: blip(400).pan(r(0,1)).out();
|
|||||||
flip(3) :: beat(1/6) :: blip(800).pan(r(0,1)).out();
|
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();
|
beat([1,0.75].beat(2)) :: blip([50, 100].beat(2)).pan(r(0,1)).out();
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Beat can match multiple values",
|
"Beat can match multiple values",
|
||||||
`
|
`
|
||||||
beat([.5, 1.25])::sound('hat').out()
|
beat([.5, 1.25])::sound('hat').out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>pulse(n: number | number[] = 1, offset: number = 1)</ic>: return true every _n_ pulses. A pulse is the tiniest possible rhythmic value.
|
- <ic>pulse(n: number | number[] = 1, offset: number = 1)</ic>: return true every _n_ pulses. A pulse is the tiniest possible rhythmic value.
|
||||||
- <ic>number</ic>: if <ic>number = 1</ic>, the function will return <ic>true</ic> every pulse. Lists can be used too.
|
- <ic>number</ic>: if <ic>number = 1</ic>, the function will return <ic>true</ic> every pulse. Lists can be used too.
|
||||||
@ -58,21 +58,21 @@ beat([.5, 1.25])::sound('hat').out()
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Intriguing rhythms",
|
"Intriguing rhythms",
|
||||||
`
|
`
|
||||||
pulse([24, 16])::sound('hat').ad(0, .02).out()
|
pulse([24, 16])::sound('hat').ad(0, .02).out()
|
||||||
pulse([48, [36,24].dur(4, 1)])::sound('fhardkick').ad(0, .1).out()
|
pulse([48, [36,24].dur(4, 1)])::sound('fhardkick').ad(0, .1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"pulse is the OG rhythmic function in Topos",
|
"pulse is the OG rhythmic function in Topos",
|
||||||
`
|
`
|
||||||
pulse([48, 24, 16].beat(4)) :: sound('linnhats').out()
|
pulse([48, 24, 16].beat(4)) :: sound('linnhats').out()
|
||||||
beat(1)::snd(['bd', '808oh'].beat(1)).out()
|
beat(1)::snd(['bd', '808oh'].beat(1)).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
- <ic>bar(n: number | number[] = 1, offset: number = 1)</ic>: return true every _n_ bars.
|
- <ic>bar(n: number | number[] = 1, offset: number = 1)</ic>: return true every _n_ bars.
|
||||||
@ -80,37 +80,37 @@ beat(1)::snd(['bd', '808oh'].beat(1)).out()
|
|||||||
- <ic>offset</ic>: offset (in bars) to apply.
|
- <ic>offset</ic>: offset (in bars) to apply.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Four beats per bar: proof",
|
"Four beats per bar: proof",
|
||||||
`
|
`
|
||||||
bar(1)::sound('kick').out()
|
bar(1)::sound('kick').out()
|
||||||
beat(1)::sound('hat').speed(2).out()
|
beat(1)::sound('hat').speed(2).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Offsetting beat and bar",
|
"Offsetting beat and bar",
|
||||||
`
|
`
|
||||||
bar(1)::sound('kick').out()
|
bar(1)::sound('kick').out()
|
||||||
beat(1)::sound('hat').speed(2).out()
|
beat(1)::sound('hat').speed(2).out()
|
||||||
beat(1, 0.5)::sound('hat').speed(4).out()
|
beat(1, 0.5)::sound('hat').speed(4).out()
|
||||||
bar(1, 0.5)::sound('sn').out()
|
bar(1, 0.5)::sound('sn').out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <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.
|
- <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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Some simple yet detailed rhythms",
|
"Some simple yet detailed rhythms",
|
||||||
`
|
`
|
||||||
onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
|
onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
|
||||||
onbeat(2,4)::snd('snare').n([8,4].beat(4)).out() // Snare on acccentuated beats
|
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
|
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## XOX Style sequencers
|
## XOX Style sequencers
|
||||||
|
|
||||||
@ -119,32 +119,32 @@ onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
|||||||
- <ic>duration: number</ic>: an optional duration (in beats) like <ic>1</ic> or </ic>4</ic>. It can be patterned.
|
- <ic>duration: number</ic>: an optional duration (in beats) like <ic>1</ic> or </ic>4</ic>. It can be patterned.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sequence built using a classic XOX sequencer style",
|
"Sequence built using a classic XOX sequencer style",
|
||||||
`
|
`
|
||||||
seq('xoxo')::sound('fhardkick').out()
|
seq('xoxo')::sound('fhardkick').out()
|
||||||
seq('ooxo')::sound('fsoftsnare').out()
|
seq('ooxo')::sound('fsoftsnare').out()
|
||||||
seq('xoxo', 0.25)::sound('fhh').out()
|
seq('xoxo', 0.25)::sound('fhh').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Another sequence using more complex parameters",
|
"Another sequence using more complex parameters",
|
||||||
`
|
`
|
||||||
seq('xoxooxxoo', [0.5, 0.25].dur(2, 1))::sound('fhardkick').out()
|
seq('xoxooxxoo', [0.5, 0.25].dur(2, 1))::sound('fhardkick').out()
|
||||||
seq('ooxo', [1, 2].bar())::sound('fsoftsnare').speed(0.5).out()
|
seq('ooxo', [1, 2].bar())::sound('fsoftsnare').speed(0.5).out()
|
||||||
seq(['xoxoxoxx', 'xxoo'].bar())::sound('fhh').out()
|
seq(['xoxoxoxx', 'xxoo'].bar())::sound('fhh').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>fullseq(expr: string, duration: number = 0.5): boolean</ic> : a variant. Will return <ic>true</ic> or <ic>false</ic> for a whole period, depending on the symbol. Useful for long structure patterns.
|
- <ic>fullseq(expr: string, duration: number = 0.5): boolean</ic> : a variant. Will return <ic>true</ic> or <ic>false</ic> for a whole period, depending on the symbol. Useful for long structure patterns.
|
||||||
- <ic>expr: string</ic>: any string composed of <ic>x</ic> or <ic>o</ic> like so: <ic>"xooxoxxoxoo"</ic>.
|
- <ic>expr: string</ic>: any string composed of <ic>x</ic> or <ic>o</ic> like so: <ic>"xooxoxxoxoo"</ic>.
|
||||||
- <ic>duration: number</ic>: an optional duration (in beats) like <ic>1</ic> or </ic>4</ic>. It can be patterned.
|
- <ic>duration: number</ic>: an optional duration (in beats) like <ic>1</ic> or </ic>4</ic>. It can be patterned.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Long structured patterns",
|
"Long structured patterns",
|
||||||
`
|
`
|
||||||
function simplePat() {
|
function simplePat() {
|
||||||
log('Simple pattern playing!')
|
log('Simple pattern playing!')
|
||||||
seq('xoxooxxoo', [0.5, 0.25].dur(2, 1))::sound('fhardkick').out()
|
seq('xoxooxxoo', [0.5, 0.25].dur(2, 1))::sound('fhardkick').out()
|
||||||
@ -159,8 +159,8 @@ function complexPat() {
|
|||||||
}
|
}
|
||||||
fullseq('xooxooxx', 4) ? simplePat() : complexPat()
|
fullseq('xooxooxx', 4) ? simplePat() : complexPat()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -171,8 +171,8 @@ We included a bunch of popular rhythm generators in Topos such as the euclidian
|
|||||||
|
|
||||||
- <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.
|
- <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(
|
${makeExample(
|
||||||
"rhythm is a beginner friendly rhythmic function!",
|
"rhythm is a beginner friendly rhythmic function!",
|
||||||
`
|
`
|
||||||
rhythm(.5, 4, 8)::sound('sine')
|
rhythm(.5, 4, 8)::sound('sine')
|
||||||
.fmi(2)
|
.fmi(2)
|
||||||
.room(0.5).size(8)
|
.room(0.5).size(8)
|
||||||
@ -181,38 +181,38 @@ rhythm(.5, 7, 8)::sound('sine')
|
|||||||
.freq(125).ad(0, .2).out()
|
.freq(125).ad(0, .2).out()
|
||||||
rhythm(.5, 3, 8)::sound('sine').freq(500).ad(0, .5).out()
|
rhythm(.5, 3, 8)::sound('sine').freq(500).ad(0, .5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
- <ic>oneuclid(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.
|
- <ic>oneuclid(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(
|
${makeExample(
|
||||||
"Using oneuclid to create a rhythm without iterators",
|
"Using oneuclid to create a rhythm without iterators",
|
||||||
`
|
`
|
||||||
// Change speed using bpm
|
// Change speed using bpm
|
||||||
bpm(250)
|
bpm(250)
|
||||||
oneuclid(5, 9) :: snd('kick').out()
|
oneuclid(5, 9) :: snd('kick').out()
|
||||||
oneuclid(7,16) :: snd('east').end(0.5).n(irand(3,5)).out()
|
oneuclid(7,16) :: snd('east').end(0.5).n(irand(3,5)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
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>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.
|
- <ic>binrhythm(divisor: number, n: number): boolean: boolean</ic>: iterator-less version of the binary rhythm generator.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Change the integers for a surprise rhythm!",
|
"Change the integers for a surprise rhythm!",
|
||||||
`
|
`
|
||||||
bpm(135);
|
bpm(135);
|
||||||
beat(.5) && bin($(1), 12) && snd('kick').n([4,9].beat(1.5)).out()
|
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()
|
beat(.5) && bin($(2), 34) && snd('snare').n([3,5].beat(1)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"binrhythm for fast cool binary rhythms!",
|
"binrhythm for fast cool binary rhythms!",
|
||||||
`
|
`
|
||||||
let a = 0;
|
let a = 0;
|
||||||
a = beat(4) ? irand(1,20) : a;
|
a = beat(4) ? irand(1,20) : a;
|
||||||
binrhythm(.5, 6) && snd(['kick', 'snare'].beat(0.5)).n(11).out()
|
binrhythm(.5, 6) && snd(['kick', 'snare'].beat(0.5)).n(11).out()
|
||||||
@ -221,34 +221,34 @@ binrhythm([.5, .25].beat(1), 30) && snd('wt_granular').n(a)
|
|||||||
.adsr(0, r(.1, .4), 0, 0).freq([50, 60, 72].beat(4))
|
.adsr(0, r(.1, .4), 0, 0).freq([50, 60, 72].beat(4))
|
||||||
.room(1).size(1).out()
|
.room(1).size(1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Submarine jungle music",
|
"Submarine jungle music",
|
||||||
`
|
`
|
||||||
bpm(145);
|
bpm(145);
|
||||||
beat(.5) && bin($(1), 911) && snd('ST69').n([2,3,4].beat())
|
beat(.5) && bin($(1), 911) && snd('ST69').n([2,3,4].beat())
|
||||||
.delay(0.125).delayt(0.25).end(0.25).speed(1/3)
|
.delay(0.125).delayt(0.25).end(0.25).speed(1/3)
|
||||||
.room(1).size(1).out()
|
.room(1).size(1).out()
|
||||||
beat(.5) && sound('amencutup').n(irand(2,7)).shape(0.3).out()
|
beat(.5) && sound('amencutup').n(irand(2,7)).shape(0.3).out()
|
||||||
`,
|
`,
|
||||||
false,
|
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.
|
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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Probablistic drums in one line!",
|
"Probablistic drums in one line!",
|
||||||
`
|
`
|
||||||
prob(60)::beat(.5) && euclid($(1), 5, 8) && snd('kick').out()
|
prob(60)::beat(.5) && euclid($(1), 5, 8) && snd('kick').out()
|
||||||
prob(60)::beat(.5) && euclid($(2), 3, 8) && snd('mash')
|
prob(60)::beat(.5) && euclid($(2), 3, 8) && snd('mash')
|
||||||
.n([1,2,3].beat(1))
|
.n([1,2,3].beat(1))
|
||||||
.pan(usine(1/4)).out()
|
.pan(usine(1/4)).out()
|
||||||
prob(80)::beat(.5) && sound(['hh', 'hat'].pick()).out()
|
prob(80)::beat(.5) && sound(['hh', 'hat'].pick()).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
import pulses from "./pulses.svg";
|
import pulses from "./pulses.svg";
|
||||||
|
|
||||||
export const linear_time = (app: Editor): string => {
|
export const linear_time = (app: Editor): string => {
|
||||||
@ -22,12 +22,12 @@ export const linear_time = (app: Editor): string => {
|
|||||||
There is a tiny widget at the bottom right of the screen showing you the current BPM and the status of the transport. You can turn it on or off in the settings menu.
|
There is a tiny widget at the bottom right of the screen showing you the current BPM and the status of the transport. You can turn it on or off in the settings menu.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Printing the transport",
|
"Printing the transport",
|
||||||
`
|
`
|
||||||
log(\`\$\{cbar()}\, \$\{cbeat()\}, \$\{cpulse()\}\`)
|
log(\`\$\{cbar()}\, \$\{cbeat()\}, \$\{cpulse()\}\`)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### BPM and PPQN
|
### BPM and PPQN
|
||||||
|
|
||||||
@ -64,8 +64,8 @@ These values are **extremely useful** to craft more complex syntax or to write m
|
|||||||
You can use time primitives as conditionals. The following example will play a pattern A for 2 bars and a pattern B for 2 bars:
|
You can use time primitives as conditionals. The following example will play a pattern A for 2 bars and a pattern B for 2 bars:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Manual mode: using time primitives!",
|
"Manual mode: using time primitives!",
|
||||||
`
|
`
|
||||||
// Manual time condition
|
// Manual time condition
|
||||||
if((cbar() % 4) > 1) {
|
if((cbar() % 4) > 1) {
|
||||||
beat(2) && sound('kick').out()
|
beat(2) && sound('kick').out()
|
||||||
@ -83,8 +83,8 @@ if((cbar() % 4) > 1) {
|
|||||||
// This is always playing no matter what happens
|
// This is always playing no matter what happens
|
||||||
beat([.5, .5, 1, .25].beat(0.5)) :: sound('shaker').out()
|
beat([.5, .5, 1, .25].beat(0.5)) :: sound('shaker').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Time Warping
|
## Time Warping
|
||||||
|
|
||||||
@ -94,8 +94,8 @@ Time generally flows from the past to the future. However, you can manipulate it
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Time is now super elastic!",
|
"Time is now super elastic!",
|
||||||
`
|
`
|
||||||
// Obscure Shenanigans - Bubobubobubo
|
// Obscure Shenanigans - Bubobubobubo
|
||||||
beat([1/4,1/8,1/16].beat(8)):: sound('sine')
|
beat([1/4,1/8,1/16].beat(8)):: sound('sine')
|
||||||
.freq([100,50].beat(16) + 50 * ($(1)%10))
|
.freq([100,50].beat(16) + 50 * ($(1)%10))
|
||||||
@ -108,14 +108,14 @@ flip(3) :: beat([.25,.5].beat(.5)) :: sound('dr')
|
|||||||
// Jumping back and forth in time
|
// Jumping back and forth in time
|
||||||
beat(.25) :: warp([12, 48, 24, 1, 120, 30].pick())
|
beat(.25) :: warp([12, 48, 24, 1, 120, 30].pick())
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>beat_warp(beat: number)</ic>: this function jumps to the _n_ beat of the clock. The first beat is <ic>1</ic>.
|
- <ic>beat_warp(beat: number)</ic>: this function jumps to the _n_ beat of the clock. The first beat is <ic>1</ic>.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Jumping back and forth with beats",
|
"Jumping back and forth with beats",
|
||||||
`
|
`
|
||||||
// Resonance bliss - Bubobubobubo
|
// Resonance bliss - Bubobubobubo
|
||||||
beat(.25)::snd('arpy')
|
beat(.25)::snd('arpy')
|
||||||
.note(30 + [0,3,7,10].beat())
|
.note(30 + [0,3,7,10].beat())
|
||||||
@ -130,40 +130,40 @@ beat(.5) :: snd('arpy').note(
|
|||||||
// Comment me to stop warping!
|
// Comment me to stop warping!
|
||||||
beat(1) :: beat_warp([2,4,5,10,11].pick())
|
beat(1) :: beat_warp([2,4,5,10,11].pick())
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Transport-based rhythm generators
|
## Transport-based rhythm generators
|
||||||
|
|
||||||
- <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.
|
- <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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Some simple yet detailed rhythms",
|
"Some simple yet detailed rhythms",
|
||||||
`
|
`
|
||||||
onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
|
onbeat(1,2,3,4)::snd('kick').out() // Bassdrum on each beat
|
||||||
onbeat(2,4)::snd('snare').n([8,4].beat(4)).out() // Snare on acccentuated beats
|
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
|
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Let's do something more complex",
|
"Let's do something more complex",
|
||||||
`
|
`
|
||||||
onbeat(0.5, 2, 3, 3.75)::snd('kick').n(2).out()
|
onbeat(0.5, 2, 3, 3.75)::snd('kick').n(2).out()
|
||||||
onbeat(2, [1.5, 3, 4].pick(), 4)::snd('snare').n(8).out()
|
onbeat(2, [1.5, 3, 4].pick(), 4)::snd('snare').n(8).out()
|
||||||
beat([.25, 1/8].beat(1.5))::snd('hat').n(2)
|
beat([.25, 1/8].beat(1.5))::snd('hat').n(2)
|
||||||
.gain(rand(0.4, 0.7)).end(0.05)
|
.gain(rand(0.4, 0.7)).end(0.05)
|
||||||
.pan(usine()).out()
|
.pan(usine()).out()
|
||||||
`,
|
`,
|
||||||
false,
|
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.
|
- <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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using oncount to create more variation in the rhythm",
|
"Using oncount to create more variation in the rhythm",
|
||||||
`
|
`
|
||||||
z1('1/16 (0 2 3 4)+(0 2 4 6)').scale('pentatonic').sound('sawtooth')
|
z1('1/16 (0 2 3 4)+(0 2 4 6)').scale('pentatonic').sound('sawtooth')
|
||||||
.cutoff([400,500,1000,2000].beat(1))
|
.cutoff([400,500,1000,2000].beat(1))
|
||||||
.lpadsr(2, 0, .2, 0, 0)
|
.lpadsr(2, 0, .2, 0, 0)
|
||||||
@ -171,20 +171,20 @@ z1('1/16 (0 2 3 4)+(0 2 4 6)').scale('pentatonic').sound('sawtooth')
|
|||||||
onbeat(1,1.5,2,3,4) :: sound('bd').gain(2.0).out()
|
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()
|
oncount([1,3,5.5,7,7.5,8],8) :: sound('hh').gain(irand(1.0,4.0)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using oncount to create rhythms with a custom meter",
|
"Using oncount to create rhythms with a custom meter",
|
||||||
`
|
`
|
||||||
bpm(200)
|
bpm(200)
|
||||||
oncount([1, 5, 9, 13],16) :: sound('808bd').n(4).shape(0.5).gain(1.0).out()
|
oncount([1, 5, 9, 13],16) :: sound('808bd').n(4).shape(0.5).gain(1.0).out()
|
||||||
oncount([5, 6, 13],16) :: sound('shaker').room(0.25).gain(0.9).out()
|
oncount([5, 6, 13],16) :: sound('shaker').room(0.25).gain(0.9).out()
|
||||||
oncount([2, 3, 3.5, 6, 7, 10, 15],16) :: sound('hh').n(8).gain(0.8).out()
|
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()
|
oncount([1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16],16) :: sound('hh').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const long_forms = (app: Editor): string => {
|
export const long_forms = (app: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -14,23 +14,23 @@ Now you know how to play some basic rhythms but in any case, you are stuck in a
|
|||||||
- **Use the nine local scripts as containers** for sections of your composition. When you start playing with **Topos**, it's easy to forget that there are multiple scripts you can play with. Each script can store a different section or part from your composition. Here is a simple example:
|
- **Use the nine local scripts as containers** for sections of your composition. When you start playing with **Topos**, it's easy to forget that there are multiple scripts you can play with. Each script can store a different section or part from your composition. Here is a simple example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Eight bars per section",
|
"Eight bars per section",
|
||||||
`
|
`
|
||||||
// Playing each script for 8 bars in succession
|
// Playing each script for 8 bars in succession
|
||||||
script([1,2,3,4].bar(8))
|
script([1,2,3,4].bar(8))
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
You can also give a specific duration to each section using <ic>.dur</ic>:
|
You can also give a specific duration to each section using <ic>.dur</ic>:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"N beats per section",
|
"N beats per section",
|
||||||
`
|
`
|
||||||
script([1,2,3,4].dur(8, 2, 16, 4))
|
script([1,2,3,4].dur(8, 2, 16, 4))
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- **Use universes as well**. Transitions between universes are _seamless_, instantaneous. Just switch to different content if you ever hit the limitations of the current _universe_.
|
- **Use universes as well**. Transitions between universes are _seamless_, instantaneous. Just switch to different content if you ever hit the limitations of the current _universe_.
|
||||||
|
|
||||||
@ -40,42 +40,42 @@ script([1,2,3,4].dur(8, 2, 16, 4))
|
|||||||
- <ic>ratio: number = 50</ic>: this argument is ratio expressed in %. It determines how much of the period should be true or false. A ratio of <ic>75</ic> means that 75% of the period will be true. A ratio of <ic>25</ic> means that 25% of the period will be true.
|
- <ic>ratio: number = 50</ic>: this argument is ratio expressed in %. It determines how much of the period should be true or false. A ratio of <ic>75</ic> means that 75% of the period will be true. A ratio of <ic>25</ic> means that 25% of the period will be true.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Two beats of silence, two beats of playing",
|
"Two beats of silence, two beats of playing",
|
||||||
`
|
`
|
||||||
flip(4) :: beat(1) :: snd('kick').out()
|
flip(4) :: beat(1) :: snd('kick').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Clapping on the edge",
|
"Clapping on the edge",
|
||||||
`
|
`
|
||||||
flip(2.5, 10) :: beat(.25) :: snd('cp').out()
|
flip(2.5, 10) :: beat(.25) :: snd('cp').out()
|
||||||
flip(2.5, 75) :: beat(.25) :: snd('click')
|
flip(2.5, 75) :: beat(.25) :: snd('click')
|
||||||
.speed(2).end(0.2).out()
|
.speed(2).end(0.2).out()
|
||||||
flip(2.5) :: beat(.5) :: snd('bd').out()
|
flip(2.5) :: beat(.5) :: snd('bd').out()
|
||||||
beat(.25) :: sound('hat').end(0.1).cutoff(1200).pan(usine(1/4)).out()
|
beat(.25) :: sound('hat').end(0.1).cutoff(1200).pan(usine(1/4)).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Good old true and false",
|
"Good old true and false",
|
||||||
`
|
`
|
||||||
if (flip(4, 75)) {
|
if (flip(4, 75)) {
|
||||||
beat(1) :: snd('kick').out()
|
beat(1) :: snd('kick').out()
|
||||||
} else {
|
} else {
|
||||||
beat(.5) :: snd('snare').out()
|
beat(.5) :: snd('snare').out()
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
true,
|
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.
|
<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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Clunky algorithmic rap music",
|
"Clunky algorithmic rap music",
|
||||||
`
|
`
|
||||||
// Rap God VS Lil Wild -- Adel Faure
|
// Rap God VS Lil Wild -- Adel Faure
|
||||||
if (flip(8)) {
|
if (flip(8)) {
|
||||||
// Playing this part for two bars
|
// Playing this part for two bars
|
||||||
@ -93,24 +93,24 @@ if (flip(8)) {
|
|||||||
beat(.5)::snd('diphone').end(0.5).n([1,2,3,4].pick()).out()
|
beat(.5)::snd('diphone').end(0.5).n([1,2,3,4].pick()).out()
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
You can use it everywhere to spice things up, including as a method parameter picker:
|
You can use it everywhere to spice things up, including as a method parameter picker:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"flip is great for parameter variation",
|
"flip is great for parameter variation",
|
||||||
`
|
`
|
||||||
beat(.5)::snd(flip(2) ? 'kick' : 'hat').out()
|
beat(.5)::snd(flip(2) ? 'kick' : 'hat').out()
|
||||||
`,
|
`,
|
||||||
true,
|
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.
|
- <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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Thinking music over bars",
|
"Thinking music over bars",
|
||||||
`
|
`
|
||||||
let roomy = (n) => n.room(1).size(1).cutoff(500 + usaw(1/8) * 5000);
|
let roomy = (n) => n.room(1).size(1).cutoff(500 + usaw(1/8) * 5000);
|
||||||
function a() {
|
function a() {
|
||||||
beat(1) && roomy(sound('kick')).out()
|
beat(1) && roomy(sound('kick')).out()
|
||||||
@ -122,24 +122,24 @@ function b() {
|
|||||||
flipbar(2) && a()
|
flipbar(2) && a()
|
||||||
flipbar(3) && b()
|
flipbar(3) && b()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Alternating over four bars",
|
"Alternating over four bars",
|
||||||
`
|
`
|
||||||
flipbar(2)
|
flipbar(2)
|
||||||
? beat(.5) && snd(['kick', 'hh'].beat(1)).out()
|
? beat(.5) && snd(['kick', 'hh'].beat(1)).out()
|
||||||
: beat(.5) && snd(['east', 'east:2'].beat(1)).out()
|
: beat(.5) && snd(['east', 'east:2'].beat(1)).out()
|
||||||
`,
|
`,
|
||||||
false,
|
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.
|
- <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.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using onbar for filler drums",
|
"Using onbar for filler drums",
|
||||||
`
|
`
|
||||||
tempo(150);
|
tempo(150);
|
||||||
// Only play on the third and fourth bar of the cycle.
|
// Only play on the third and fourth bar of the cycle.
|
||||||
onbar([3,4], 4)::beat(.25)::snd('hh').out();
|
onbar([3,4], 4)::beat(.25)::snd('hh').out();
|
||||||
@ -155,8 +155,8 @@ if (onbar([1,2], 4)) {
|
|||||||
rhythm(.5, 1, 7) :: snd('jvbass').n(2).out();
|
rhythm(.5, 1, 7) :: snd('jvbass').n(2).out();
|
||||||
rhythm(.5, 2, 7) :: snd('snare').n(3).out();
|
rhythm(.5, 2, 7) :: snd('snare').n(3).out();
|
||||||
}`,
|
}`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import times from "./times.svg";
|
import times from "./times.svg";
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { key_shortcut, makeExampleFactory } from "../../Documentation";
|
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const bonus = (application: Editor): string => {
|
export const bonus = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -14,16 +14,16 @@ Some features have been included as a bonus. These features are often about patt
|
|||||||
The editor theme can be changed using the <ic>theme</ic> and <ic>randomTheme</ic> functions. The following example will use a random color scheme for every beat:
|
The editor theme can be changed using the <ic>theme</ic> and <ic>randomTheme</ic> functions. The following example will use a random color scheme for every beat:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Random theme on each beat",
|
"Random theme on each beat",
|
||||||
`
|
`
|
||||||
beat(1)::randomTheme()
|
beat(1)::randomTheme()
|
||||||
`, true)}
|
`, true)}
|
||||||
|
|
||||||
You can also pick a theme using the <ic>theme</ic> function with a string as only argument:
|
You can also pick a theme using the <ic>theme</ic> function with a string as only argument:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Picking a theme",
|
"Picking a theme",
|
||||||
`
|
`
|
||||||
beat(1)::theme("Batman")
|
beat(1)::theme("Batman")
|
||||||
`, true)}
|
`, true)}
|
||||||
|
|
||||||
@ -36,27 +36,27 @@ beat(1)::theme("Batman")
|
|||||||
[Hydra](https://hydra.ojack.xyz/?sketch_id=mahalia_1) is a popular live-codable video synthesizer developed by [Olivia Jack](https://ojack.xyz/) and other contributors. It follows an analog synthesizer patching metaphor to encourage live coding complex shaders. Being very easy to use, extremely powerful and also very rewarding to use, Hydra has become a popular choice for adding visuals into a live code performance.
|
[Hydra](https://hydra.ojack.xyz/?sketch_id=mahalia_1) is a popular live-codable video synthesizer developed by [Olivia Jack](https://ojack.xyz/) and other contributors. It follows an analog synthesizer patching metaphor to encourage live coding complex shaders. Being very easy to use, extremely powerful and also very rewarding to use, Hydra has become a popular choice for adding visuals into a live code performance.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Hydra integration",
|
"Hydra integration",
|
||||||
`beat(4) :: hydra.osc(3, 0.5, 2).out()`,
|
`beat(4) :: hydra.osc(3, 0.5, 2).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Close the documentation to see the effect: ${key_shortcut(
|
Close the documentation to see the effect: ${key_shortcut(
|
||||||
"Ctrl+D",
|
"Ctrl+D",
|
||||||
)}! **Boom, all shiny!**
|
)}! **Boom, all shiny!**
|
||||||
|
|
||||||
Be careful not to call <ic>hydra</ic> too often as it can impact performances. You can use any rhythmical function like <ic>beat()</ic> function to limit the number of function calls. You can write any Topos code like <ic>[1,2,3].beat()</ic> to bring some life and movement in your Hydra sketches.
|
Be careful not to call <ic>hydra</ic> too often as it can impact performances. You can use any rhythmical function like <ic>beat()</ic> function to limit the number of function calls. You can write any Topos code like <ic>[1,2,3].beat()</ic> to bring some life and movement in your Hydra sketches.
|
||||||
|
|
||||||
Stopping **Hydra** is simple:
|
Stopping **Hydra** is simple:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Stopping Hydra",
|
"Stopping Hydra",
|
||||||
`
|
`
|
||||||
beat(4) :: stop_hydra() // this one
|
beat(4) :: stop_hydra() // this one
|
||||||
beat(4) :: hydra.hush() // or this one
|
beat(4) :: hydra.hush() // or this one
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
### Changing the resolution
|
### Changing the resolution
|
||||||
@ -64,10 +64,10 @@ beat(4) :: hydra.hush() // or this one
|
|||||||
You can change Hydra resolution using this simple method:
|
You can change Hydra resolution using this simple method:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Changing Hydra resolution",
|
"Changing Hydra resolution",
|
||||||
`hydra.setResolution(1024, 768)`,
|
`hydra.setResolution(1024, 768)`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
@ -87,8 +87,8 @@ ${makeExample("Hydra namespace", `hydra.voronoi(20).out()`, true)}
|
|||||||
Topos embeds a small <ic>.gif</ic> picture player with a small API. GIFs are automatically fading out after the given duration. Look at the following example:
|
Topos embeds a small <ic>.gif</ic> picture player with a small API. GIFs are automatically fading out after the given duration. Look at the following example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing many gifs",
|
"Playing many gifs",
|
||||||
`
|
`
|
||||||
beat(0.25)::gif({
|
beat(0.25)::gif({
|
||||||
url:v('gif')[$(1)%6], // Any URL will do!
|
url:v('gif')[$(1)%6], // Any URL will do!
|
||||||
opacity: r(0.5, 1), // Opacity (0-1)
|
opacity: r(0.5, 1), // Opacity (0-1)
|
||||||
@ -100,7 +100,7 @@ beat(0.25)::gif({
|
|||||||
posX: ir(1,1200), // CSS Horizontal Position
|
posX: ir(1,1200), // CSS Horizontal Position
|
||||||
posY: ir(1, 800), // CSS Vertical Position
|
posY: ir(1, 800), // CSS Vertical Position
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
5
src/documentation/more/index.ts
Normal file
5
src/documentation/more/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export { about } from './about';
|
||||||
|
export { bonus } from './bonus';
|
||||||
|
export { oscilloscope } from './oscilloscope';
|
||||||
|
export { synchronisation } from './synchronisation';
|
||||||
|
export { visualization } from './visualization.ts';
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const oscilloscope = (application: Editor): string => {
|
export const oscilloscope = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -10,18 +10,18 @@ You can turn on the oscilloscope to generate interesting visuals or to inspect a
|
|||||||
You need to manually feed the scope with the sounds you want to inspect:
|
You need to manually feed the scope with the sounds you want to inspect:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Feeding a sine to the oscilloscope",
|
"Feeding a sine to the oscilloscope",
|
||||||
`
|
`
|
||||||
beat(1)::sound('sine').freq(200).ad(0, .2).scope().out()
|
beat(1)::sound('sine').freq(200).ad(0, .2).scope().out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Here is a layout of the scope configuration options:
|
Here is a layout of the scope configuration options:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Oscilloscope configuration",
|
"Oscilloscope configuration",
|
||||||
`
|
`
|
||||||
scope({
|
scope({
|
||||||
enabled: true, // off by default
|
enabled: true, // off by default
|
||||||
color: "#fdba74", // any valid CSS color or "random"
|
color: "#fdba74", // any valid CSS color or "random"
|
||||||
@ -35,12 +35,12 @@ scope({
|
|||||||
refresh: 1 // refresh rate (in pulses)
|
refresh: 1 // refresh rate (in pulses)
|
||||||
})
|
})
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Demo with multiple scope mode",
|
"Demo with multiple scope mode",
|
||||||
`
|
`
|
||||||
rhythm(.5, [4,5].dur(4*3, 4*1), 8)::sound('fhardkick').out()
|
rhythm(.5, [4,5].dur(4*3, 4*1), 8)::sound('fhardkick').out()
|
||||||
beat(0.25)::sound('square').freq([
|
beat(0.25)::sound('square').freq([
|
||||||
[250, 250/2, 250/4].pick(),
|
[250, 250/2, 250/4].pick(),
|
||||||
@ -56,8 +56,8 @@ scope({enabled: true, thickness: 8,
|
|||||||
color: ['purple', 'green', 'random'].beat(),
|
color: ['purple', 'green', 'random'].beat(),
|
||||||
size: 0.5, fftSize: 2048})
|
size: 0.5, fftSize: 2048})
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Note that these values can be patterned as well! You can transform the oscilloscope into its own light show if you want. The picture is not stable anyway so you won't have much use of it for precision work :)
|
Note that these values can be patterned as well! You can transform the oscilloscope into its own light show if you want. The picture is not stable anyway so you won't have much use of it for precision work :)
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const synchronisation = (app: Editor): string => {
|
export const synchronisation = (app: Editor): string => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { key_shortcut, makeExampleFactory } from "../../Documentation";
|
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const visualization = (application: Editor): string => {
|
export const visualization = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -18,10 +18,10 @@ While Topos is mainly being developed as a live coding environment for algorithm
|
|||||||
[Hydra](https://hydra.ojack.xyz/?sketch_id=mahalia_1) is a popular live-codable video synthesizer developed by [Olivia Jack](https://ojack.xyz/) and other contributors. It follows an analog synthesizer patching metaphor to encourage live coding complex shaders. Being very easy to use, extremely powerful and also very rewarding to use, Hydra has become a popular choice for adding visuals into a live code performance.
|
[Hydra](https://hydra.ojack.xyz/?sketch_id=mahalia_1) is a popular live-codable video synthesizer developed by [Olivia Jack](https://ojack.xyz/) and other contributors. It follows an analog synthesizer patching metaphor to encourage live coding complex shaders. Being very easy to use, extremely powerful and also very rewarding to use, Hydra has become a popular choice for adding visuals into a live code performance.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Hydra integration",
|
"Hydra integration",
|
||||||
`beat(4) :: hydra.osc(3, 0.5, 2).out()`,
|
`beat(4) :: hydra.osc(3, 0.5, 2).out()`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Close the documentation to see the effect: ${key_shortcut(
|
Close the documentation to see the effect: ${key_shortcut(
|
||||||
"Ctrl+D",
|
"Ctrl+D",
|
||||||
@ -32,23 +32,23 @@ Be careful not to call <ic>hydra</ic> too often as it can impact performances. Y
|
|||||||
Stopping **Hydra** is simple:
|
Stopping **Hydra** is simple:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Stopping Hydra",
|
"Stopping Hydra",
|
||||||
`
|
`
|
||||||
beat(4) :: stop_hydra() // this one
|
beat(4) :: stop_hydra() // this one
|
||||||
beat(4) :: hydra.hush() // or this one
|
beat(4) :: hydra.hush() // or this one
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Changing the resolution
|
### Changing the resolution
|
||||||
|
|
||||||
You can change Hydra resolution using this simple method:
|
You can change Hydra resolution using this simple method:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Changing Hydra resolution",
|
"Changing Hydra resolution",
|
||||||
`hydra.setResolution(1024, 768)`,
|
`hydra.setResolution(1024, 768)`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
### Hydra documentation
|
### Hydra documentation
|
||||||
|
|
||||||
@ -68,8 +68,8 @@ ${makeExample("Hydra namespace", `hydra.voronoi(20).out()`, true)}
|
|||||||
Topos embeds a small <ic>.gif</ic> picture player with a small API. GIFs are automatically fading out after the given duration. Look at the following example:
|
Topos embeds a small <ic>.gif</ic> picture player with a small API. GIFs are automatically fading out after the given duration. Look at the following example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Playing many gifs",
|
"Playing many gifs",
|
||||||
`
|
`
|
||||||
beat(0.25)::gif({
|
beat(0.25)::gif({
|
||||||
url:v('gif')[$(1)%6], // Any URL will do!
|
url:v('gif')[$(1)%6], // Any URL will do!
|
||||||
opacity: r(0.5, 1), // Opacity (0-1)
|
opacity: r(0.5, 1), // Opacity (0-1)
|
||||||
@ -81,8 +81,8 @@ beat(0.25)::gif({
|
|||||||
posX: ir(1,1200), // CSS Horizontal Position
|
posX: ir(1,1200), // CSS Horizontal Position
|
||||||
posY: ir(1, 800), // CSS Vertical Position
|
posY: ir(1, 800), // CSS Vertical Position
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Canvas live coding
|
## Canvas live coding
|
||||||
|
|
||||||
@ -95,8 +95,8 @@ In addition to the standard Canvas API, Topos also includes some pre-defined sha
|
|||||||
* <ic>draw(f: Function)</ic> - Draws to a canvas with the given function.
|
* <ic>draw(f: Function)</ic> - Draws to a canvas with the given function.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Drawing to canvas",
|
"Drawing to canvas",
|
||||||
`
|
`
|
||||||
beat(0.5) && clear() && draw(context => {
|
beat(0.5) && clear() && draw(context => {
|
||||||
context.fillStyle = 'red';
|
context.fillStyle = 'red';
|
||||||
|
|
||||||
@ -117,30 +117,30 @@ beat(0.5) && clear() && draw(context => {
|
|||||||
context.fill();
|
context.fill();
|
||||||
})
|
})
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using draw with events and shapes",
|
"Using draw with events and shapes",
|
||||||
`
|
`
|
||||||
beat(0.25) && sound("bass1:5").pitch(rI(1,6)).draw(x => {
|
beat(0.25) && sound("bass1:5").pitch(rI(1,6)).draw(x => {
|
||||||
donut(x.pitch)
|
donut(x.pitch)
|
||||||
}).out()
|
}).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using draw with ziffers and shapes",
|
"Using draw with ziffers and shapes",
|
||||||
`
|
`
|
||||||
z1("1/8 (0 2 1 4)+(2 1)").sound("sine").ad(0.05,.25).clear()
|
z1("1/8 (0 2 1 4)+(2 1)").sound("sine").ad(0.05,.25).clear()
|
||||||
.draw(x => {
|
.draw(x => {
|
||||||
pie({slices:7,eaten:(7-x.pitch-1),fillStyle:"green", rotate: 250})
|
pie({slices:7,eaten:(7-x.pitch-1),fillStyle:"green", rotate: 250})
|
||||||
}).log("pitch").out()
|
}).log("pitch").out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
* <ic<image(url, x, y, width, height, rotation)</ic> - Draws an image to a canvas.
|
* <ic<image(url, x, y, width, height, rotation)</ic> - Draws an image to a canvas.
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ ${makeExample(
|
|||||||
beat(0.5) && clear() && image("http://localhost:8000/topos_frog.svg",200,200+epulse()%15)
|
beat(0.5) && clear() && image("http://localhost:8000/topos_frog.svg",200,200+epulse()%15)
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
* <ic>clear()</ic> - Clears the canvas.
|
* <ic>clear()</ic> - Clears the canvas.
|
||||||
* <ic>background(fill: string)</ic> - Sets the background color, image or gradient.
|
* <ic>background(fill: string)</ic> - Sets the background color, image or gradient.
|
||||||
@ -166,22 +166,22 @@ Text can be drawn to canvas using the <ic>drawText()</ic> function. The function
|
|||||||
* <ic>drawText(text, fontSize, rotation, font, x, y)</ic> - Draws text to a canvas.
|
* <ic>drawText(text, fontSize, rotation, font, x, y)</ic> - Draws text to a canvas.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Writing to canvas",
|
"Writing to canvas",
|
||||||
`
|
`
|
||||||
beat(0.5) && clear() && drawText("Hello world!", 100, 0, "Arial", 100, 100)
|
beat(0.5) && clear() && drawText("Hello world!", 100, 0, "Arial", 100, 100)
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
* <ic>randomChar(number, min, max)</ic> - Returns a number of random characters from given unicode range.
|
* <ic>randomChar(number, min, max)</ic> - Returns a number of random characters from given unicode range.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Drawing random characters to canvas",
|
"Drawing random characters to canvas",
|
||||||
`
|
`
|
||||||
beat(0.5) && clear() && drawText(randomChar(10,1000,2000),30)
|
beat(0.5) && clear() && drawText(randomChar(10,1000,2000),30)
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
* <ic>emoji(size)</ic> - Returns a random emojis as text.
|
* <ic>emoji(size)</ic> - Returns a random emojis as text.
|
||||||
|
|
||||||
@ -195,7 +195,7 @@ ${makeExample(
|
|||||||
beat(0.5) && clear() && drawText({x: 10, y: epulse()%700, text: food(50)})
|
beat(0.5) && clear() && drawText({x: 10, y: epulse()%700, text: food(50)})
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
* <ic>expression(size)</ic> - Returns a random expression emojis as text.
|
* <ic>expression(size)</ic> - Returns a random expression emojis as text.
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
|
|
||||||
export const chaining = (application: Editor): string => {
|
export const chaining = (application: Editor): string => {
|
||||||
@ -9,12 +9,12 @@ export const chaining = (application: Editor): string => {
|
|||||||
You might have noticed that **Topos** is using chains a lot. Chains are a very common pattern when programming, especially when you deal with objets that can be composed from many changing properties. Method chaining is used by many objects but mostly by <ic>sound()</ic> and <ic>midi()</ic>. It looks like this:
|
You might have noticed that **Topos** is using chains a lot. Chains are a very common pattern when programming, especially when you deal with objets that can be composed from many changing properties. Method chaining is used by many objects but mostly by <ic>sound()</ic> and <ic>midi()</ic>. It looks like this:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Method chaining",
|
"Method chaining",
|
||||||
`
|
`
|
||||||
beat(1)::sound('bd').speed(2).lpf(500).out()
|
beat(1)::sound('bd').speed(2).lpf(500).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Method chains become fun if you add just a little bit of complexity to them. You can start to add conditions, start to register complex chains to be re-used later on, etc.. We will not remind you how to write basic chains. The whole documentation is full of examples! Let's explore more delicate patterns!
|
Method chains become fun if you add just a little bit of complexity to them. You can start to add conditions, start to register complex chains to be re-used later on, etc.. We will not remind you how to write basic chains. The whole documentation is full of examples! Let's explore more delicate patterns!
|
||||||
|
|
||||||
@ -23,22 +23,22 @@ Method chains become fun if you add just a little bit of complexity to them. You
|
|||||||
You can use the <ic>register(...args)</ic> function to... register a chain that you would like to re-use later on.
|
You can use the <ic>register(...args)</ic> function to... register a chain that you would like to re-use later on.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Re-creating a classic Tidal function",
|
"Re-creating a classic Tidal function",
|
||||||
`
|
`
|
||||||
// Playing with extreme panning and playback rate
|
// Playing with extreme panning and playback rate
|
||||||
register('juxrev', n=>n.pan([0, 1]).speed([1, -1]))
|
register('juxrev', n=>n.pan([0, 1]).speed([1, -1]))
|
||||||
|
|
||||||
// Using our new abstraction
|
// Using our new abstraction
|
||||||
beat(1)::sound('fhh').juxrev().out()
|
beat(1)::sound('fhh').juxrev().out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
This is an extremely powerful construct. For example, you can use it to create synthesizer presets and reuse them later on. You can also define parameters for your registered functions. For example:
|
This is an extremely powerful construct. For example, you can use it to create synthesizer presets and reuse them later on. You can also define parameters for your registered functions. For example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Creating synth presets",
|
"Creating synth presets",
|
||||||
`
|
`
|
||||||
// Registering a specific synth architecture
|
// Registering a specific synth architecture
|
||||||
register('sub', (n,x=4,y=80)=>n.ad(0, .25)
|
register('sub', (n,x=4,y=80)=>n.ad(0, .25)
|
||||||
.fmi(x).pan([0, 1])
|
.fmi(x).pan([0, 1])
|
||||||
@ -51,16 +51,16 @@ register('sub', (n,x=4,y=80)=>n.ad(0, .25)
|
|||||||
rhythm(.25, [6, 8].beat(), 12)::sound('sine')
|
rhythm(.25, [6, 8].beat(), 12)::sound('sine')
|
||||||
.note([0, 2, 4, 5].scale('minor', 50).beat(0.5))
|
.note([0, 2, 4, 5].scale('minor', 50).beat(0.5))
|
||||||
.sub(8).out()`,
|
.sub(8).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Registering chain for all events
|
## Registering chain for all events
|
||||||
|
|
||||||
The chain can also be registered automatically for all events. This is useful if you want to add a specific effect to all your events.
|
The chain can also be registered automatically for all events. This is useful if you want to add a specific effect to all your events.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Registering chain to all events at once",
|
"Registering chain to all events at once",
|
||||||
`
|
`
|
||||||
z0("h 9 ^ <7 5 3 1>")
|
z0("h 9 ^ <7 5 3 1>")
|
||||||
.sound("sine")
|
.sound("sine")
|
||||||
.out()
|
.out()
|
||||||
@ -71,28 +71,28 @@ z1("0 4 3 2")
|
|||||||
|
|
||||||
all(x=>x.room(1).delay(rI(0,0.5)))
|
all(x=>x.room(1).delay(rI(0,0.5)))
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Logging values from the chain
|
## Logging values from the chain
|
||||||
|
|
||||||
You can use the <ic>log()</ic> function to print values from the current event. This can be useful to debug your code. Useful parameters to log could be **note**, **pitch**, **dur**, **octave** etc...
|
You can use the <ic>log()</ic> function to print values from the current event. This can be useful to debug your code. Useful parameters to log could be **note**, **pitch**, **dur**, **octave** etc...
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Logging values from the chain",
|
"Logging values from the chain",
|
||||||
`
|
`
|
||||||
beat(1) :: sound("sine").pitch(rI(1,6)).log("note").out()
|
beat(1) :: sound("sine").pitch(rI(1,6)).log("note").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Logging values from ziffers pattern",
|
"Logging values from ziffers pattern",
|
||||||
`
|
`
|
||||||
z1("0 3 2 5").scale("rocritonic").sound("sine").log("pitch","note","key").out()
|
z1("0 3 2 5").scale("rocritonic").sound("sine").log("pitch","note","key").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Conditional chaining
|
## Conditional chaining
|
||||||
|
|
||||||
@ -101,17 +101,17 @@ There are cases when you don't always want to apply one or many elements that ar
|
|||||||
All functions from the sound object can be used to modify the event, for example:
|
All functions from the sound object can be used to modify the event, for example:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Modifying sound events with probabilities",
|
"Modifying sound events with probabilities",
|
||||||
`
|
`
|
||||||
beat(.5) && sound('fhh')
|
beat(.5) && sound('fhh')
|
||||||
.odds(1/4, s => s.speed(irand(1,4)))
|
.odds(1/4, s => s.speed(irand(1,4)))
|
||||||
.rarely(s => s.room(0.5).size(8).speed(0.5))
|
.rarely(s => s.room(0.5).size(8).speed(0.5))
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Chance to play a random note",
|
"Chance to play a random note",
|
||||||
`
|
`
|
||||||
rhythm(.5, 3, 8) && sound('pluck').note(38).out()
|
rhythm(.5, 3, 8) && sound('pluck').note(38).out()
|
||||||
beat(.5) && sound('pluck').note(60)
|
beat(.5) && sound('pluck').note(60)
|
||||||
.often(s => s.note(57))
|
.often(s => s.note(57))
|
||||||
@ -119,8 +119,8 @@ beat(.5) && sound('pluck').note(60)
|
|||||||
.note(62)
|
.note(62)
|
||||||
.room(0.5).size(3)
|
.room(0.5).size(3)
|
||||||
.out()`,
|
.out()`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
There is a growing collection of probability and chance methods you can use:
|
There is a growing collection of probability and chance methods you can use:
|
||||||
|
|
||||||
@ -145,14 +145,14 @@ There is a growing collection of probability and chance methods you can use:
|
|||||||
The conditional chaining also applies to MIDI. Values can also be incremented using <ic>+=</ic> notation.
|
The conditional chaining also applies to MIDI. Values can also be incremented using <ic>+=</ic> notation.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Modifying midi events with probabilities",
|
"Modifying midi events with probabilities",
|
||||||
`beat(.5) && midi(60).channel(1)
|
`beat(.5) && midi(60).channel(1)
|
||||||
.odds(1/4, n => n.channel(2))
|
.odds(1/4, n => n.channel(2))
|
||||||
.often(n => n.note+=4)
|
.often(n => n.note+=4)
|
||||||
.sometimes(s => s.velocity(irand(50,100)))
|
.sometimes(s => s.velocity(irand(50,100)))
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
## Ziffers
|
## Ziffers
|
||||||
|
|
||||||
@ -165,8 +165,8 @@ Ziffers patterns can be chained to <ic>sound()</ic> and <ic>midi()</ic> as well.
|
|||||||
* <ic>midi()</ic> - for outputting pattern as MIDI (See **MIDI**)
|
* <ic>midi()</ic> - for outputting pattern as MIDI (See **MIDI**)
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Ziffer player using a sound chain and probabilities!",
|
"Ziffer player using a sound chain and probabilities!",
|
||||||
`
|
`
|
||||||
z1('s 0 5 7 0 3 7 0 2 7 0 1 7 0 1 6 5 4 3 2')
|
z1('s 0 5 7 0 3 7 0 2 7 0 1 7 0 1 6 5 4 3 2')
|
||||||
.octave([0, 1].beat(2) - 1)
|
.octave([0, 1].beat(2) - 1)
|
||||||
.scale('pentatonic').sound('pluck')
|
.scale('pentatonic').sound('pluck')
|
||||||
@ -174,7 +174,7 @@ z1('s 0 5 7 0 3 7 0 2 7 0 1 7 0 1 6 5 4 3 2')
|
|||||||
.odds(1/2, n => n.speed(0.5))
|
.odds(1/2, n => n.speed(0.5))
|
||||||
.room(0.5).size(0.5).out()
|
.room(0.5).size(0.5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const functions = (application: Editor): string => {
|
export const functions = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -15,20 +15,20 @@ You can control scripts programatically. This is the core concept of Topos after
|
|||||||
- <ic>copy_script(from: number, to: number)</ic>: copies a local script denoted by its number to another local script. **This is a destructive operation!**
|
- <ic>copy_script(from: number, to: number)</ic>: copies a local script denoted by its number to another local script. **This is a destructive operation!**
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Calling a script! The most important feature!",
|
"Calling a script! The most important feature!",
|
||||||
`
|
`
|
||||||
beat(1) :: script(1)
|
beat(1) :: script(1)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Calling mutliple scripts at the same time.",
|
"Calling mutliple scripts at the same time.",
|
||||||
`
|
`
|
||||||
beat(1) :: script(1, 3, 5)
|
beat(1) :: script(1, 3, 5)
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Math functions
|
## Math functions
|
||||||
|
|
||||||
@ -49,10 +49,10 @@ There are some very useful scaling methods taken from **SuperCollider**. You can
|
|||||||
- <ic>curve: number</ic>: <ic>0</ic> is linear, <ic>< 0</ic> is concave, negatively curved, <ic>> 0</ic> is convex, positively curved
|
- <ic>curve: number</ic>: <ic>0</ic> is linear, <ic>< 0</ic> is concave, negatively curved, <ic>> 0</ic> is convex, positively curved
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Scaling an LFO",
|
"Scaling an LFO",
|
||||||
`usine(1/2).linlin(0, 1, 0, 100)`,
|
`usine(1/2).linlin(0, 1, 0, 100)`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -61,24 +61,24 @@ ${makeExample(
|
|||||||
- <ic>delay(ms: number, func: Function): void</ic>: Delays the execution of a function by a given number of milliseconds.
|
- <ic>delay(ms: number, func: Function): void</ic>: Delays the execution of a function by a given number of milliseconds.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Phased woodblocks",
|
"Phased woodblocks",
|
||||||
`
|
`
|
||||||
// Some very low-budget version of phase music
|
// Some very low-budget version of phase music
|
||||||
beat(.5) :: delay(usine(.125) * 80, () => sound('east').out())
|
beat(.5) :: delay(usine(.125) * 80, () => sound('east').out())
|
||||||
beat(.5) :: delay(50, () => sound('east').out())
|
beat(.5) :: delay(50, () => sound('east').out())
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>delayr(ms: number, nb: number, func: Function): void</ic>: Delays the execution of a function by a given number of milliseconds, repeated a given number of times.
|
- <ic>delayr(ms: number, nb: number, func: Function): void</ic>: Delays the execution of a function by a given number of milliseconds, repeated a given number of times.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Another woodblock texture",
|
"Another woodblock texture",
|
||||||
`
|
`
|
||||||
beat(1) :: delayr(50, 4, () => sound('east').speed([0.5,.25].beat()).out())
|
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())
|
flip(2) :: beat(2) :: delayr(150, 4, () => sound('east').speed([0.5,.25].beat() * 4).out())
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const generators = (application: Editor): string => {
|
export const generators = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -15,8 +15,8 @@ Once the generator is cached the values will be returned from the named cache ev
|
|||||||
The resulted values can be played using either <ic>pitch()</ic> or <ic>freq()</ic> or as Ziffers patterns. When playing the values using <ic>pitch()</ic> different scales and chained methods can be used to alter the result, for example <ic>mod(value: number)</ic> to limit the integer range or <ic>scale(name: string)</ic> etc. to change the resulting note.
|
The resulted values can be played using either <ic>pitch()</ic> or <ic>freq()</ic> or as Ziffers patterns. When playing the values using <ic>pitch()</ic> different scales and chained methods can be used to alter the result, for example <ic>mod(value: number)</ic> to limit the integer range or <ic>scale(name: string)</ic> etc. to change the resulting note.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Simple looping generator function",
|
"Simple looping generator function",
|
||||||
`
|
`
|
||||||
function* simple() {
|
function* simple() {
|
||||||
let x = 0;
|
let x = 0;
|
||||||
while (x < 12) {
|
while (x < 12) {
|
||||||
@ -27,12 +27,12 @@ function* simple() {
|
|||||||
|
|
||||||
beat(.25) && sound("triangle").pitch(cache("simple",simple())).scale("minor").out()
|
beat(.25) && sound("triangle").pitch(cache("simple",simple())).scale("minor").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Infinite frequency generator",
|
"Infinite frequency generator",
|
||||||
`
|
`
|
||||||
function* poly(x=0) {
|
function* poly(x=0) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const s = Math.tan(x/10)+Math.sin(x/20);
|
const s = Math.tan(x/10)+Math.sin(x/20);
|
||||||
@ -43,14 +43,14 @@ ${makeExample(
|
|||||||
|
|
||||||
beat(.125) && sound("triangle").freq(cache("mathyshit",poly())).out()
|
beat(.125) && sound("triangle").freq(cache("mathyshit",poly())).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
When you want to dance with a dynamical system in controlled musical chaos, Topos is waiting for you:
|
When you want to dance with a dynamical system in controlled musical chaos, Topos is waiting for you:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Truly scale free chaos inspired by Lorentz attractor",
|
"Truly scale free chaos inspired by Lorentz attractor",
|
||||||
`
|
`
|
||||||
function* strange(x = 0.1, y = 0, z = 0, rho = 28, beta = 8 / 3, zeta = 10) {
|
function* strange(x = 0.1, y = 0, z = 0, rho = 28, beta = 8 / 3, zeta = 10) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const dx = 10 * (y - x);
|
const dx = 10 * (y - x);
|
||||||
@ -71,8 +71,8 @@ ${makeExample(
|
|||||||
.adsr(.15,.1,.1,.1)
|
.adsr(.15,.1,.1,.1)
|
||||||
.log("freq").out()
|
.log("freq").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Henon and his discrete music",
|
"Henon and his discrete music",
|
||||||
@ -100,8 +100,8 @@ ${makeExample(
|
|||||||
)};
|
)};
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"1970s fractal dream",
|
"1970s fractal dream",
|
||||||
`
|
`
|
||||||
function* rossler(x = 0.1, y = 0.1, z = 0.1, a = 0.2, b = 0.2, c = 5.7) {
|
function* rossler(x = 0.1, y = 0.1, z = 0.1, a = 0.2, b = 0.2, c = 5.7) {
|
||||||
while (true) {
|
while (true) {
|
||||||
const dx = - y - z;
|
const dx = - y - z;
|
||||||
@ -122,8 +122,8 @@ ${makeExample(
|
|||||||
.adsr(0,.1,.1,.1)
|
.adsr(0,.1,.1,.1)
|
||||||
.log("freq").out()
|
.log("freq").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
|
|
||||||
## OEIS integer sequences
|
## OEIS integer sequences
|
||||||
@ -145,7 +145,7 @@ ${makeExample(
|
|||||||
.gain(1).out()
|
.gain(1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
## Using generators with Ziffers
|
## Using generators with Ziffers
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ Alternatively generators can be used with Ziffers to generate longer patterns. I
|
|||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Ziffers patterns using a generator functions",
|
"Ziffers patterns using a generator functions",
|
||||||
`
|
`
|
||||||
function* poly(x) {
|
function* poly(x) {
|
||||||
while (true) {
|
while (true) {
|
||||||
yield 64 * Math.pow(x, 6) - 480 * Math.pow(x, 4) + 720 * Math.pow(x, 2);
|
yield 64 * Math.pow(x, 6) - 480 * Math.pow(x, 4) + 720 * Math.pow(x, 2);
|
||||||
|
|||||||
7
src/documentation/patterns/index.ts
Normal file
7
src/documentation/patterns/index.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export { chaining } from './chaining';
|
||||||
|
export { functions } from './functions';
|
||||||
|
export { generators } from './generators';
|
||||||
|
export { lfos } from './lfos';
|
||||||
|
export { patterns } from './patterns';
|
||||||
|
export { probabilities } from './probabilities';
|
||||||
|
export { variables } from './variables';
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const lfos = (application: Editor): string => {
|
export const lfos = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -14,46 +14,46 @@ Low Frequency Oscillators (_LFOs_) are an important piece in any digital audio w
|
|||||||
- <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_.
|
- <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(
|
${makeExample(
|
||||||
"Modulating the speed of a sample player using a sine LFO",
|
"Modulating the speed of a sample player using a sine LFO",
|
||||||
`beat(.25) && snd('cp').speed(1 + usine(0.25) * 2).out()`,
|
`beat(.25) && snd('cp').speed(1 + usine(0.25) * 2).out()`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
- <ic>triangle(freq: number = 1, phase: number = 0): number</ic>: returns a triangle oscillation between <ic>-1</ic> and <ic>1</ic>.
|
- <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_.
|
- <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(
|
${makeExample(
|
||||||
"Modulating the speed of a sample player using a triangle LFO",
|
"Modulating the speed of a sample player using a triangle LFO",
|
||||||
`beat(.25) && snd('cp').speed(1 + utriangle(0.25) * 2).out()`,
|
`beat(.25) && snd('cp').speed(1 + utriangle(0.25) * 2).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>saw(freq: number = 1, phase: number = 0): number</ic>: returns a sawtooth-like oscillation between <ic>-1</ic> and <ic>1</ic>.
|
- <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_.
|
- <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(
|
${makeExample(
|
||||||
"Modulating the speed of a sample player using a saw LFO",
|
"Modulating the speed of a sample player using a saw LFO",
|
||||||
`beat(.25) && snd('cp').speed(1 + usaw(0.25) * 2).out()`,
|
`beat(.25) && snd('cp').speed(1 + usaw(0.25) * 2).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <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>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.
|
- <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(
|
${makeExample(
|
||||||
"Modulating the speed of a sample player using a square LFO",
|
"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()`,
|
`beat(.25) && snd('cp').speed(1 + usquare(0.25, 0, 0.25) * 2).out()`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
- <ic>noise(times: number = 1)</ic>: returns a random value between -1 and 1.
|
- <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.
|
- <ic>unoise(times: number = 1)</ic>: returns a random value between 0 and 1.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Modulating the speed of a sample player using noise",
|
"Modulating the speed of a sample player using noise",
|
||||||
`beat(.25) && snd('cp').speed(1 + noise() * 2).out()`,
|
`beat(.25) && snd('cp').speed(1 + noise() * 2).out()`,
|
||||||
true,
|
true,
|
||||||
)};
|
)};
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const patterns = (application: Editor): string => {
|
export const patterns = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -10,24 +10,24 @@ export const patterns = (application: Editor): string => {
|
|||||||
It means that the following:
|
It means that the following:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Boring kick",
|
"Boring kick",
|
||||||
`
|
`
|
||||||
beat(1)::sound('kick').out()
|
beat(1)::sound('kick').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
can be turned into something more interesting like this easily:
|
can be turned into something more interesting like this easily:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Less boring kick",
|
"Less boring kick",
|
||||||
`
|
`
|
||||||
let c = [1,2].dur(3, 1)
|
let c = [1,2].dur(3, 1)
|
||||||
beat([1, 0.5, 0.25].dur(0.75, 0.25, 1) / c)::sound(['kick', 'fsoftsnare'].beat(0.75))
|
beat([1, 0.5, 0.25].dur(0.75, 0.25, 1) / c)::sound(['kick', 'fsoftsnare'].beat(0.75))
|
||||||
.ad(0, .25).shape(usine(1/2)*0.5).speed([1, 2, 4].beat(0.5)).out()
|
.ad(0, .25).shape(usine(1/2)*0.5).speed([1, 2, 4].beat(0.5)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
**Topos** comes with a lot of array methods to deal with musical patterns of increasing complexity. Some knowledge of patterns and how to use them will help you to break out of simple loops and repeating structures. The most basic JavaScript data structure is the [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Topos is extending it with custom methods to describe patterns that evolve over time. These methods can often be chained to compose more complex expressions: <ic>[1, 2, 3].repeatOdd(5).palindrome().beat()</ic>.
|
**Topos** comes with a lot of array methods to deal with musical patterns of increasing complexity. Some knowledge of patterns and how to use them will help you to break out of simple loops and repeating structures. The most basic JavaScript data structure is the [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). Topos is extending it with custom methods to describe patterns that evolve over time. These methods can often be chained to compose more complex expressions: <ic>[1, 2, 3].repeatOdd(5).palindrome().beat()</ic>.
|
||||||
@ -37,18 +37,18 @@ beat([1, 0.5, 0.25].dur(0.75, 0.25, 1) / c)::sound(['kick', 'fsoftsnare'].beat(0
|
|||||||
- <ic>beat(division: number)</ic>: this method will return the next value in the list every _n_ pulses. By default, <ic>1</ic> equals to one beat but integer and floating point number values are supported as well. This method is extremely powerful and can be used for many different purposes. Check out the examples.
|
- <ic>beat(division: number)</ic>: this method will return the next value in the list every _n_ pulses. By default, <ic>1</ic> equals to one beat but integer and floating point number values are supported as well. This method is extremely powerful and can be used for many different purposes. Check out the examples.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Light drumming",
|
"Light drumming",
|
||||||
`
|
`
|
||||||
// Every bar, use a different rhythm
|
// Every bar, use a different rhythm
|
||||||
beat([1, 0.75].beat(4)) :: sound('cp').out()
|
beat([1, 0.75].beat(4)) :: sound('cp').out()
|
||||||
beat([0.5, 1].beat(4)) :: sound('kick').out()
|
beat([0.5, 1].beat(4)) :: sound('kick').out()
|
||||||
beat(2)::snd('snare').shape(.5).out()
|
beat(2)::snd('snare').shape(.5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using beat to create arpeggios",
|
"Using beat to create arpeggios",
|
||||||
`
|
`
|
||||||
// Arpeggio using pulse divisions
|
// Arpeggio using pulse divisions
|
||||||
beat([.5, .25].beat(0.5)) :: sound('sine')
|
beat([.5, .25].beat(0.5)) :: sound('sine')
|
||||||
.lpf(100+usine(1/4)*400).lpad(2, 0, .25)
|
.lpf(100+usine(1/4)*400).lpad(2, 0, .25)
|
||||||
@ -62,25 +62,25 @@ beat([.5, .25].beat(0.5)) :: sound('sine')
|
|||||||
.delayfb(0.5)
|
.delayfb(0.5)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Cool ambiance",
|
"Cool ambiance",
|
||||||
`
|
`
|
||||||
beat(.5) :: snd(['kick', 'hat'].beat(0.5)).out()
|
beat(.5) :: snd(['kick', 'hat'].beat(0.5)).out()
|
||||||
beat([2,4].beat(2)) :: snd('shaker').delay(.5).delayfb(.75).delayt(0.125).out()
|
beat([2,4].beat(2)) :: snd('shaker').delay(.5).delayfb(.75).delayt(0.125).out()
|
||||||
flip(2)::beat(1)::snd('froomy').out()
|
flip(2)::beat(1)::snd('froomy').out()
|
||||||
flip(4)::beat(2)::snd('pad').n(2).shape(.5)
|
flip(4)::beat(2)::snd('pad').n(2).shape(.5)
|
||||||
.orbit(2).room(0.9).size(0.9).release(0.5).out()
|
.orbit(2).room(0.9).size(0.9).release(0.5).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>bar(value: number = 1)</ic>: returns the next value every bar (if <ic>value = 1</ic>). Using a larger value will return the next value every <ic>n</ic> bars.
|
- <ic>bar(value: number = 1)</ic>: returns the next value every bar (if <ic>value = 1</ic>). Using a larger value will return the next value every <ic>n</ic> bars.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"A simple drumbeat in no time!",
|
"A simple drumbeat in no time!",
|
||||||
`
|
`
|
||||||
beat(1)::sound(['kick', 'hat', 'snare', 'hat'].beat()).out()
|
beat(1)::sound(['kick', 'hat', 'snare', 'hat'].beat()).out()
|
||||||
beat([1/4, 1/2].dur(1.5, 0.5))::sound(['jvbass', 'fikea'].bar())
|
beat([1/4, 1/2].dur(1.5, 0.5))::sound(['jvbass', 'fikea'].bar())
|
||||||
.ad(0, .25).room(0.5).size(2).resonance(0.15).lpf(
|
.ad(0, .25).room(0.5).size(2).resonance(0.15).lpf(
|
||||||
@ -88,12 +88,12 @@ beat([1/4, 1/2].dur(1.5, 0.5))::sound(['jvbass', 'fikea'].bar())
|
|||||||
* [1, 2].bar())
|
* [1, 2].bar())
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using beat and bar in the same example",
|
"Using beat and bar in the same example",
|
||||||
`
|
`
|
||||||
beat(2)::snd('snare').out()
|
beat(2)::snd('snare').out()
|
||||||
beat([1, 0.5].beat()) :: sound(['bass3'].bar())
|
beat([1, 0.5].beat()) :: sound(['bass3'].bar())
|
||||||
.freq(100).n([12, 14].bar())
|
.freq(100).n([12, 14].bar())
|
||||||
@ -102,13 +102,13 @@ beat([1, 0.5].beat()) :: sound(['bass3'].bar())
|
|||||||
.speed([1,2,3].beat())
|
.speed([1,2,3].beat())
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>dur(...list: numbers[])</ic> : keeps the same value for a duration of <ic>n</ic> beats corresponding to the <ic>nth</ic> number of the list you provide.
|
- <ic>dur(...list: numbers[])</ic> : keeps the same value for a duration of <ic>n</ic> beats corresponding to the <ic>nth</ic> number of the list you provide.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Holding a value for n beats",
|
"Holding a value for n beats",
|
||||||
`
|
`
|
||||||
// The second note is kept for twice as long
|
// The second note is kept for twice as long
|
||||||
beat(0.5)::sound('notes').n([1,2].dur(1, 2))
|
beat(0.5)::sound('notes').n([1,2].dur(1, 2))
|
||||||
.room(0.5).size(8).delay(0.125).delayt(1/8)
|
.room(0.5).size(8).delay(0.125).delayt(1/8)
|
||||||
@ -117,12 +117,12 @@ beat(0.5)::sound('notes').n([1,2].dur(1, 2))
|
|||||||
beat(1)::sound(['kick', 'fsnare'].dur(3, 1))
|
beat(1)::sound(['kick', 'fsnare'].dur(3, 1))
|
||||||
.n([0,3].dur(3, 1)).out()
|
.n([0,3].dur(3, 1)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Patterning with ternary statements",
|
"Patterning with ternary statements",
|
||||||
`
|
`
|
||||||
const dada = flipbar(2) ? [0,[3,5,-1].bar(3),2,3] : [9,8,9,6]
|
const dada = flipbar(2) ? [0,[3,5,-1].bar(3),2,3] : [9,8,9,6]
|
||||||
beat(0.5) :: sound('wt_hvoice:3')
|
beat(0.5) :: sound('wt_hvoice:3')
|
||||||
.pitch(dada.beat(0.5))
|
.pitch(dada.beat(0.5))
|
||||||
@ -136,8 +136,8 @@ beat(1) :: sound('kick').n(4).out()
|
|||||||
onbeat([0.5,0.8].beat(1),2) :: sound('snare').out()
|
onbeat([0.5,0.8].beat(1),2) :: sound('snare').out()
|
||||||
onbeat(0.5,0.8,1,1.5,2,2.5,3,4) :: sound('hh').out()
|
onbeat(0.5,0.8,1,1.5,2,2.5,3,4) :: sound('hh').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Iteration using a counter
|
## Iteration using a counter
|
||||||
|
|
||||||
@ -145,68 +145,68 @@ onbeat(0.5,0.8,1,1.5,2,2.5,3,4) :: sound('hh').out()
|
|||||||
- <ic>$(name,limit?,step?)</ic>: shorter alias for the counter.
|
- <ic>$(name,limit?,step?)</ic>: shorter alias for the counter.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using counter to iterate over a list",
|
"Using counter to iterate over a list",
|
||||||
`
|
`
|
||||||
beat(0.5) :: sound("bd").gain(line(0,1,0.01).$("ramp")).out()
|
beat(0.5) :: sound("bd").gain(line(0,1,0.01).$("ramp")).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Manipulating notes and scales
|
## Manipulating notes and scales
|
||||||
|
|
||||||
- <ic>pitch()</ic>: convert a list of integers to pitch classes
|
- <ic>pitch()</ic>: convert a list of integers to pitch classes
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Converting a list of integers to pitch classes using key and scale",
|
"Converting a list of integers to pitch classes using key and scale",
|
||||||
`
|
`
|
||||||
beat(0.25) :: snd('sine')
|
beat(0.25) :: snd('sine')
|
||||||
.pitch([0,1,2,3,4,6,7,8].beat(0.125))
|
.pitch([0,1,2,3,4,6,7,8].beat(0.125))
|
||||||
.key(["F4","F3"].beat(2.0))
|
.key(["F4","F3"].beat(2.0))
|
||||||
.scale("minor").ad(0, .25).out()
|
.scale("minor").ad(0, .25).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>semitones(number[], ...args?)</ic>: Create scale from semitone intervals.
|
- <ic>semitones(number[], ...args?)</ic>: Create scale from semitone intervals.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play pitches from scale created from semitone intervals",
|
"Play pitches from scale created from semitone intervals",
|
||||||
`
|
`
|
||||||
beat(1) :: sound('gtr').pitch([0, 4, 3, 2].beat()).key(64)
|
beat(1) :: sound('gtr').pitch([0, 4, 3, 2].beat()).key(64)
|
||||||
.semitones(1, 1, 3, 1, 1, 2, 3).out()
|
.semitones(1, 1, 3, 1, 1, 2, 3).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>cents(number[], ...args?)</ic>: Create scale from cent intervals.
|
- <ic>cents(number[], ...args?)</ic>: Create scale from cent intervals.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play pitches from scale created from cent intervals",
|
"Play pitches from scale created from cent intervals",
|
||||||
`
|
`
|
||||||
rhythm([0.5,0.25].beat(1),14,16) :: sound('pluck')
|
rhythm([0.5,0.25].beat(1),14,16) :: sound('pluck')
|
||||||
.stretch(iR(1,5)).pitch(iR(0,6)).key(57)
|
.stretch(iR(1,5)).pitch(iR(0,6)).key(57)
|
||||||
.cents(120,270,540,670,785,950,1215).out()
|
.cents(120,270,540,670,785,950,1215).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>ratios(number[], ...args?)</ic>: Create scale from ratios.
|
- <ic>ratios(number[], ...args?)</ic>: Create scale from ratios.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play pitches from scale created from ratios",
|
"Play pitches from scale created from ratios",
|
||||||
`
|
`
|
||||||
rhythm([0.5,0.25].beat(0.25),5,7) :: sound('east:3')
|
rhythm([0.5,0.25].beat(0.25),5,7) :: sound('east:3')
|
||||||
.pitch([0,1,2,3,4,5,6,7,8,9,10,11].beat(0.25)).key(67)
|
.pitch([0,1,2,3,4,5,6,7,8,9,10,11].beat(0.25)).key(67)
|
||||||
.ratios(2/11,4/11,6/11,8/11,10/11,11/11).out()
|
.ratios(2/11,4/11,6/11,8/11,10/11,11/11).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>edo(number, scale?: string|number[])</ic>: Create scale from equal divisions of the octave. Creates chromatic scale by default.
|
- <ic>edo(number, scale?: string|number[])</ic>: Create scale from equal divisions of the octave. Creates chromatic scale by default.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Play pitches from scale created from equal divisions of the octave",
|
"Play pitches from scale created from equal divisions of the octave",
|
||||||
`
|
`
|
||||||
z0("e bd bd <bd bd [bd bd] [bd bd bd bd]>").sound().out()
|
z0("e bd bd <bd bd [bd bd] [bd bd bd bd]>").sound().out()
|
||||||
flipbar(1) :: rhythm(.25,14,16) :: sound("ST10:30").stretch(3).gain(0.5)
|
flipbar(1) :: rhythm(.25,14,16) :: sound("ST10:30").stretch(3).gain(0.5)
|
||||||
.pitch([0,10,r(20,40),r(100,200),r(-200,200),r(200,300),200,r(3,666)].beat([1.0,0.5,0.25].bar(6)))
|
.pitch([0,10,r(20,40),r(100,200),r(-200,200),r(200,300),200,r(3,666)].beat([1.0,0.5,0.25].bar(6)))
|
||||||
@ -218,57 +218,57 @@ rhythm(2.0,26,32) :: sound("ST20").n([22,5,24,34,31,5,11,19].pick()).stretch(rI(
|
|||||||
.edo(666)
|
.edo(666)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
- <ic>scale(scale: string, base note: number)</ic>: Map each element of the list to the closest note of the slected scale. [0, 2, 3, 5 ].scale("major", 50) returns [50, 52, <ic>54</ic>, 55]. You can use western scale names like (Major, Minor, Minor pentatonic ...) or [zeitler](https://ianring.com/musictheory/scales/traditions/zeitler) scale names. Alternatively you can also use the integers as used by Ian Ring in his [study of scales](https://ianring.com/musictheory/scales/).
|
- <ic>scale(scale: string, base note: number)</ic>: Map each element of the list to the closest note of the slected scale. [0, 2, 3, 5 ].scale("major", 50) returns [50, 52, <ic>54</ic>, 55]. You can use western scale names like (Major, Minor, Minor pentatonic ...) or [zeitler](https://ianring.com/musictheory/scales/traditions/zeitler) scale names. Alternatively you can also use the integers as used by Ian Ring in his [study of scales](https://ianring.com/musictheory/scales/).
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Mapping the note array to the E3 major scale",
|
"Mapping the note array to the E3 major scale",
|
||||||
`
|
`
|
||||||
beat(1) :: snd('gtr')
|
beat(1) :: snd('gtr')
|
||||||
.note([0, 5, 2, 1, 7].scale("Major", 52).beat())
|
.note([0, 5, 2, 1, 7].scale("Major", 52).beat())
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>scaleArp(scale: string, mask: number)</ic>: extrapolate a custom-masked scale from each list elements. [0].scale("major", 3) returns [0,2,4]. <ic>scaleArp</ic> supports the same scales as <ic>scale</ic>.
|
- <ic>scaleArp(scale: string, mask: number)</ic>: extrapolate a custom-masked scale from each list elements. [0].scale("major", 3) returns [0,2,4]. <ic>scaleArp</ic> supports the same scales as <ic>scale</ic>.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Extrapolate a 3-elements Mixolydian scale from 2 notes",
|
"Extrapolate a 3-elements Mixolydian scale from 2 notes",
|
||||||
`
|
`
|
||||||
beat(1) :: snd('gtr')
|
beat(1) :: snd('gtr')
|
||||||
.note([0, 5].scaleArp("mixolydian", 3).beat() + 50)
|
.note([0, 5].scaleArp("mixolydian", 3).beat() + 50)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Iteration using the mouse
|
## Iteration using the mouse
|
||||||
|
|
||||||
- <ic>mouseX()</ic> / <ic>mouseY()</ic>: divides the screen in <ic>n</ic> zones and returns the value corresponding to the mouse position on screen.</ic>
|
- <ic>mouseX()</ic> / <ic>mouseY()</ic>: divides the screen in <ic>n</ic> zones and returns the value corresponding to the mouse position on screen.</ic>
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Controlling an arpeggio (octave and note) with mouse",
|
"Controlling an arpeggio (octave and note) with mouse",
|
||||||
`
|
`
|
||||||
beat(0.25)::sound('wt_piano')
|
beat(0.25)::sound('wt_piano')
|
||||||
.note([0,2,3,4,5,7,8,9,11,12].scale(
|
.note([0,2,3,4,5,7,8,9,11,12].scale(
|
||||||
'minor', 30 + [0,12,24].mouseY()).mouseX())
|
'minor', 30 + [0,12,24].mouseY()).mouseX())
|
||||||
.room(0.5).size(4).lpad(-2, .2).lpf(500, 0.3)
|
.room(0.5).size(4).lpad(-2, .2).lpf(500, 0.3)
|
||||||
.ad(0, .2).out()
|
.ad(0, .2).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Simple data operations
|
## Simple data operations
|
||||||
|
|
||||||
- <ic>palindrome()</ic>: Concatenates a list with the same list in reverse.
|
- <ic>palindrome()</ic>: Concatenates a list with the same list in reverse.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Palindrome filter sweep",
|
"Palindrome filter sweep",
|
||||||
`
|
`
|
||||||
beat([1,.5,.25].beat()) :: snd('wt_stereo')
|
beat([1,.5,.25].beat()) :: snd('wt_stereo')
|
||||||
.speed([1, 0.5, 0.25])
|
.speed([1, 0.5, 0.25])
|
||||||
.pan(r(0, 1)).freq([100,200,300].beat(0.25))
|
.pan(r(0, 1)).freq([100,200,300].beat(0.25))
|
||||||
@ -277,15 +277,15 @@ beat([1,.5,.25].beat()) :: snd('wt_stereo')
|
|||||||
.lpf([500,1000,2000,4000].palindrome().beat())
|
.lpf([500,1000,2000,4000].palindrome().beat())
|
||||||
.lpad(4, 0, .25).sustain(0.125).out()
|
.lpad(4, 0, .25).sustain(0.125).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>random(index: number)</ic>: pick a random element in the given list.
|
- <ic>random(index: number)</ic>: pick a random element in the given list.
|
||||||
- <ic>rand(index: number)</ic>: shorter alias for the same method.
|
- <ic>rand(index: number)</ic>: shorter alias for the same method.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sipping some gasoline at the robot bar",
|
"Sipping some gasoline at the robot bar",
|
||||||
`
|
`
|
||||||
// rand, random and pick are doing the same thing!
|
// rand, random and pick are doing the same thing!
|
||||||
beat(1)::snd('fhardkick').shape(0.5)
|
beat(1)::snd('fhardkick').shape(0.5)
|
||||||
.ad(0, .1).lpf(500).db(-12).out()
|
.ad(0, .1).lpf(500).db(-12).out()
|
||||||
@ -296,69 +296,69 @@ beat([.5, 1].rand() / 2) :: snd(
|
|||||||
.lpf([5000,3000,2000].pick())
|
.lpf([5000,3000,2000].pick())
|
||||||
.end(0.5).out()
|
.end(0.5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>pick()</ic>: pick a random element in the list.
|
- <ic>pick()</ic>: pick a random element in the list.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Picking values in lists",
|
"Picking values in lists",
|
||||||
`
|
`
|
||||||
beat(0.25)::sound(['ftabla', 'fwood'].pick())
|
beat(0.25)::sound(['ftabla', 'fwood'].pick())
|
||||||
.speed([1,2,3,4].pick()).ad(0, .125).n(ir(1,10))
|
.speed([1,2,3,4].pick()).ad(0, .125).n(ir(1,10))
|
||||||
.room(0.5).size(1).out()
|
.room(0.5).size(1).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>degrade(amount: number)</ic>: removes _n_% of the list elements. Lists can be degraded as long as one element remains. The amount of degradation is given as a percentage.
|
- <ic>degrade(amount: number)</ic>: removes _n_% of the list elements. Lists can be degraded as long as one element remains. The amount of degradation is given as a percentage.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Amen break suffering from data loss",
|
"Amen break suffering from data loss",
|
||||||
`
|
`
|
||||||
// Tweak the value to degrade this amen break even more!
|
// Tweak the value to degrade this amen break even more!
|
||||||
beat(.25)::snd('amencutup').n([1,2,3,4,5,6,7,8,9].degrade(20).loop($(1))).out()
|
beat(.25)::snd('amencutup').n([1,2,3,4,5,6,7,8,9].degrade(20).loop($(1))).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>repeat(amount: number)</ic>: repeat every list elements _n_ times.
|
- <ic>repeat(amount: number)</ic>: repeat every list elements _n_ times.
|
||||||
- <ic>repeatEven(amount: number)</ic>: repeat every pair element of the list _n_ times.
|
- <ic>repeatEven(amount: number)</ic>: repeat every pair element of the list _n_ times.
|
||||||
- <ic>repeatOdd(amount: number)</ic>: repeat every odd element of the list _n_ times.
|
- <ic>repeatOdd(amount: number)</ic>: repeat every odd element of the list _n_ times.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Repeating samples a given number of times",
|
"Repeating samples a given number of times",
|
||||||
`
|
`
|
||||||
beat(.25)::sound('amencutup').n([1,2,3,4,5,6,7,8].repeat(4).beat(.25)).out()
|
beat(.25)::sound('amencutup').n([1,2,3,4,5,6,7,8].repeat(4).beat(.25)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>loop(index: number)</ic>: loop takes one argument, the _index_. It allows you to iterate over a list using an iterator such as a counter. This is super useful to control how you are accessing values in a list without relying on a temporal method such as <ic>.beat()</ic> or </ic>.bar()</ic>.
|
- <ic>loop(index: number)</ic>: loop takes one argument, the _index_. It allows you to iterate over a list using an iterator such as a counter. This is super useful to control how you are accessing values in a list without relying on a temporal method such as <ic>.beat()</ic> or </ic>.bar()</ic>.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Don't you know how to count up to 5?",
|
"Don't you know how to count up to 5?",
|
||||||
`
|
`
|
||||||
beat(1) :: sound('numbers').n([1,2,3,4,5].loop($(3, 10, 2))).out()
|
beat(1) :: sound('numbers').n([1,2,3,4,5].loop($(3, 10, 2))).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>shuffle(): this</ic>: shuffles a list! Simple enough!
|
- <ic>shuffle(): this</ic>: shuffles a list! Simple enough!
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Shuffling a list for extra randomness",
|
"Shuffling a list for extra randomness",
|
||||||
`
|
`
|
||||||
beat(1) :: sound('numbers').n([1,2,3,4,5].shuffle().loop($(1)).out()
|
beat(1) :: sound('numbers').n([1,2,3,4,5].shuffle().loop($(1)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>rotate(steps: number)</ic>: rotate a list to the right _n_ times. The last value become the first, rinse and repeat.
|
- <ic>rotate(steps: number)</ic>: rotate a list to the right _n_ times. The last value become the first, rinse and repeat.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"To make things more complex... here you go",
|
"To make things more complex... here you go",
|
||||||
`
|
`
|
||||||
beat(.25) :: snd('sine').fmi([1.99, 2])
|
beat(.25) :: snd('sine').fmi([1.99, 2])
|
||||||
.ad(0, .125).lpf(500+r(1,400))
|
.ad(0, .125).lpf(500+r(1,400))
|
||||||
.lpad(usine()*8, 0, .125)
|
.lpad(usine()*8, 0, .125)
|
||||||
@ -369,21 +369,21 @@ beat(.25) :: snd('sine').fmi([1.99, 2])
|
|||||||
.beat(.25)) // while the index changes
|
.beat(.25)) // while the index changes
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Filtering
|
## Filtering
|
||||||
|
|
||||||
- <ic>unique()</ic>: filter a list to remove repeated values.
|
- <ic>unique()</ic>: filter a list to remove repeated values.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Demonstrative filtering. Final list is [100, 200]",
|
"Demonstrative filtering. Final list is [100, 200]",
|
||||||
`
|
`
|
||||||
// Remove unique and 100 will repeat four times!
|
// Remove unique and 100 will repeat four times!
|
||||||
beat(1)::snd('sine').sustain(0.1).freq([100,100,100,100,200].unique().beat()).out()
|
beat(1)::snd('sine').sustain(0.1).freq([100,100,100,100,200].unique().beat()).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Simple math operations
|
## Simple math operations
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const probabilities = (application: Editor): string => {
|
export const probabilities = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -13,12 +13,12 @@ There are some simple functions to play with probabilities.
|
|||||||
- <ic>irand(min: number, max:number)</ic>: returns a random integer between <ic>min</ic> and <ic>max</ic>. Shorthands <ic>ir()</ic> or <ic>rI()</ic>.
|
- <ic>irand(min: number, max:number)</ic>: returns a random integer between <ic>min</ic> and <ic>max</ic>. Shorthands <ic>ir()</ic> or <ic>rI()</ic>.
|
||||||
|
|
||||||
${makeExample(
|
${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()
|
rhythm(0.125, 10, 16) :: sound('sid').n(4).note(50 + irand(50, 62) % 8).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
- <ic>prob(p: number)</ic>: return <ic>true</ic> _p_% of time, <ic>false</ic> in other cases.
|
- <ic>prob(p: number)</ic>: return <ic>true</ic> _p_% of time, <ic>false</ic> in other cases.
|
||||||
@ -26,14 +26,14 @@ rhythm(0.125, 10, 16) :: sound('sid').n(4).note(50 + irand(50, 62) % 8).out()
|
|||||||
|
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"The Teletype experience!",
|
"The Teletype experience!",
|
||||||
`
|
`
|
||||||
prob(50) :: script(1);
|
prob(50) :: script(1);
|
||||||
prob(60) :: script(2);
|
prob(60) :: script(2);
|
||||||
prob(80) :: script(toss() ? script(3) : script(4))
|
prob(80) :: script(toss() ? script(3) : script(4))
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
- <ic>seed(val: number|string)</ic>: 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.
|
- <ic>seed(val: number|string)</ic>: 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.
|
||||||
|
|
||||||
@ -59,28 +59,28 @@ By default chance operators will be evaluated 48 times within a beat. You can ch
|
|||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using chance operators",
|
"Using chance operators",
|
||||||
`
|
`
|
||||||
rarely() :: sound('hh').out(); // Rarely 48 times is still a lot
|
rarely() :: sound('hh').out(); // Rarely 48 times is still a lot
|
||||||
rarely(4) :: sound('bd').out(); // Rarely in 4 beats is bit less
|
rarely(4) :: sound('bd').out(); // Rarely in 4 beats is bit less
|
||||||
rarely(8) :: sound('east').out(); // Rarely in 8 beats is even less
|
rarely(8) :: sound('east').out(); // Rarely in 8 beats is even less
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using chance with other operators",
|
"Using chance with other operators",
|
||||||
`
|
`
|
||||||
frequently() :: beat(1) :: sound('kick').out();
|
frequently() :: beat(1) :: sound('kick').out();
|
||||||
often() :: beat(0.5) :: sound('hh').out();
|
often() :: beat(0.5) :: sound('hh').out();
|
||||||
sometimes() :: onbeat(1,3) :: sound('snare').out();
|
sometimes() :: onbeat(1,3) :: sound('snare').out();
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using chance with chaining",
|
"Using chance with chaining",
|
||||||
`
|
`
|
||||||
beat(0.5) && sound("bd")
|
beat(0.5) && sound("bd")
|
||||||
.freq(100)
|
.freq(100)
|
||||||
.sometimes(s=>s.crush(2.5))
|
.sometimes(s=>s.crush(2.5))
|
||||||
@ -92,7 +92,7 @@ ${makeExample(
|
|||||||
.almostNever(n=>n.freq(400))
|
.almostNever(n=>n.freq(400))
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../main";
|
import { type Editor } from "../../main";
|
||||||
import { makeExampleFactory } from "../../Documentation";
|
import { makeExampleFactory } from "../Documentation";
|
||||||
|
|
||||||
export const variables = (application: Editor): string => {
|
export const variables = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -12,22 +12,22 @@ By default, each script is independant from each other. The variables defined in
|
|||||||
There is a <ic>global</ic> object that you can use to store and retrieve information. It is a simple key/value store. You can store any type of data in it:
|
There is a <ic>global</ic> object that you can use to store and retrieve information. It is a simple key/value store. You can store any type of data in it:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Setting a global variable",
|
"Setting a global variable",
|
||||||
`
|
`
|
||||||
// This is script n°3
|
// This is script n°3
|
||||||
global.my_variable = 2
|
global.my_variable = 2
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Getting that variable back and printing!",
|
"Getting that variable back and printing!",
|
||||||
`
|
`
|
||||||
// This is script n°4
|
// This is script n°4
|
||||||
log(global.my_variable)
|
log(global.my_variable)
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
Now your scripts can share information with each other!
|
Now your scripts can share information with each other!
|
||||||
|
|
||||||
@ -47,30 +47,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!
|
**Note:** Counters also come with a secret syntax. They can be called with the **$** symbol!
|
||||||
|
|
||||||
${makeExample(
|
${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()
|
rhythm(.25, 6, 8) :: sound('dr').n($(1)).end(.25).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Using a more complex counter",
|
"Using a more complex counter",
|
||||||
`
|
`
|
||||||
// Limit is 20, step is 5
|
// Limit is 20, step is 5
|
||||||
rhythm(.25, 6, 8) :: sound('dr').n($(1, 20, 5)).end(.25).out()
|
rhythm(.25, 6, 8) :: sound('dr').n($(1, 20, 5)).end(.25).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Calling the drunk mechanism",
|
"Calling the drunk mechanism",
|
||||||
`
|
`
|
||||||
// Limit is 20, step is 5
|
// Limit is 20, step is 5
|
||||||
rhythm(.25, 6, 8) :: sound('dr').n(drunk()).end(.25).out()
|
rhythm(.25, 6, 8) :: sound('dr').n(drunk()).end(.25).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
6
src/documentation/patterns/ziffers/index.ts
Normal file
6
src/documentation/patterns/ziffers/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export { ziffers_basics } from './ziffers_basics';
|
||||||
|
export { ziffers_scales } from './ziffers_scales';
|
||||||
|
export { ziffers_rhythm } from './ziffers_rhythm';
|
||||||
|
export { ziffers_algorithmic } from './ziffers_algorithmic';
|
||||||
|
export { ziffers_tonnetz } from './ziffers_tonnetz';
|
||||||
|
export { ziffers_syncing } from './ziffers_syncing';
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const ziffers_algorithmic = (application: Editor): string => {
|
export const ziffers_algorithmic = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const ziffers_basics = (application: Editor): string => {
|
export const ziffers_basics = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -13,8 +13,8 @@ Ziffers is a **musical number based notation** tuned for _live coding_. It is a
|
|||||||
- embracing a different mindset and approach to time and **patterning**.
|
- embracing a different mindset and approach to time and **patterning**.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Super Fancy Ziffers example",
|
"Super Fancy Ziffers example",
|
||||||
`
|
`
|
||||||
z1('1/8 024!3 035 024 0124').sound('wt_stereo')
|
z1('1/8 024!3 035 024 0124').sound('wt_stereo')
|
||||||
.adsr(0, .4, 0.5, .4).gain(0.1)
|
.adsr(0, .4, 0.5, .4).gain(0.1)
|
||||||
.lpadsr(4, 0, .2, 0, 0)
|
.lpadsr(4, 0, .2, 0, 0)
|
||||||
@ -29,8 +29,8 @@ let osci = 1500 + usine(1/2) * 2000;
|
|||||||
z3('can can:2').sound().gain(1).cutoff(osci).out()
|
z3('can can:2').sound().gain(1).cutoff(osci).out()
|
||||||
z4('1/4 kick kick snare kick').sound().gain(1).cutoff(osci).out()
|
z4('1/4 kick kick snare kick').sound().gain(1).cutoff(osci).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Evaluation
|
## Evaluation
|
||||||
|
|
||||||
@ -58,57 +58,57 @@ The basic Ziffer notation is entirely written in JavaScript strings (_e.g_ <ic>"
|
|||||||
**Note:** Some features are experimental and some are still unsupported. For full / prior syntax see article about <a href="https://zenodo.org/record/7841945" target="_blank">Ziffers</a>.
|
**Note:** Some features are experimental and some are still unsupported. For full / prior syntax see article about <a href="https://zenodo.org/record/7841945" target="_blank">Ziffers</a>.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Pitches from 0 to 9",
|
"Pitches from 0 to 9",
|
||||||
`
|
`
|
||||||
z1('0.25 0 1 2 3 4 5 6 7 8 9').sound('wt_stereo')
|
z1('0.25 0 1 2 3 4 5 6 7 8 9').sound('wt_stereo')
|
||||||
.adsr(0, .1, 0, 0).out()`,
|
.adsr(0, .1, 0, 0).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Escaped pitches using curly brackets",
|
"Escaped pitches using curly brackets",
|
||||||
`z1('_ _ 0 {9 10 11} 4 {12 13 14}')
|
`z1('_ _ 0 {9 10 11} 4 {12 13 14}')
|
||||||
.sound('wt_05').pan(r(0,1))
|
.sound('wt_05').pan(r(0,1))
|
||||||
.cutoff(usaw(1/2) * 4000)
|
.cutoff(usaw(1/2) * 4000)
|
||||||
.room(0.9).size(0.9).out()`,
|
.room(0.9).size(0.9).out()`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Durations using fractions and floating point numbers",
|
"Durations using fractions and floating point numbers",
|
||||||
`
|
`
|
||||||
z1('1/8 0 2 4 0 2 4 1/4 0 3 5 0.25 _ 0 7 0 7')
|
z1('1/8 0 2 4 0 2 4 1/4 0 3 5 0.25 _ 0 7 0 7')
|
||||||
.sound('square').delay(0.5).delayt(1/8)
|
.sound('square').delay(0.5).delayt(1/8)
|
||||||
.adsr(0, .1, 0, 0).delayfb(0.45).out()
|
.adsr(0, .1, 0, 0).delayfb(0.45).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Disco was invented thanks to Ziffers",
|
"Disco was invented thanks to Ziffers",
|
||||||
`
|
`
|
||||||
z1('e _ _ 0 ^ 0 _ 0 ^ 0').sound('jvbass').out()
|
z1('e _ _ 0 ^ 0 _ 0 ^ 0').sound('jvbass').out()
|
||||||
beat(1)::snd('bd').out(); beat(2)::snd('sd').out()
|
beat(1)::snd('bd').out(); beat(2)::snd('sd').out()
|
||||||
beat(3) :: snd('cp').room(0.5).size(0.5).orbit(2).out()
|
beat(3) :: snd('cp').room(0.5).size(0.5).orbit(2).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Accidentals and rests for nice melodies",
|
"Accidentals and rests for nice melodies",
|
||||||
`
|
`
|
||||||
z1('^ 1/8 0 1 b2 3 4 _ 4 b5 4 3 b2 1 0')
|
z1('^ 1/8 0 1 b2 3 4 _ 4 b5 4 3 b2 1 0')
|
||||||
.scale('major').sound('triangle')
|
.scale('major').sound('triangle')
|
||||||
.cutoff(500).lpadsr(5, 0, 1/12, 0, 0)
|
.cutoff(500).lpadsr(5, 0, 1/12, 0, 0)
|
||||||
.fmi(0.5).fmh(2).delay(0.5).delayt(1/3)
|
.fmi(0.5).fmh(2).delay(0.5).delayt(1/3)
|
||||||
.adsr(0, .1, 0, 0).out()
|
.adsr(0, .1, 0, 0).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Repeat items n-times",
|
"Repeat items n-times",
|
||||||
`
|
`
|
||||||
z1('1/8 _ _ 0!4 3!4 4!4 3!4')
|
z1('1/8 _ _ 0!4 3!4 4!4 3!4')
|
||||||
.scale('major').sound('wt_oboe')
|
.scale('major').sound('wt_oboe')
|
||||||
.shape(0.2).sustain(0.1).out()
|
.shape(0.2).sustain(0.1).out()
|
||||||
@ -116,38 +116,38 @@ z2('1/8 _ 0!4 5!4 4!2 7!2')
|
|||||||
.scale('major').sound('wt_oboe')
|
.scale('major').sound('wt_oboe')
|
||||||
.shape(0.2).sustain(0.1).out()
|
.shape(0.2).sustain(0.1).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Subdivided durations",
|
"Subdivided durations",
|
||||||
`
|
`
|
||||||
z1('w [0 [5 [3 7]]] h [0 4]')
|
z1('w [0 [5 [3 7]]] h [0 4]')
|
||||||
.scale('major').sound('sine')
|
.scale('major').sound('sine')
|
||||||
.fmi(usine(.5)).fmh(2).out()
|
.fmi(usine(.5)).fmh(2).out()
|
||||||
`,
|
`,
|
||||||
false,
|
false,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Rests
|
## Rests
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Rest and octaves",
|
"Rest and octaves",
|
||||||
`
|
`
|
||||||
z1('q 0 ^ e0 r _ 0 _ r 4 ^4 4')
|
z1('q 0 ^ e0 r _ 0 _ r 4 ^4 4')
|
||||||
.sound('sine').scale("godian").out()
|
.sound('sine').scale("godian").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Rests with durations",
|
"Rests with durations",
|
||||||
`
|
`
|
||||||
z1('q 0 4 e^r 3 e3 0.5^r h4 1/4^r e 5 r 0.125^r 0')
|
z1('q 0 4 e^r 3 e3 0.5^r h4 1/4^r e 5 r 0.125^r 0')
|
||||||
.sound('sine').scale("aeryptian").out()
|
.sound('sine').scale("aeryptian").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Chords
|
## Chords
|
||||||
|
|
||||||
@ -161,7 +161,7 @@ ${makeExample(
|
|||||||
.room(0.5).size(0.9)
|
.room(0.5).size(0.9)
|
||||||
.scale("minor").out()
|
.scale("minor").out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
@ -171,7 +171,7 @@ ${makeExample(
|
|||||||
.sound('triangle').adsr(0.2, 0.3, 0, 0)
|
.sound('triangle').adsr(0.2, 0.3, 0, 0)
|
||||||
.room(0.5).size(0.9).scale("major").out()
|
.room(0.5).size(0.9).scale("major").out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
@ -182,7 +182,7 @@ ${makeExample(
|
|||||||
.lpadsr(4, 0, .4, 0, 0).size(0.9)
|
.lpadsr(4, 0, .4, 0, 0).size(0.9)
|
||||||
.scale("major").out()
|
.scale("major").out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
@ -227,74 +227,74 @@ ${makeExample(
|
|||||||
Chords can be arpeggiated using the @-character within the ziffers notation or by using <ic>arpeggio</ic> method.
|
Chords can be arpeggiated using the @-character within the ziffers notation or by using <ic>arpeggio</ic> method.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Arpeggio using the mini-notation",
|
"Arpeggio using the mini-notation",
|
||||||
`
|
`
|
||||||
z1("(i v vi%-3 iv%-2)@(s 0 2 0 1 2 1 0 2)")
|
z1("(i v vi%-3 iv%-2)@(s 0 2 0 1 2 1 0 2)")
|
||||||
.sound("sine").out()
|
.sound("sine").out()
|
||||||
`,
|
`,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Arpeggio from named chords with durations",
|
"Arpeggio from named chords with durations",
|
||||||
`
|
`
|
||||||
z1("_ Gm7 ^ C9 D7 Gm7")
|
z1("_ Gm7 ^ C9 D7 Gm7")
|
||||||
.arpeggio("e 0 2 q 3 e 1 2")
|
.arpeggio("e 0 2 q 3 e 1 2")
|
||||||
.sound("sine").out()
|
.sound("sine").out()
|
||||||
`,
|
`,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Arpeggio from roman chords with inversions",
|
"Arpeggio from roman chords with inversions",
|
||||||
`
|
`
|
||||||
z1("i v%-1 vi%-1 iv%-2")
|
z1("i v%-1 vi%-1 iv%-2")
|
||||||
.arpeggio(0,2,1,2)
|
.arpeggio(0,2,1,2)
|
||||||
.noteLength(0.125)
|
.noteLength(0.125)
|
||||||
.sound("sine").out()
|
.sound("sine").out()
|
||||||
`,
|
`,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Chaining
|
## Chaining
|
||||||
|
|
||||||
- Basic notation
|
- Basic notation
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Simple method chaining",
|
"Simple method chaining",
|
||||||
`
|
`
|
||||||
z1('0 1 2 3').key('G3')
|
z1('0 1 2 3').key('G3')
|
||||||
.scale('minor').sound('sine').out()
|
.scale('minor').sound('sine').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"More complex chaining",
|
"More complex chaining",
|
||||||
`
|
`
|
||||||
z1('0 1 2 3 4').key('G3').scale('minor').sound('sine').often(n => n.pitch+=3).rarely(s => s.delay(0.5)).out()
|
z1('0 1 2 3 4').key('G3').scale('minor').sound('sine').often(n => n.pitch+=3).rarely(s => s.delay(0.5)).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Alternative way for inputting options",
|
"Alternative way for inputting options",
|
||||||
`
|
`
|
||||||
z1('0 3 2 4',{key: 'D3', scale: 'minor pentatonic'}).sound('sine').out()
|
z1('0 3 2 4',{key: 'D3', scale: 'minor pentatonic'}).sound('sine').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## String prototypes
|
## String prototypes
|
||||||
|
|
||||||
You can also use string prototypes as an alternative syntax for creating Ziffers patterns
|
You can also use string prototypes as an alternative syntax for creating Ziffers patterns
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"String prototypes",
|
"String prototypes",
|
||||||
`
|
`
|
||||||
"q 0 e 5 2 6 2 q 3".z0().sound('sine').out()
|
"q 0 e 5 2 6 2 q 3".z0().sound('sine').out()
|
||||||
"q 2 7 8 6".z1().octave(-1).sound('sine').out()
|
"q 2 7 8 6".z1().octave(-1).sound('sine').out()
|
||||||
"q 2 7 8 6".z2({key: "C2", scale: "aeolian"}).sound('sine').scale("minor").out()
|
"q 2 7 8 6".z2({key: "C2", scale: "aeolian"}).sound('sine').scale("minor").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const ziffers_rhythm = (application: Editor): string => {
|
export const ziffers_rhythm = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -9,30 +9,30 @@ export const ziffers_rhythm = (application: Editor): string => {
|
|||||||
Ziffers combines rhythmic and melodic notation into a single pattern language. This means that you can use the same pattern to describe both the rhythm and the melody of a musical phrase similarly to the way it is done in traditional music notation.
|
Ziffers combines rhythmic and melodic notation into a single pattern language. This means that you can use the same pattern to describe both the rhythm and the melody of a musical phrase similarly to the way it is done in traditional music notation.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Duration chars",
|
"Duration chars",
|
||||||
`
|
`
|
||||||
z1('q 0 0 4 4 5 5 h4 q 3 3 2 2 1 1 h0').sound('sine').out()
|
z1('q 0 0 4 4 5 5 h4 q 3 3 2 2 1 1 h0').sound('sine').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Fraction durations",
|
"Fraction durations",
|
||||||
`
|
`
|
||||||
z1('1/4 0 0 4 4 5 5 2/4 4 1/4 3 3 2 2 1 1 2/4 0')
|
z1('1/4 0 0 4 4 5 5 2/4 4 1/4 3 3 2 2 1 1 2/4 0')
|
||||||
.sound('sine').out()
|
.sound('sine').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Decimal durations",
|
"Decimal durations",
|
||||||
`
|
`
|
||||||
z1('0.25 5 1 2 6 0.125 3 8 0.5 4 1.0 0')
|
z1('0.25 5 1 2 6 0.125 3 8 0.5 4 1.0 0')
|
||||||
.sound('sine').scale("galian").out()
|
.sound('sine').scale("galian").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## List of all duration characters
|
## List of all duration characters
|
||||||
|
|
||||||
@ -90,68 +90,68 @@ Ziffers maps the following duration characters to the corresponding note lengths
|
|||||||
Samples can be patterned using the sample names or using <c>@</c>-operator for assigning sample to a pitch. Sample index can be changed using the <c>:</c> operator.
|
Samples can be patterned using the sample names or using <c>@</c>-operator for assigning sample to a pitch. Sample index can be changed using the <c>:</c> operator.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sampled drums",
|
"Sampled drums",
|
||||||
`
|
`
|
||||||
z1('bd [hh hh]').octave(-2).sound('sine').out()
|
z1('bd [hh hh]').octave(-2).sound('sine').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"More complex pattern",
|
"More complex pattern",
|
||||||
`
|
`
|
||||||
z1('bd [hh <hh <cp cp:2>>]').octave(-2).sound('sine').out()
|
z1('bd [hh <hh <cp cp:2>>]').octave(-2).sound('sine').out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Pitched samples",
|
"Pitched samples",
|
||||||
`
|
`
|
||||||
z1('0@sax 3@sax 2@sax 6@sax')
|
z1('0@sax 3@sax 2@sax 6@sax')
|
||||||
.octave(-1).sound()
|
.octave(-1).sound()
|
||||||
.adsr(0.25,0.125,0.125,0.25).out()
|
.adsr(0.25,0.125,0.125,0.25).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Pitched samples from list operation",
|
"Pitched samples from list operation",
|
||||||
`
|
`
|
||||||
z1('e (0 3 -1 4)+(-1 0 2 1)@sine')
|
z1('e (0 3 -1 4)+(-1 0 2 1)@sine')
|
||||||
.key('G4')
|
.key('G4')
|
||||||
.scale('110 220 320 450')
|
.scale('110 220 320 450')
|
||||||
.sound().out()
|
.sound().out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Pitched samples with list notation",
|
"Pitched samples with list notation",
|
||||||
`
|
`
|
||||||
z1('e (0 2 6 3 5 -2)@sax (0 2 6 3 5 -2)@arp')
|
z1('e (0 2 6 3 5 -2)@sax (0 2 6 3 5 -2)@arp')
|
||||||
.octave(-1).sound()
|
.octave(-1).sound()
|
||||||
.adsr(0.25,0.125,0.125,0.25).out()
|
.adsr(0.25,0.125,0.125,0.25).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sample indices",
|
"Sample indices",
|
||||||
`
|
`
|
||||||
z1('e 1:2 4:3 6:2')
|
z1('e 1:2 4:3 6:2')
|
||||||
.octave(-1).sound("east").out()
|
.octave(-1).sound("east").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Pitched samples with sample indices",
|
"Pitched samples with sample indices",
|
||||||
`
|
`
|
||||||
z1('_e 1@east:2 4@bd:3 6@arp:2 9@baa').sound().out()
|
z1('_e 1@east:2 4@bd:3 6@arp:2 9@baa').sound().out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const ziffers_scales = (application: Editor): string => {
|
export const ziffers_scales = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -80,8 +80,8 @@ export const ziffers_scales = (application: Editor): string => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Werckmeister scale in Scala format",
|
"Werckmeister scale in Scala format",
|
||||||
`
|
`
|
||||||
const werckmeister = "107.82 203.91 311.72 401.955 503.91 605.865 701.955 809.775 900. 1007.82 1103.91 1200."
|
const werckmeister = "107.82 203.91 311.72 401.955 503.91 605.865 701.955 809.775 900. 1007.82 1103.91 1200."
|
||||||
|
|
||||||
z0('s (0,3) ^ 0 3 ^ 0 (3,6) 0 _ (3,5) 0 _ 3 ^ 0 (3,5) ^ 0 6 0 _ 3 0')
|
z0('s (0,3) ^ 0 3 ^ 0 (3,6) 0 _ (3,5) 0 _ 3 ^ 0 (3,5) ^ 0 6 0 _ 3 0')
|
||||||
@ -94,8 +94,8 @@ ${makeExample(
|
|||||||
|
|
||||||
onbeat(1,1.5,3) :: sound('bd').cutoff(100 + usine(.25) * 1000).out()
|
onbeat(1,1.5,3) :: sound('bd').cutoff(100 + usine(.25) * 1000).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const ziffers_syncing = (application: Editor): string => {
|
export const ziffers_syncing = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
@ -13,19 +13,19 @@ Ziffers patterns can be synced to any event by using **cue**, **sync**, **wait**
|
|||||||
The <ic>cue(name: string)</ic> methods can be used to send cue messages for ziffers patterns. The <ic>wait(name: string)</ic> method is used to wait for the cue message to be received before starting the next cycle.
|
The <ic>cue(name: string)</ic> methods can be used to send cue messages for ziffers patterns. The <ic>wait(name: string)</ic> method is used to wait for the cue message to be received before starting the next cycle.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Sending cue from event and wait",
|
"Sending cue from event and wait",
|
||||||
`
|
`
|
||||||
beat(4.0) :: sound("bd").cue("foo").out()
|
beat(4.0) :: sound("bd").cue("foo").out()
|
||||||
z1("e 0 3 2 1 2 1").wait("foo").sound("sine").out()
|
z1("e 0 3 2 1 2 1").wait("foo").sound("sine").out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
The <ic>sync(name: string)</ic> method is used to sync the ziffers pattern to the cue message.
|
The <ic>sync(name: string)</ic> method is used to sync the ziffers pattern to the cue message.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Delayed start using individual cue",
|
"Delayed start using individual cue",
|
||||||
`
|
`
|
||||||
register('christmas', n=>n.room(0.25).size(2).speed([0.5, 0.25, 0.125])
|
register('christmas', n=>n.room(0.25).size(2).speed([0.5, 0.25, 0.125])
|
||||||
.delay(0.5).delayt(1/3).delayfb(0.5).bpf(200+usine(1/3)*500).out())
|
.delay(0.5).delayt(1/3).delayfb(0.5).bpf(200+usine(1/3)*500).out())
|
||||||
onbar(1) :: cue("bar")
|
onbar(1) :: cue("bar")
|
||||||
@ -33,21 +33,21 @@ The <ic>sync(name: string)</ic> method is used to sync the ziffers pattern to th
|
|||||||
z1("<0.25 0.125> 0 4 2 -2").sync("bar").sound("ST40:25").christmas()
|
z1("<0.25 0.125> 0 4 2 -2").sync("bar").sound("ST40:25").christmas()
|
||||||
z2("<0.25 0.125> 0 6 4 -4").sync("baz").sound("ST40:25").christmas()
|
z2("<0.25 0.125> 0 6 4 -4").sync("baz").sound("ST40:25").christmas()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
The <ic>listen(name: string)</ic> method can be used to listen for the cue messages and play one event from the pattern for every cue.
|
The <ic>listen(name: string)</ic> method can be used to listen for the cue messages and play one event from the pattern for every cue.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Delayed start using individual cue",
|
"Delayed start using individual cue",
|
||||||
`
|
`
|
||||||
beat(1.0) :: cue("boom")
|
beat(1.0) :: cue("boom")
|
||||||
|
|
||||||
z1("bd <hh ho>").listen("boom")
|
z1("bd <hh ho>").listen("boom")
|
||||||
.sound().out()
|
.sound().out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
## Sync with beat
|
## Sync with beat
|
||||||
@ -65,7 +65,7 @@ beat([2.0,0.5,1.5].bar(1)) ::
|
|||||||
.dur(0.5).out()
|
.dur(0.5).out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Automatic sync for ziffers patterns
|
## Automatic sync for ziffers patterns
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { type Editor } from "../../../main";
|
import { type Editor } from "../../../main";
|
||||||
import { makeExampleFactory } from "../../../Documentation";
|
import { makeExampleFactory } from "../../Documentation";
|
||||||
|
|
||||||
export const ziffers_tonnetz = (application: Editor): string => {
|
export const ziffers_tonnetz = (application: Editor): string => {
|
||||||
const makeExample = makeExampleFactory(application);
|
const makeExample = makeExampleFactory(application);
|
||||||
return `
|
return `
|
||||||
# Tonnetz
|
# Tonnetz
|
||||||
|
|
||||||
The Riemannian Tonnetz is a geometric representation of pitches where we apply mathematical operations to analyze harmonic and melodic relationships in tonal music. Ziffers includes an implementation of live coding Tonnetz developed together with <a href="https://github.com/edelveart/TypeScriptTonnetz" target="_blank">Edgar Delgado Vega</a>. Nevertheless, our implementation allows you to play in different chord complexes and **combine 67 transformations** with **new exploratory notation**. You have at your disposal the sets: traditional PLR, film music, extended PLR* and functions for seventh chords PLRQ, PLRQ*, ST.
|
The Riemannian Tonnetz is a geometric representation of pitches where we apply mathematical operations to analyze harmonic and melodic relationships in tonal music. Ziffers includes an implementation of live coding Tonnetz developed together with <a href="https://github.com/edelveart/TypeScriptTonnetz" target="_blank">Edgar Delgado Vega</a>. Nevertheless, our implementation allows you to play in different chord complexes and **combine 67 transformations** with **new exploratory notation**. You have at your disposal the sets: traditional PLR, film music, extended PLR* and functions for seventh chords PLRQ, PLRQ*, ST.
|
||||||
@ -37,47 +37,47 @@ Indexed transformations <ic>[plrfsntqNSEW][1-9]*</ic>:
|
|||||||
### Examples:
|
### Examples:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Explorative transformations with roman chords",
|
"Explorative transformations with roman chords",
|
||||||
`
|
`
|
||||||
z1('i i7').tonnetz("p1 p2 plr2")
|
z1('i i7').tonnetz("p1 p2 plr2")
|
||||||
.sound('wt_stereo')
|
.sound('wt_stereo')
|
||||||
.adsr(0, .1, 0, 0)
|
.adsr(0, .1, 0, 0)
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Arpeggiated explorative transformations",
|
"Arpeggiated explorative transformations",
|
||||||
`
|
`
|
||||||
z1("i7")
|
z1("i7")
|
||||||
.tonnetz("p l2 r3 rp4l")
|
.tonnetz("p l2 r3 rp4l")
|
||||||
.arpeggio("e _ 0 1 s ^ 0 2 1 3 h _ 012 s ^ 2 1")
|
.arpeggio("e _ 0 1 s ^ 0 2 1 3 h _ 012 s ^ 2 1")
|
||||||
.sound("sine")
|
.sound("sine")
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Arpeggios and note lengths with parameters",
|
"Arpeggios and note lengths with parameters",
|
||||||
`
|
`
|
||||||
z1("024")
|
z1("024")
|
||||||
.tonnetz("p lr rp lrp")
|
.tonnetz("p lr rp lrp")
|
||||||
.arpeggio(0,2,1,2)
|
.arpeggio(0,2,1,2)
|
||||||
.noteLength(1/16,1/8)
|
.noteLength(1/16,1/8)
|
||||||
.sound("sine")
|
.sound("sine")
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Explorative transformations with cardinal directions",
|
"Explorative transformations with cardinal directions",
|
||||||
`
|
`
|
||||||
z1("1/4 i")
|
z1("1/4 i")
|
||||||
.tonnetz("p Np N2p N3p plr N3plr E EE EEE E6 NSE3W2")
|
.tonnetz("p Np N2p N3p plr N3plr E EE EEE E6 NSE3W2")
|
||||||
.sound("sine")
|
.sound("sine")
|
||||||
.out()
|
.out()
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Triad transformations
|
## Triad transformations
|
||||||
|
|
||||||
@ -117,8 +117,8 @@ Therefore, you will see that paying attention to the examples will allow you to
|
|||||||
|
|
||||||
### Examples:
|
### Examples:
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Synthetic 'Morton'",
|
"Synthetic 'Morton'",
|
||||||
`
|
`
|
||||||
z0('h. 0 q _6 h _4 _3 w _2 _0 h. ^0 q 6 h 4 3 3/4 2 5/4 0 w r')
|
z0('h. 0 q _6 h _4 _3 w _2 _0 h. ^0 q 6 h 4 3 3/4 2 5/4 0 w r')
|
||||||
.scale("minor").sound('sawtooth').key("A")
|
.scale("minor").sound('sawtooth').key("A")
|
||||||
.room(0.9).size(9).phaser(0.25).phaserDepth(0.8)
|
.room(0.9).size(9).phaser(0.25).phaserDepth(0.8)
|
||||||
@ -137,8 +137,8 @@ z2('904')
|
|||||||
|
|
||||||
z3('e __ 4 s 0 e 1 2 s')
|
z3('e __ 4 s 0 e 1 2 s')
|
||||||
.sound('hat').delay(0.5).delayfb(0.35).out()`,
|
.sound('hat').delay(0.5).delayfb(0.35).out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Different Tonnetz, Chord Complexes
|
## Different Tonnetz, Chord Complexes
|
||||||
|
|
||||||
@ -204,8 +204,8 @@ So that you can incorporate this new musical machinery into your game, all the p
|
|||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Transform seventh chord from chromatic scale",
|
"Transform seventh chord from chromatic scale",
|
||||||
`
|
`
|
||||||
z1("1.0 047{10}")
|
z1("1.0 047{10}")
|
||||||
.scale('chromatic')
|
.scale('chromatic')
|
||||||
.tetraTonnetz("o p18 q15 l13 n51 p19 q15")
|
.tetraTonnetz("o p18 q15 l13 n51 p19 q15")
|
||||||
@ -214,8 +214,8 @@ z1("1.0 047{10}")
|
|||||||
.adsr(.5,0.05,0.25,0.5)
|
.adsr(.5,0.05,0.25,0.5)
|
||||||
.dur(2.0)
|
.dur(2.0)
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Cyclic methods
|
## Cyclic methods
|
||||||
|
|
||||||
@ -236,8 +236,8 @@ Unlike HexaCycles and OctaCycles, **EnneaCycles** are four-note chord sequences.
|
|||||||
### Examples:
|
### Examples:
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Arpeggio with ennea cycle",
|
"Arpeggio with ennea cycle",
|
||||||
`
|
`
|
||||||
z1("0 2 -1 3")
|
z1("0 2 -1 3")
|
||||||
.enneaCycle()
|
.enneaCycle()
|
||||||
.arpeggio(0,2,1)
|
.arpeggio(0,2,1)
|
||||||
@ -246,20 +246,20 @@ z1("0 2 -1 3")
|
|||||||
.sound("sine")
|
.sound("sine")
|
||||||
.adsr(0.1,0.15,0.25,0.1)
|
.adsr(0.1,0.15,0.25,0.1)
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Variating arpeggios",
|
"Variating arpeggios",
|
||||||
`
|
`
|
||||||
z1("s 0 3 2 1")
|
z1("s 0 3 2 1")
|
||||||
.octaCycle()
|
.octaCycle()
|
||||||
.arpeggio([0,[0,2],[1,0],[0,1,2]].beat(0.15))
|
.arpeggio([0,[0,2],[1,0],[0,1,2]].beat(0.15))
|
||||||
.sound("triangle")
|
.sound("triangle")
|
||||||
.adsr(0.1,0.1,0.13,0.15)
|
.adsr(0.1,0.1,0.13,0.15)
|
||||||
.out()`,
|
.out()`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
## Cycles with vitamins and repetitions
|
## Cycles with vitamins and repetitions
|
||||||
|
|
||||||
@ -278,15 +278,15 @@ As you can verify it manually, you will see that this is not the case. Upon reac
|
|||||||
To play the chords without jumps in our hexaCycle (although the prefix "hexa" would no longer have a precise meaning), we add a number of repetitions.
|
To play the chords without jumps in our hexaCycle (although the prefix "hexa" would no longer have a precise meaning), we add a number of repetitions.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"HexaCycles with vitamins",
|
"HexaCycles with vitamins",
|
||||||
`
|
`
|
||||||
z1("0")
|
z1("0")
|
||||||
.scale("chromatic")
|
.scale("chromatic")
|
||||||
.hexaCycle([2,3,7],4)
|
.hexaCycle([2,3,7],4)
|
||||||
.sound("sine").out()
|
.sound("sine").out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
By default hexaCycles and enneaCycles have <ic>3</ic> repetitions, while octaCycles has <ic>4</ic> repetitions. We have specified a **chromatic scale** although this is the **default scale**. Try changing the **repeats and scales** when playing with different Tonnetz.
|
By default hexaCycles and enneaCycles have <ic>3</ic> repetitions, while octaCycles has <ic>4</ic> repetitions. We have specified a **chromatic scale** although this is the **default scale**. Try changing the **repeats and scales** when playing with different Tonnetz.
|
||||||
|
|
||||||
@ -315,19 +315,19 @@ In addition to the cyclical traversing methods, Ziffers implements traversing me
|
|||||||
As you have noticed, all these graphs usually have many chords, so sometimes it will be convenient to slice up fragments of the cycles. We encourage you to explore these methods and their different parameters. The tonnetz traversing methods can be used in combination with the Ziffers generative methods to sequence, arpeggiate and to randomize the chords in different ways.
|
As you have noticed, all these graphs usually have many chords, so sometimes it will be convenient to slice up fragments of the cycles. We encourage you to explore these methods and their different parameters. The tonnetz traversing methods can be used in combination with the Ziffers generative methods to sequence, arpeggiate and to randomize the chords in different ways.
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Cube Dance swing",
|
"Cube Dance swing",
|
||||||
`
|
`
|
||||||
z1("0").cubeDance([3,4,5])
|
z1("0").cubeDance([3,4,5])
|
||||||
.sound("sine")
|
.sound("sine")
|
||||||
.ad(r(0.1,0.5),0.1)
|
.ad(r(0.1,0.5),0.1)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Selecting subset of chords from the cube dance",
|
"Selecting subset of chords from the cube dance",
|
||||||
`
|
`
|
||||||
z1("1/2 0")
|
z1("1/2 0")
|
||||||
.cubeDance([3,4,5],4)
|
.cubeDance([3,4,5],4)
|
||||||
.at(0,8,2,rI(9,14))
|
.at(0,8,2,rI(9,14))
|
||||||
@ -336,12 +336,12 @@ z1("1/2 0")
|
|||||||
.delay(2)
|
.delay(2)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Power Towers with pulse",
|
"Power Towers with pulse",
|
||||||
`
|
`
|
||||||
z1("1/4 2").powerTowers([2,3,7])
|
z1("1/4 2").powerTowers([2,3,7])
|
||||||
.between(5,11)
|
.between(5,11)
|
||||||
.arpeggio("e 0 3 1 2")
|
.arpeggio("e 0 3 1 2")
|
||||||
@ -349,12 +349,12 @@ z1("1/4 2").powerTowers([2,3,7])
|
|||||||
.adsr(0.01,0.1,0.1,0.9)
|
.adsr(0.01,0.1,0.1,0.9)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true,
|
true,
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Between an OctaTower",
|
"Between an OctaTower",
|
||||||
`
|
`
|
||||||
z1("s. 0")
|
z1("s. 0")
|
||||||
.octaTower()
|
.octaTower()
|
||||||
.between(2,8)
|
.between(2,8)
|
||||||
@ -363,12 +363,12 @@ z1("s. 0")
|
|||||||
.adsr(0.1,0.15,0,0.1)
|
.adsr(0.1,0.15,0,0.1)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Selecting chords from the weitzmann region",
|
"Selecting chords from the weitzmann region",
|
||||||
`
|
`
|
||||||
z1("1/8 0")
|
z1("1/8 0")
|
||||||
.weitzmannRegions()
|
.weitzmannRegions()
|
||||||
.at(1,rI(0,7),4,6)
|
.at(1,rI(0,7),4,6)
|
||||||
@ -377,12 +377,12 @@ z1("1/8 0")
|
|||||||
.ad(0.15,0.15)
|
.ad(0.15,0.15)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
${makeExample(
|
${makeExample(
|
||||||
"Boretz Spider",
|
"Boretz Spider",
|
||||||
`
|
`
|
||||||
z1("1/16 0")
|
z1("1/16 0")
|
||||||
.boretzRegions([1,4,7])
|
.boretzRegions([1,4,7])
|
||||||
.at(2,rI(3,7),4,6)
|
.at(2,rI(3,7),4,6)
|
||||||
@ -391,8 +391,8 @@ z1("1/16 0")
|
|||||||
.adsr(0.1,0.1,0.1,0.2)
|
.adsr(0.1,0.1,0.1,0.2)
|
||||||
.out()
|
.out()
|
||||||
`,
|
`,
|
||||||
true
|
true
|
||||||
)}
|
)}
|
||||||
|
|
||||||
* Remark F: You can find more details about Weitzmann and Boretz regions in chapters 4 and 7 of Richard Cohn's book [Audacious Euphony: Chromatic Harmony and the Triad's Second Nature (2012)](https://books.google.com.pe/books?id=rZxZCMRiO9EC&pg=PA59&hl=es&source=gbs_toc_r&cad=2#v=onepage&q&f=false).
|
* Remark F: You can find more details about Weitzmann and Boretz regions in chapters 4 and 7 of Richard Cohn's book [Audacious Euphony: Chromatic Harmony and the Triad's Second Nature (2012)](https://books.google.com.pe/books?id=rZxZCMRiO9EC&pg=PA59&hl=es&source=gbs_toc_r&cad=2#v=onepage&q&f=false).
|
||||||
|
|
||||||
|
|||||||
12
src/main.ts
12
src/main.ts
@ -13,11 +13,11 @@ import {
|
|||||||
loadUniverserFromUrl,
|
loadUniverserFromUrl,
|
||||||
} from "./FileManagement";
|
} from "./FileManagement";
|
||||||
import { singleElements, buttonGroups, ElementMap, createDocumentationStyle } from "./DomElements";
|
import { singleElements, buttonGroups, ElementMap, createDocumentationStyle } from "./DomElements";
|
||||||
import { registerFillKeys, registerOnKeyDown } from "./KeyActions";
|
import { registerFillKeys, registerOnKeyDown } from "./Keyboard";
|
||||||
import { installEditor } from "./EditorSetup";
|
import { installEditor } from "./EditorSetup";
|
||||||
import { documentation_factory, documentation_pages, showDocumentation, updateDocumentationContent } from "./Documentation";
|
import { documentation_factory, documentation_pages, showDocumentation, updateDocumentationContent } from "./documentation/Documentation";
|
||||||
import { EditorView } from "codemirror";
|
import { EditorView } from "codemirror";
|
||||||
import { Clock } from "./Clock";
|
import { Clock } from "./clock/Clock";
|
||||||
import { loadSamples, UserAPI } from "./API";
|
import { loadSamples, UserAPI } from "./API";
|
||||||
import * as oeis from "jisg";
|
import * as oeis from "jisg";
|
||||||
import * as zpatterns from "zifferjs/src/patterns.ts";
|
import * as zpatterns from "zifferjs/src/patterns.ts";
|
||||||
@ -28,7 +28,7 @@ import { tryEvaluate } from "./Evaluator";
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import showdown from "showdown";
|
import showdown from "showdown";
|
||||||
import { makeStringExtensions } from "./extensions/StringExtensions";
|
import { makeStringExtensions } from "./extensions/StringExtensions";
|
||||||
import { installInterfaceLogic } from "./InterfaceLogic";
|
import { installInterfaceLogic } from "./UILogic";
|
||||||
import { installWindowBehaviors } from "./WindowBehavior";
|
import { installWindowBehaviors } from "./WindowBehavior";
|
||||||
import { makeNumberExtensions } from "./extensions/NumberExtensions";
|
import { makeNumberExtensions } from "./extensions/NumberExtensions";
|
||||||
import colors from "./colors.json";
|
import colors from "./colors.json";
|
||||||
@ -124,7 +124,6 @@ export class Editor {
|
|||||||
this.initializeElements();
|
this.initializeElements();
|
||||||
this.initializeButtonGroups();
|
this.initializeButtonGroups();
|
||||||
this.setCanvas(this.interface.feedback as HTMLCanvasElement);
|
this.setCanvas(this.interface.feedback as HTMLCanvasElement);
|
||||||
this.setCanvas(this.interface.scope as HTMLCanvasElement);
|
|
||||||
this.setCanvas(this.interface.drawings as HTMLCanvasElement);
|
this.setCanvas(this.interface.drawings as HTMLCanvasElement);
|
||||||
try {
|
try {
|
||||||
this.loadHydraSynthAsync();
|
this.loadHydraSynthAsync();
|
||||||
@ -198,7 +197,7 @@ export class Editor {
|
|||||||
// ================================================================================
|
// ================================================================================
|
||||||
|
|
||||||
installEditor(this);
|
installEditor(this);
|
||||||
runOscilloscope(this.interface.scope as HTMLCanvasElement, this);
|
runOscilloscope(this.interface.feedback as HTMLCanvasElement, this);
|
||||||
|
|
||||||
// First evaluation of the init file
|
// First evaluation of the init file
|
||||||
tryEvaluate(this, this.universes[this.selected_universe.toString()].init);
|
tryEvaluate(this, this.universes[this.selected_universe.toString()].init);
|
||||||
@ -581,7 +580,6 @@ export class Editor {
|
|||||||
private setCanvas(canvas: HTMLCanvasElement): void {
|
private setCanvas(canvas: HTMLCanvasElement): void {
|
||||||
/**
|
/**
|
||||||
* Sets the canvas element and configures its size and context.
|
* Sets the canvas element and configures its size and context.
|
||||||
*
|
|
||||||
* @param canvas - The HTMLCanvasElement to set.
|
* @param canvas - The HTMLCanvasElement to set.
|
||||||
*/
|
*/
|
||||||
if (!canvas) return;
|
if (!canvas) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user