First batch of code cleaning
This commit is contained in:
@ -57,7 +57,6 @@ export const singleElements = {
|
||||
hydra_canvas: "hydra-bg",
|
||||
feedback: "feedback",
|
||||
drawings: "drawings",
|
||||
scope: "scope",
|
||||
};
|
||||
|
||||
export const buttonGroups = {
|
||||
|
||||
@ -321,7 +321,7 @@ export const installEditor = (app: Editor) => {
|
||||
),
|
||||
editorSetup,
|
||||
app.themeCompartment.of(
|
||||
getCodeMirrorTheme(app.getColorScheme("Tomorrow Night Burns")),
|
||||
getCodeMirrorTheme(app.getColorScheme("Batman")),
|
||||
// debug
|
||||
),
|
||||
app.chosenLanguage.of(javascript()),
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import type { Editor } from "./main";
|
||||
import type { File } from "./FileManagement";
|
||||
|
||||
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
const codeReplace = (code: string): string => {
|
||||
return code.replace(/->|::/g, "&&");
|
||||
};
|
||||
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
const codeReplace = (code: string): string => code.replace(/->|::/g, "&&");
|
||||
const cache = new Map<string, Function>();
|
||||
const MAX_CACHE_SIZE = 40;
|
||||
|
||||
const tryCatchWrapper = async (
|
||||
application: Editor,
|
||||
code: string,
|
||||
): Promise<boolean> => {
|
||||
async function tryCatchWrapper(application: Editor, code: string): Promise<boolean> {
|
||||
/**
|
||||
* 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.
|
||||
* @returns A promise that resolves to a boolean indicating whether the code executed successfully or not.
|
||||
*/
|
||||
|
||||
try {
|
||||
await new Function(`"use strict"; ${codeReplace(code)}`).call(
|
||||
application.api,
|
||||
);
|
||||
await new Function(`"use strict"; ${codeReplace(code)}`).call(application.api);
|
||||
return true;
|
||||
} catch (error) {
|
||||
application.interface.error_line.innerHTML = error as string;
|
||||
application.api._reportError(error as string);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const cache = new Map<string, Function>();
|
||||
const MAX_CACHE_SIZE = 40;
|
||||
}
|
||||
|
||||
const addFunctionToCache = (code: string, fn: Function) => {
|
||||
/**
|
||||
@ -45,11 +36,8 @@ const addFunctionToCache = (code: string, fn: Function) => {
|
||||
cache.set(code, fn);
|
||||
};
|
||||
|
||||
export const tryEvaluate = async (
|
||||
application: Editor,
|
||||
code: File,
|
||||
timeout = 5000,
|
||||
): Promise<void> => {
|
||||
|
||||
export async function tryEvaluate(application: Editor, code: File, timeout = 5000): Promise<void> {
|
||||
/**
|
||||
* Tries to evaluate the provided code within a specified timeout period.
|
||||
* Increments the evaluation count of the code file.
|
||||
@ -63,39 +51,30 @@ export const tryEvaluate = async (
|
||||
code.evaluations!++;
|
||||
const candidateCode = code.candidate;
|
||||
|
||||
try {
|
||||
const cachedFunction = cache.get(candidateCode);
|
||||
if (cachedFunction) {
|
||||
cachedFunction.call(application.api);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
const wrappedCode = `let i = ${code.evaluations}; ${candidateCode}`;
|
||||
const isCodeValid = await Promise.race([
|
||||
tryCatchWrapper(application, wrappedCode),
|
||||
delay(timeout),
|
||||
delay(timeout)
|
||||
]);
|
||||
|
||||
if (isCodeValid) {
|
||||
code.committed = code.candidate;
|
||||
const newFunction = new Function(
|
||||
`"use strict"; ${codeReplace(wrappedCode)}`,
|
||||
);
|
||||
code.committed = candidateCode;
|
||||
const newFunction = new Function(`"use strict"; ${codeReplace(wrappedCode)}`);
|
||||
addFunctionToCache(candidateCode, newFunction);
|
||||
} else {
|
||||
application.api.logOnce("Compilation error!");
|
||||
await evaluate(application, code, timeout);
|
||||
await delay(100);
|
||||
await tryEvaluate(application, code, timeout);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
application.interface.error_line.innerHTML = error as string;
|
||||
application.api._reportError(error as string);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const evaluate = async (
|
||||
application: Editor,
|
||||
code: File,
|
||||
timeout = 1000,
|
||||
): Promise<void> => {
|
||||
export async function evaluate(application: Editor, code: File, timeout = 1000): Promise<void> {
|
||||
/**
|
||||
* Evaluates the given code using the provided application and timeout.
|
||||
* @param application The editor application.
|
||||
@ -103,18 +82,17 @@ export const evaluate = async (
|
||||
* @param timeout The timeout value in milliseconds (default: 1000).
|
||||
* @returns A Promise that resolves when the evaluation is complete.
|
||||
*/
|
||||
|
||||
try {
|
||||
await Promise.race([
|
||||
tryCatchWrapper(application, code.committed as string),
|
||||
delay(timeout),
|
||||
delay(timeout)
|
||||
]);
|
||||
if (code.evaluations) code.evaluations++;
|
||||
code.evaluations!++;
|
||||
} catch (error) {
|
||||
application.interface.error_line.innerHTML = error as string;
|
||||
console.log(error);
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const evaluateOnce = async (
|
||||
application: Editor,
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
// import { tutorial_universe } from "./universes/tutorial";
|
||||
import { gzipSync, decompressSync, strFromU8 } from "fflate";
|
||||
// import { examples } from "./examples/excerpts";
|
||||
import { type Editor } from "./main";
|
||||
import { uniqueNamesGenerator, colors, animals } from "unique-names-generator";
|
||||
import { tryEvaluate } from "./Evaluator";
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { type Editor } from "./main";
|
||||
import { vim } from "@replit/codemirror-vim";
|
||||
import { tryEvaluate } from "./Evaluator";
|
||||
import { hideDocumentation, showDocumentation } from "./Documentation";
|
||||
import { hideDocumentation, showDocumentation } from "./documentation/Documentation";
|
||||
import { openSettingsModal, openUniverseModal } from "./FileManagement";
|
||||
|
||||
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,
|
||||
showDocumentation,
|
||||
updateDocumentationContent,
|
||||
} from "./Documentation";
|
||||
} from "./documentation/Documentation";
|
||||
import {
|
||||
type Universe,
|
||||
template_universe,
|
||||
@ -1,7 +1,6 @@
|
||||
// @ts-ignore
|
||||
import { TransportNode } from "./TransportNode";
|
||||
import TransportProcessor from "./TransportProcessor?worker&url";
|
||||
import { Editor } from "./main";
|
||||
import { TransportNode } from "./ClockNode";
|
||||
import TransportProcessor from "./ClockProcessor?worker&url";
|
||||
import { Editor } from "../main";
|
||||
|
||||
export interface TimePosition {
|
||||
/**
|
||||
@ -57,7 +56,7 @@ export class Clock {
|
||||
this.logicalTime = 0;
|
||||
this.tick = 0;
|
||||
this._bpm = 120;
|
||||
this._ppqn = 48;
|
||||
this._ppqn = 48 * 2;
|
||||
this.transportNode = null;
|
||||
this.ctx = ctx;
|
||||
this.running = true;
|
||||
@ -189,6 +188,11 @@ export class Clock {
|
||||
}
|
||||
|
||||
public incrementTick(bpm: number) {
|
||||
/**
|
||||
* Increment the clock tick by 1.
|
||||
* @param bpm - The current beats per minute value
|
||||
* @returns void
|
||||
*/
|
||||
this.tick++;
|
||||
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");
|
||||
|
||||
export class TransportNode extends AudioWorkletNode {
|
||||
@ -12,9 +12,9 @@ export class TransportNode extends AudioWorkletNode {
|
||||
|
||||
/** @type {(this: MessagePort, ev: MessageEvent<any>) => any} */
|
||||
handleMessage = (message) => {
|
||||
if(message.data) {
|
||||
if (message.data) {
|
||||
if (message.data.type === "bang") {
|
||||
if(this.app.clock.running) {
|
||||
if (this.app.clock.running) {
|
||||
if (this.app.settings.send_clock) {
|
||||
this.app.api.MidiConnection.sendMidiClock();
|
||||
}
|
||||
@ -60,6 +60,6 @@ export class TransportNode extends AudioWorkletNode {
|
||||
}
|
||||
|
||||
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";
|
||||
// Basics
|
||||
import { introduction } from "./documentation/basics/welcome";
|
||||
import { atelier } from "./documentation/basics/atelier";
|
||||
import { loading_samples } from "./documentation/learning/samples/loading_samples";
|
||||
import { amplitude } from "./documentation/learning/audio_engine/amplitude";
|
||||
import { effects } from "./documentation/learning/audio_engine/effects";
|
||||
import { sampler } from "./documentation/learning/audio_engine/sampler";
|
||||
import { sample_banks } from "./documentation/learning/samples/sample_banks";
|
||||
import { audio_basics } from "./documentation/learning/audio_engine/audio_basics";
|
||||
import { sample_list } from "./documentation/learning/samples/sample_list";
|
||||
import { software_interface } from "./documentation/basics/interface";
|
||||
import { shortcuts } from "./documentation/basics/keyboard";
|
||||
import { code } from "./documentation/basics/code";
|
||||
import { mouse } from "./documentation/basics/mouse";
|
||||
// More
|
||||
import { oscilloscope } from "./documentation/more/oscilloscope";
|
||||
import { synchronisation } from "./documentation/more/synchronisation";
|
||||
import { about } from "./documentation/more/about";
|
||||
import { bonus } from "./documentation/more/bonus";
|
||||
import { visualization } from "./documentation/more/visualization";
|
||||
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";
|
||||
import { Editor } from "../main";
|
||||
import { introduction, atelier, software_interface, shortcuts, code, mouse, interaction } from "./basics";
|
||||
import { amplitude, effects, sampler, synths, filters, audio_basics } from "./learning/audio_engine";
|
||||
import { lfos, functions, generators, variables, probabilities } from './patterns';
|
||||
import { ziffers_basics, ziffers_scales, ziffers_rhythm, ziffers_algorithmic, ziffers_tonnetz, ziffers_syncing } from "./patterns/ziffers";
|
||||
import { loading_samples } from "./learning/samples/loading_samples";
|
||||
import { sample_banks } from "./learning/samples/sample_banks";
|
||||
import { sample_list } from "./learning/samples/sample_list";
|
||||
import { oscilloscope } from "./more/oscilloscope";
|
||||
import { synchronisation } from "./more/synchronisation";
|
||||
import { about } from "./more/about";
|
||||
import { bonus } from "./more/bonus";
|
||||
import { visualization } from "./more/visualization";
|
||||
import { chaining } from "./patterns/chaining";
|
||||
import { time } from "./learning/time/time";
|
||||
import { linear_time } from "./learning/time/linear_time";
|
||||
import { cyclical_time } from "./learning/time/cyclical_time";
|
||||
import { long_forms } from "./learning/time/long_forms";
|
||||
import { midi } from "./learning/midi";
|
||||
import { osc } from "./learning/osc";
|
||||
import { patterns } from "./patterns/patterns";
|
||||
// Setting up the Markdown converter with syntax highlighting
|
||||
import showdown from "showdown";
|
||||
import showdownHighlight from "showdown-highlight";
|
||||
import "highlight.js/styles/atom-one-dark-reasonable.min.css";
|
||||
import { createDocumentationStyle } from "./DomElements";
|
||||
import { filters } from "./documentation/learning/audio_engine/filters";
|
||||
import { createDocumentationStyle } from "../DomElements";
|
||||
showdown.setFlavor("github");
|
||||
|
||||
type StyleBinding = {
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const atelier = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory, key_shortcut } from "../../Documentation";
|
||||
import { makeExampleFactory, key_shortcut } from "../Documentation";
|
||||
|
||||
export const code = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -43,7 +43,7 @@ beat(1) :: snd('bd').out()
|
||||
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"More complex conditions using ?",
|
||||
@ -53,7 +53,7 @@ beat(4) ? snd('kick').out() : beat(2) :: snd('snare').out()
|
||||
// (true) ? log('very true') : log('very false')
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
${makeExample(
|
||||
@ -64,7 +64,7 @@ beat(4) ? snd('kick').out() : beat(2) :: snd('snare').out()
|
||||
!beat(2) :: beat(0.5) :: snd('clap').out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
# About crashes and bugs
|
||||
|
||||
@ -77,7 +77,7 @@ ${makeExample(
|
||||
qjldfqsdklqsjdlkqjsdlqkjdlksjd
|
||||
`,
|
||||
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 { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
// @ts-ignore
|
||||
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 topos_arch from "./topos_arch.svg";
|
||||
import many_universes from "./many_universes.svg";
|
||||
@ -44,7 +44,7 @@ beat(1) :: script(1) // Calling local script n°1
|
||||
flip(4) :: beat(.5) :: script(2) // Calling script n°2
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Script execution can become musical too!",
|
||||
@ -55,7 +55,7 @@ flip(4) :: beat([.5, .25].beat(16)) :: script(
|
||||
[5, 6, 7, 8].beat())
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Navigating the interface
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { key_shortcut } from "../../Documentation";
|
||||
import { key_shortcut } from "../Documentation";
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const shortcuts = (app: Editor): string => {
|
||||
let makeExample = makeExampleFactory(app);
|
||||
@ -74,7 +74,7 @@ ${makeExample(
|
||||
beat(fill() ? 1/4 : 1/2)::sound('cp').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const mouse = (app: Editor): string => {
|
||||
let makeExample = makeExampleFactory(app);
|
||||
@ -28,7 +28,7 @@ beat(.25) :: sound('sine')
|
||||
.room(0.35).size(4).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
<br>
|
||||
|
||||
@ -47,7 +47,7 @@ beat(.25) :: sound('sine')
|
||||
.note(noteX())
|
||||
.room(0.35).size(4).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Mouse and Arrays
|
||||
|
||||
@ -65,7 +65,7 @@ log([4,5,6,7].mouseY())
|
||||
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { makeExampleFactory, key_shortcut } from "../../Documentation";
|
||||
import { makeExampleFactory, key_shortcut } from "../Documentation";
|
||||
import { type Editor } from "../../main";
|
||||
import { examples } from "../../examples/excerpts";
|
||||
import { examples } from "../excerpts";
|
||||
|
||||
export const introduction = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const amplitude = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -21,7 +21,7 @@ ${makeExample(
|
||||
`
|
||||
beat(.5)::snd('cp').vel($(1)%10 / 10).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Amplitude Enveloppe
|
||||
|
||||
@ -52,7 +52,7 @@ beat(.25)::sound('sawtooth')
|
||||
.smooth().out();
|
||||
`,
|
||||
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:
|
||||
|
||||
@ -72,7 +72,7 @@ beat(.25)::sound('sawtooth')
|
||||
.smooth().out();
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const audio_basics = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -23,7 +23,7 @@ beat(1) && sound('bd').out()
|
||||
beat(0.5) && sound('hh').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
These commands, in plain english, can be translated to:
|
||||
|
||||
@ -39,7 +39,7 @@ 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();
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Now, it translates as follows:
|
||||
|
||||
@ -60,7 +60,7 @@ ${makeExample(
|
||||
beat(1)::sound('cp').out(2)
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Try to remove <ic>.out</ic>. You will see that no sound is playing at all!
|
||||
|
||||
@ -78,7 +78,7 @@ beat(1) :: sound('pad').n(1)
|
||||
.velocity(0.25)
|
||||
.pan(usine()).release(2).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Picking a specific sound
|
||||
|
||||
@ -107,7 +107,7 @@ ${makeExample(
|
||||
beat(1) && sound('kick').n([1,2,3,4,5,6,7,8].pick()).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
You can also use the <ic>:</ic> to pick a sample number directly from the <ic>sound</ic> function:
|
||||
|
||||
@ -127,7 +127,7 @@ ${makeExample(
|
||||
// Move your mouse to change the sample being used!
|
||||
beat(.25) && sound('ST09').n(Math.floor(mouseX())).out()`,
|
||||
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.
|
||||
@ -160,7 +160,7 @@ beat(1)::sound('hh').out()
|
||||
beat(2)::sound('cp').orbit(2).room(0.5).size(8).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## The art of chaining
|
||||
|
||||
@ -175,7 +175,7 @@ beat(0.25) && sound('fhh')
|
||||
.cutoff(usine(1/2) * 5000)
|
||||
.out()`,
|
||||
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.
|
||||
`;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const distortion = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -24,7 +24,7 @@ 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()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const effects = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -29,7 +29,7 @@ ${makeExample(
|
||||
beat(2)::snd('cp').room(0.5).size(4).out()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
## Delay
|
||||
|
||||
@ -48,7 +48,7 @@ beat(2)::snd('cp').delay(0.5).delaytime(0.75).delayfb(0.8).out()
|
||||
beat(4)::snd('snare').out()
|
||||
beat(1)::snd('kick').out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Phaser
|
||||
|
||||
@ -69,7 +69,7 @@ rhythm(.5, 7, 8)::sound('wt_stereo')
|
||||
.room(0.5).size(4).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Distorsion, saturation, destruction
|
||||
|
||||
@ -89,7 +89,7 @@ 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()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
## Vibrato
|
||||
|
||||
@ -105,7 +105,7 @@ beat(1) :: sound('triangle')
|
||||
.vibmod([1,2,4,8].beat(2))
|
||||
.out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Compression
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const filters = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -16,7 +16,7 @@ ${makeExample(
|
||||
"Filtering the high frequencies of an oscillator",
|
||||
`beat(.5) :: sound('sawtooth').cutoff(50 + usine(1/8) * 2000).out()`,
|
||||
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:
|
||||
|
||||
@ -32,7 +32,7 @@ ${makeExample(
|
||||
"Filtering a bass",
|
||||
`beat(.5) :: sound('jvbass').lpf([250,1000,8000].beat()).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Highpass filter
|
||||
|
||||
@ -45,7 +45,7 @@ ${makeExample(
|
||||
"Filtering a noise source",
|
||||
`beat(.5) :: sound('gtr').hpf([250,1000, 2000, 3000, 4000].beat()).end(0.5).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Bandpass filter
|
||||
|
||||
@ -58,7 +58,7 @@ ${makeExample(
|
||||
"Sweeping the filter on the same guitar sample",
|
||||
`beat(.5) :: sound('gtr').bandf(100 + usine(1/8) * 4000).end(0.5).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Alternatively, <ic>lpf</ic>, <ic>hpf</ic> and <ic>bpf</ic> can take a second argument, the **resonance**.
|
||||
|
||||
@ -72,7 +72,7 @@ ${makeExample(
|
||||
"Filtering a bass",
|
||||
`beat(.5) :: sound('jvbass').ftype(['12db', '24db'].beat(4)).lpf([250,1000,8000].beat()).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Filter envelopes
|
||||
|
||||
@ -96,7 +96,7 @@ ${makeExample(
|
||||
.cutoff(5000).lpa([0.05, 0.25, 0.5].beat(2))
|
||||
.lpenv(-8).lpq(10).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Highpass envelope
|
||||
|
||||
@ -116,7 +116,7 @@ ${makeExample(
|
||||
.hcutoff(1000).hpa([0.05, 0.25, 0.5].beat(2))
|
||||
.hpenv(8).hpq(10).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Bandpass envelope
|
||||
|
||||
@ -138,7 +138,7 @@ ${makeExample(
|
||||
.bpenv(-4).release(2).out()
|
||||
`,
|
||||
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 { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const sampler = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -39,7 +39,7 @@ beat(.5)::snd('pad').begin(0.2)
|
||||
.clip(1).out()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
|
||||
## Playback speed / pitching samples
|
||||
@ -53,7 +53,7 @@ beat(0.5)::sound('notes')
|
||||
.speed([1,2,3,4].palindrome().beat(0.5)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
It also works by using negative values. It reverses the playback:
|
||||
|
||||
@ -64,7 +64,7 @@ beat(0.5)::sound('notes')
|
||||
.speed(-[1,2,3,4].palindrome().beat(0.5)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Of course you can play melodies using samples:
|
||||
|
||||
@ -77,7 +77,7 @@ beat(0.5)::sound('notes')
|
||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.5)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Panning
|
||||
|
||||
@ -92,7 +92,7 @@ beat(0.25)::sound('notes')
|
||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
## Looping over a sample
|
||||
@ -110,7 +110,7 @@ beat(0.25)::sound('fikea').loop(1)
|
||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Stretching a sample
|
||||
|
||||
@ -123,7 +123,7 @@ ${makeExample(
|
||||
beat(4) :: sound('amen1').n(11).stretch(4).out()
|
||||
beat(1) :: sound('kick').shape(0.35).out()`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
## Cutting samples
|
||||
|
||||
@ -140,7 +140,7 @@ beat(0.25)::sound('notes')
|
||||
.note([0, 2, 3, 4, 5].scale('minor', 50).beat(0.25)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
You can also use <ic>clip</ic> to cut the sample everytime a new sample comes in:
|
||||
|
||||
@ -155,7 +155,7 @@ beat(0.125)::sound('notes')
|
||||
+ [-12,12].beat()).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Adding vibrato to samples
|
||||
|
||||
@ -168,7 +168,7 @@ ${makeExample(
|
||||
beat(1)::sound('fhang').vib([1, 2, 4].bar()).vibmod([0.5, 2].beat()).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
`;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const synths = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory, key_shortcut } from "../../Documentation";
|
||||
import { makeExampleFactory, key_shortcut } from "../Documentation";
|
||||
|
||||
export const midi = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -27,7 +27,7 @@ ${makeExample(
|
||||
midi_outputs()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>midi_output(output_name: string)</ic>: enter your desired output to connect to it.
|
||||
|
||||
@ -37,7 +37,7 @@ ${makeExample(
|
||||
midi_output("MIDI Rocket-Trumpet")
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
That's it! You are now ready to play with MIDI.
|
||||
|
||||
@ -55,7 +55,7 @@ ${makeExample(
|
||||
rhythm(.5, 5, 8) :: midi(50).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"MIDI note using three parameters: note, velocity, channel",
|
||||
@ -64,7 +64,7 @@ ${makeExample(
|
||||
rhythm(.5, 5, 8) :: midi(50, 50 + usine(.5) * 20, 0).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"MIDI note by passing an object",
|
||||
@ -73,7 +73,7 @@ ${makeExample(
|
||||
rhythm(.5, 5, 8) :: midi({note: 50, velocity: 50 + usine(.5) * 20, channel: 0}).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
We can now have some fun and starting playing a small piano piece:
|
||||
|
||||
@ -87,7 +87,7 @@ beat(.75) && midi([64, 67, 69].beat()).sustain(0.05).out()
|
||||
beat(.25) && midi([64, 67, 69].beat() + 24).sustain(0.05).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Control and Program Changes
|
||||
|
||||
@ -100,7 +100,7 @@ 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})
|
||||
`,
|
||||
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>).
|
||||
|
||||
@ -110,7 +110,7 @@ ${makeExample(
|
||||
program_change([1,2,3,4,5,6,7,8].pick(), 1)
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
## System Exclusive Messages
|
||||
@ -124,7 +124,7 @@ ${makeExample(
|
||||
sysex(0x90, 0x40, 0x7f)
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Clock
|
||||
|
||||
@ -136,7 +136,7 @@ ${makeExample(
|
||||
beat(.25) && midi_clock() // Sending clock to MIDI device from the global buffer
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Using midi with ziffers
|
||||
|
||||
@ -148,7 +148,7 @@ ${makeExample(
|
||||
z1('0 2 e 5 2 q 4 2').midi().port(2).channel(4).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Setting the channel within the pattern",
|
||||
@ -156,7 +156,7 @@ ${makeExample(
|
||||
z1('(0 2 e 5 2):0 (4 2):1').midi().out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const osc = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -31,7 +31,7 @@ beat(1)::getOsc()
|
||||
// 1 : {data: Array(2), address: '/lala'}
|
||||
// 2 : {data: Array(2), address: '/lala'}`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Filtered messages
|
||||
|
||||
@ -46,7 +46,7 @@ beat(1)::getOsc("/lala")
|
||||
// 2 : (2) [82, 'bob']
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Output
|
||||
|
||||
@ -58,7 +58,7 @@ ${makeExample(
|
||||
beat(1)::sound('cp').speed(2).vel(0.5).osc()
|
||||
`,
|
||||
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:
|
||||
|
||||
@ -69,7 +69,7 @@ ${makeExample(
|
||||
osc('/my/osc/address', 5000, 1, 2, 3)
|
||||
`,
|
||||
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 { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const loading_samples = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -19,7 +19,7 @@ ${makeExample(
|
||||
hh: ['hh27/000_hh27closedhh.wav','hh/000_hh3closedhh.wav'],
|
||||
}, 'github:tidalcycles/Dirt-Samples/master/');`,
|
||||
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:
|
||||
|
||||
@ -28,7 +28,7 @@ ${makeExample(
|
||||
`rhythm(.5, 5, 8)::sound('bd').n(ir(1,2)).end(1).out()
|
||||
`,
|
||||
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:
|
||||
|
||||
@ -41,7 +41,7 @@ samples("github:Bubobubobubobubo/Dough-Samples/main");
|
||||
samples("github:Bubobubobubobubo/Dough-Amiga/main");
|
||||
`,
|
||||
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!
|
||||
|
||||
@ -59,7 +59,7 @@ samples("shabda:ocean")
|
||||
beat(1)::sound('ocean').clip(1).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
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 { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const sample_banks = (application: Editor): string => {
|
||||
// @ts-ignore
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const samples_to_markdown = (
|
||||
application: Editor,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const cyclical_time = (app: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -22,7 +22,7 @@ ${makeExample(
|
||||
beat([1,1/2,1/4,1/8].beat(2)) :: sound('hat').n(0).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Some sort of ringtone",
|
||||
@ -42,7 +42,7 @@ flip(3) :: beat(1/6) :: blip(800).pan(r(0,1)).out();
|
||||
beat([1,0.75].beat(2)) :: blip([50, 100].beat(2)).pan(r(0,1)).out();
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Beat can match multiple values",
|
||||
@ -50,7 +50,7 @@ ${makeExample(
|
||||
beat([.5, 1.25])::sound('hat').out()
|
||||
`,
|
||||
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>number</ic>: if <ic>number = 1</ic>, the function will return <ic>true</ic> every pulse. Lists can be used too.
|
||||
@ -64,7 +64,7 @@ pulse([24, 16])::sound('hat').ad(0, .02).out()
|
||||
pulse([48, [36,24].dur(4, 1)])::sound('fhardkick').ad(0, .1).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"pulse is the OG rhythmic function in Topos",
|
||||
`
|
||||
@ -72,7 +72,7 @@ pulse([48, 24, 16].beat(4)) :: sound('linnhats').out()
|
||||
beat(1)::snd(['bd', '808oh'].beat(1)).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
- <ic>bar(n: number | number[] = 1, offset: number = 1)</ic>: return true every _n_ bars.
|
||||
@ -86,7 +86,7 @@ bar(1)::sound('kick').out()
|
||||
beat(1)::sound('hat').speed(2).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
${makeExample(
|
||||
@ -98,7 +98,7 @@ beat(1, 0.5)::sound('hat').speed(4).out()
|
||||
bar(1, 0.5)::sound('sn').out()
|
||||
`,
|
||||
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.
|
||||
|
||||
@ -110,7 +110,7 @@ onbeat(2,4)::snd('snare').n([8,4].beat(4)).out() // Snare on acccentuated beats
|
||||
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## XOX Style sequencers
|
||||
|
||||
@ -126,7 +126,7 @@ seq('ooxo')::sound('fsoftsnare').out()
|
||||
seq('xoxo', 0.25)::sound('fhh').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Another sequence using more complex parameters",
|
||||
@ -136,7 +136,7 @@ seq('ooxo', [1, 2].bar())::sound('fsoftsnare').speed(0.5).out()
|
||||
seq(['xoxoxoxx', 'xxoo'].bar())::sound('fhh').out()
|
||||
`,
|
||||
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>expr: string</ic>: any string composed of <ic>x</ic> or <ic>o</ic> like so: <ic>"xooxoxxoxoo"</ic>.
|
||||
@ -160,7 +160,7 @@ function complexPat() {
|
||||
fullseq('xooxooxx', 4) ? simplePat() : complexPat()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
|
||||
@ -182,7 +182,7 @@ rhythm(.5, 7, 8)::sound('sine')
|
||||
rhythm(.5, 3, 8)::sound('sine').freq(500).ad(0, .5).out()
|
||||
`,
|
||||
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.
|
||||
@ -195,7 +195,7 @@ ${makeExample(
|
||||
oneuclid(7,16) :: snd('east').end(0.5).n(irand(3,5)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>bin(iterator: number, n: number): boolean</ic>: a binary rhythm generator. It transforms the given number into its binary representation (_e.g_ <ic>34</ic> becomes <ic>100010</ic>). It then returns a boolean value based on the iterator in order to generate a rhythm.
|
||||
- <ic>binrhythm(divisor: number, n: number): boolean: boolean</ic>: iterator-less version of the binary rhythm generator.
|
||||
@ -208,7 +208,7 @@ beat(.5) && bin($(1), 12) && snd('kick').n([4,9].beat(1.5)).out()
|
||||
beat(.5) && bin($(2), 34) && snd('snare').n([3,5].beat(1)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"binrhythm for fast cool binary rhythms!",
|
||||
@ -222,7 +222,7 @@ binrhythm([.5, .25].beat(1), 30) && snd('wt_granular').n(a)
|
||||
.room(1).size(1).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Submarine jungle music",
|
||||
@ -234,7 +234,7 @@ beat(.5) && bin($(1), 911) && snd('ST69').n([2,3,4].beat())
|
||||
beat(.5) && sound('amencutup').n(irand(2,7)).shape(0.3).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
If you don't find it spicy enough, you can add some more probabilities to your rhythms by taking advantage of the probability functions. See the functions documentation page to learn more about them.
|
||||
|
||||
@ -248,7 +248,7 @@ prob(60)::beat(.5) && euclid($(2), 3, 8) && snd('mash')
|
||||
prob(80)::beat(.5) && sound(['hh', 'hat'].pick()).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import pulses from "./pulses.svg";
|
||||
|
||||
export const linear_time = (app: Editor): string => {
|
||||
@ -27,7 +27,7 @@ ${makeExample(
|
||||
log(\`\$\{cbar()}\, \$\{cbeat()\}, \$\{cpulse()\}\`)
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### BPM and PPQN
|
||||
|
||||
@ -84,7 +84,7 @@ if((cbar() % 4) > 1) {
|
||||
beat([.5, .5, 1, .25].beat(0.5)) :: sound('shaker').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Time Warping
|
||||
|
||||
@ -109,7 +109,7 @@ flip(3) :: beat([.25,.5].beat(.5)) :: sound('dr')
|
||||
beat(.25) :: warp([12, 48, 24, 1, 120, 30].pick())
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>beat_warp(beat: number)</ic>: this function jumps to the _n_ beat of the clock. The first beat is <ic>1</ic>.
|
||||
|
||||
@ -131,7 +131,7 @@ beat(.5) :: snd('arpy').note(
|
||||
beat(1) :: beat_warp([2,4,5,10,11].pick())
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Transport-based rhythm generators
|
||||
|
||||
@ -145,7 +145,7 @@ onbeat(2,4)::snd('snare').n([8,4].beat(4)).out() // Snare on acccentuated beats
|
||||
onbeat(1.5,2.5,3.5, 3.75)::snd('hat').gain(r(0.9,1.1)).out() // Cool high-hats
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Let's do something more complex",
|
||||
@ -157,7 +157,7 @@ beat([.25, 1/8].beat(1.5))::snd('hat').n(2)
|
||||
.pan(usine()).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>oncount(beats: number[], meter: number)</ic>: This function is similar to <ic>onbeat</ic> but it allows you to specify a custom number of beats as the last argument.
|
||||
|
||||
@ -172,7 +172,7 @@ onbeat(1,1.5,2,3,4) :: sound('bd').gain(2.0).out()
|
||||
oncount([1,3,5.5,7,7.5,8],8) :: sound('hh').gain(irand(1.0,4.0)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Using oncount to create rhythms with a custom meter",
|
||||
@ -184,7 +184,7 @@ oncount([2, 3, 3.5, 6, 7, 10, 15],16) :: sound('hh').n(8).gain(0.8).out()
|
||||
oncount([1, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16],16) :: sound('hh').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const long_forms = (app: Editor): string => {
|
||||
// @ts-ignore
|
||||
@ -20,7 +20,7 @@ ${makeExample(
|
||||
script([1,2,3,4].bar(8))
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
You can also give a specific duration to each section using <ic>.dur</ic>:
|
||||
|
||||
@ -30,7 +30,7 @@ ${makeExample(
|
||||
script([1,2,3,4].dur(8, 2, 16, 4))
|
||||
`,
|
||||
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_.
|
||||
|
||||
@ -45,7 +45,7 @@ ${makeExample(
|
||||
flip(4) :: beat(1) :: snd('kick').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Clapping on the edge",
|
||||
@ -57,7 +57,7 @@ flip(2.5) :: beat(.5) :: snd('bd').out()
|
||||
beat(.25) :: sound('hat').end(0.1).cutoff(1200).pan(usine(1/4)).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Good old true and false",
|
||||
@ -69,7 +69,7 @@ if (flip(4, 75)) {
|
||||
}
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
<ic>flip</ic> is extremely powerful and is used internally for a lot of other Topos functions. You can also use it to think about **longer durations** spanning over multiple bars. Here is a silly composition that is using <ic>flip</ic> to generate a 4 bars long pattern.
|
||||
|
||||
@ -94,7 +94,7 @@ if (flip(8)) {
|
||||
}
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
You can use it everywhere to spice things up, including as a method parameter picker:
|
||||
|
||||
@ -104,7 +104,7 @@ ${makeExample(
|
||||
beat(.5)::snd(flip(2) ? 'kick' : 'hat').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>flipbar(n: number = 1)</ic>: this method works just like <ic>flip</ic> but counts in bars instead of beats. It allows you to think about even larger time cycles. You can also pair it with regular <ic>flip</ic> for writing complex and long-spanning algorithmic beats.
|
||||
|
||||
@ -123,7 +123,7 @@ flipbar(2) && a()
|
||||
flipbar(3) && b()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"Alternating over four bars",
|
||||
`
|
||||
@ -132,7 +132,7 @@ flipbar(2)
|
||||
: beat(.5) && snd(['east', 'east:2'].beat(1)).out()
|
||||
`,
|
||||
false,
|
||||
)};
|
||||
)};
|
||||
|
||||
|
||||
- <ic>onbar(bars: number | number[], n: number)</ic>: The second argument, <ic>n</ic>, is used to divide the time in a period of <ic>n</ic> consecutive bars. The first argument should be a bar number or a list of bar numbers to play on. For example, <ic>onbar([1, 4], 5)</ic> will return <ic>true</ic> on bar <ic>1</ic> and <ic>4</ic> but return <ic>false</ic> the rest of the time. You can easily divide time that way.
|
||||
@ -156,7 +156,7 @@ if (onbar([1,2], 4)) {
|
||||
rhythm(.5, 2, 7) :: snd('snare').n(3).out();
|
||||
}`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { type Editor } from "../../../main";
|
||||
import times from "./times.svg";
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { key_shortcut, makeExampleFactory } from "../../Documentation";
|
||||
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const bonus = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -39,7 +39,7 @@ ${makeExample(
|
||||
"Hydra integration",
|
||||
`beat(4) :: hydra.osc(3, 0.5, 2).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Close the documentation to see the effect: ${key_shortcut(
|
||||
"Ctrl+D",
|
||||
@ -56,7 +56,7 @@ beat(4) :: stop_hydra() // this one
|
||||
beat(4) :: hydra.hush() // or this one
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
### Changing the resolution
|
||||
@ -67,7 +67,7 @@ ${makeExample(
|
||||
"Changing Hydra resolution",
|
||||
`hydra.setResolution(1024, 768)`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Documentation
|
||||
|
||||
@ -101,6 +101,6 @@ beat(0.25)::gif({
|
||||
posY: ir(1, 800), // CSS Vertical Position
|
||||
`,
|
||||
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 { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const oscilloscope = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -15,7 +15,7 @@ ${makeExample(
|
||||
beat(1)::sound('sine').freq(200).ad(0, .2).scope().out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Here is a layout of the scope configuration options:
|
||||
|
||||
@ -36,7 +36,7 @@ scope({
|
||||
})
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Demo with multiple scope mode",
|
||||
@ -57,7 +57,7 @@ scope({enabled: true, thickness: 8,
|
||||
size: 0.5, fftSize: 2048})
|
||||
`,
|
||||
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 :)
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const synchronisation = (app: Editor): string => {
|
||||
// @ts-ignore
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { key_shortcut, makeExampleFactory } from "../../Documentation";
|
||||
import { key_shortcut, makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const visualization = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -21,7 +21,7 @@ ${makeExample(
|
||||
"Hydra integration",
|
||||
`beat(4) :: hydra.osc(3, 0.5, 2).out()`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
Close the documentation to see the effect: ${key_shortcut(
|
||||
"Ctrl+D",
|
||||
@ -38,7 +38,7 @@ beat(4) :: stop_hydra() // this one
|
||||
beat(4) :: hydra.hush() // or this one
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Changing the resolution
|
||||
|
||||
@ -48,7 +48,7 @@ ${makeExample(
|
||||
"Changing Hydra resolution",
|
||||
`hydra.setResolution(1024, 768)`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
### Hydra documentation
|
||||
|
||||
@ -82,7 +82,7 @@ beat(0.25)::gif({
|
||||
posY: ir(1, 800), // CSS Vertical Position
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Canvas live coding
|
||||
|
||||
@ -118,29 +118,29 @@ beat(0.5) && clear() && draw(context => {
|
||||
})
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${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 => {
|
||||
donut(x.pitch)
|
||||
}).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
false,
|
||||
)}
|
||||
|
||||
|
||||
${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()
|
||||
.draw(x => {
|
||||
pie({slices:7,eaten:(7-x.pitch-1),fillStyle:"green", rotate: 250})
|
||||
}).log("pitch").out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
false,
|
||||
)}
|
||||
|
||||
* <ic<image(url, x, y, width, height, rotation)</ic> - Draws an image to a canvas.
|
||||
|
||||
@ -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.
|
||||
|
||||
${makeExample(
|
||||
"Writing to canvas",
|
||||
`
|
||||
"Writing to canvas",
|
||||
`
|
||||
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.
|
||||
|
||||
${makeExample(
|
||||
"Drawing random characters to canvas",
|
||||
`
|
||||
"Drawing random characters to canvas",
|
||||
`
|
||||
beat(0.5) && clear() && drawText(randomChar(10,1000,2000),30)
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
false,
|
||||
)}
|
||||
|
||||
* <ic>emoji(size)</ic> - Returns a random emojis as text.
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
import { type Editor } from "../../main";
|
||||
|
||||
export const chaining = (application: Editor): string => {
|
||||
@ -14,7 +14,7 @@ ${makeExample(
|
||||
beat(1)::sound('bd').speed(2).lpf(500).out()
|
||||
`,
|
||||
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!
|
||||
|
||||
@ -32,7 +32,7 @@ register('juxrev', n=>n.pan([0, 1]).speed([1, -1]))
|
||||
beat(1)::sound('fhh').juxrev().out()
|
||||
`,
|
||||
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:
|
||||
|
||||
@ -52,15 +52,15 @@ rhythm(.25, [6, 8].beat(), 12)::sound('sine')
|
||||
.note([0, 2, 4, 5].scale('minor', 50).beat(0.5))
|
||||
.sub(8).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## 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.
|
||||
|
||||
${makeExample(
|
||||
"Registering chain to all events at once",
|
||||
`
|
||||
"Registering chain to all events at once",
|
||||
`
|
||||
z0("h 9 ^ <7 5 3 1>")
|
||||
.sound("sine")
|
||||
.out()
|
||||
@ -71,8 +71,8 @@ z1("0 4 3 2")
|
||||
|
||||
all(x=>x.room(1).delay(rI(0,0.5)))
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
true,
|
||||
)}
|
||||
|
||||
## Logging values from the chain
|
||||
|
||||
@ -84,7 +84,7 @@ ${makeExample(
|
||||
beat(1) :: sound("sine").pitch(rI(1,6)).log("note").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Logging values from ziffers pattern",
|
||||
@ -92,7 +92,7 @@ ${makeExample(
|
||||
z1("0 3 2 5").scale("rocritonic").sound("sine").log("pitch","note","key").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Conditional chaining
|
||||
|
||||
@ -108,7 +108,7 @@ beat(.5) && sound('fhh')
|
||||
.rarely(s => s.room(0.5).size(8).speed(0.5))
|
||||
.out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"Chance to play a random note",
|
||||
`
|
||||
@ -120,7 +120,7 @@ beat(.5) && sound('pluck').note(60)
|
||||
.room(0.5).size(3)
|
||||
.out()`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
There is a growing collection of probability and chance methods you can use:
|
||||
|
||||
@ -152,7 +152,7 @@ ${makeExample(
|
||||
.sometimes(s => s.velocity(irand(50,100)))
|
||||
.out()`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
## Ziffers
|
||||
|
||||
@ -175,6 +175,6 @@ z1('s 0 5 7 0 3 7 0 2 7 0 1 7 0 1 6 5 4 3 2')
|
||||
.room(0.5).size(0.5).out()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const functions = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -20,7 +20,7 @@ ${makeExample(
|
||||
beat(1) :: script(1)
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Calling mutliple scripts at the same time.",
|
||||
@ -28,7 +28,7 @@ ${makeExample(
|
||||
beat(1) :: script(1, 3, 5)
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Math functions
|
||||
|
||||
@ -52,7 +52,7 @@ ${makeExample(
|
||||
"Scaling an LFO",
|
||||
`usine(1/2).linlin(0, 1, 0, 100)`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ beat(.5) :: delay(usine(.125) * 80, () => sound('east').out())
|
||||
beat(.5) :: delay(50, () => sound('east').out())
|
||||
`,
|
||||
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.
|
||||
|
||||
@ -79,6 +79,6 @@ beat(1) :: delayr(50, 4, () => sound('east').speed([0.5,.25].beat()).out())
|
||||
flip(2) :: beat(2) :: delayr(150, 4, () => sound('east').speed([0.5,.25].beat() * 4).out())
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const generators = (application: Editor): string => {
|
||||
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.
|
||||
|
||||
${makeExample(
|
||||
"Simple looping generator function",
|
||||
`
|
||||
"Simple looping generator function",
|
||||
`
|
||||
function* simple() {
|
||||
let x = 0;
|
||||
while (x < 12) {
|
||||
@ -27,12 +27,12 @@ function* simple() {
|
||||
|
||||
beat(.25) && sound("triangle").pitch(cache("simple",simple())).scale("minor").out()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
true,
|
||||
)};
|
||||
|
||||
${makeExample(
|
||||
"Infinite frequency generator",
|
||||
`
|
||||
"Infinite frequency generator",
|
||||
`
|
||||
function* poly(x=0) {
|
||||
while (true) {
|
||||
const s = Math.tan(x/10)+Math.sin(x/20);
|
||||
@ -43,8 +43,8 @@ ${makeExample(
|
||||
|
||||
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:
|
||||
|
||||
@ -72,7 +72,7 @@ ${makeExample(
|
||||
.log("freq").out()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
${makeExample(
|
||||
"Henon and his discrete music",
|
||||
@ -123,7 +123,7 @@ ${makeExample(
|
||||
.log("freq").out()
|
||||
`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
|
||||
## OEIS integer sequences
|
||||
@ -153,7 +153,7 @@ Alternatively generators can be used with Ziffers to generate longer patterns. I
|
||||
|
||||
${makeExample(
|
||||
"Ziffers patterns using a generator functions",
|
||||
`
|
||||
`
|
||||
function* poly(x) {
|
||||
while (true) {
|
||||
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 { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const lfos = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -17,7 +17,7 @@ ${makeExample(
|
||||
"Modulating the speed of a sample player using a sine LFO",
|
||||
`beat(.25) && snd('cp').speed(1 + usine(0.25) * 2).out()`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
- <ic>triangle(freq: number = 1, 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_.
|
||||
@ -26,7 +26,7 @@ ${makeExample(
|
||||
"Modulating the speed of a sample player using a triangle LFO",
|
||||
`beat(.25) && snd('cp').speed(1 + utriangle(0.25) * 2).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>saw(freq: number = 1, 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_.
|
||||
@ -35,7 +35,7 @@ ${makeExample(
|
||||
"Modulating the speed of a sample player using a saw LFO",
|
||||
`beat(.25) && snd('cp').speed(1 + usaw(0.25) * 2).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>square(freq: number = 1, 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.
|
||||
@ -44,7 +44,7 @@ ${makeExample(
|
||||
"Modulating the speed of a sample player using a square LFO",
|
||||
`beat(.25) && snd('cp').speed(1 + usquare(0.25, 0, 0.25) * 2).out()`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
- <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.
|
||||
@ -53,7 +53,7 @@ ${makeExample(
|
||||
"Modulating the speed of a sample player using noise",
|
||||
`beat(.25) && snd('cp').speed(1 + noise() * 2).out()`,
|
||||
true,
|
||||
)};
|
||||
)};
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const patterns = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -15,7 +15,7 @@ ${makeExample(
|
||||
beat(1)::sound('kick').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
can be turned into something more interesting like this easily:
|
||||
|
||||
@ -27,7 +27,7 @@ beat([1, 0.5, 0.25].dur(0.75, 0.25, 1) / c)::sound(['kick', 'fsoftsnare'].beat(0
|
||||
.ad(0, .25).shape(usine(1/2)*0.5).speed([1, 2, 4].beat(0.5)).out()
|
||||
`,
|
||||
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>.
|
||||
@ -45,7 +45,7 @@ beat([0.5, 1].beat(4)) :: sound('kick').out()
|
||||
beat(2)::snd('snare').shape(.5).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"Using beat to create arpeggios",
|
||||
`
|
||||
@ -63,7 +63,7 @@ beat([.5, .25].beat(0.5)) :: sound('sine')
|
||||
.out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
${makeExample(
|
||||
"Cool ambiance",
|
||||
`
|
||||
@ -74,7 +74,7 @@ flip(4)::beat(2)::snd('pad').n(2).shape(.5)
|
||||
.orbit(2).room(0.9).size(0.9).release(0.5).out()
|
||||
`,
|
||||
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.
|
||||
|
||||
@ -89,7 +89,7 @@ beat([1/4, 1/2].dur(1.5, 0.5))::sound(['jvbass', 'fikea'].bar())
|
||||
.out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Using beat and bar in the same example",
|
||||
@ -102,7 +102,7 @@ beat([1, 0.5].beat()) :: sound(['bass3'].bar())
|
||||
.speed([1,2,3].beat())
|
||||
.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.
|
||||
|
||||
@ -118,7 +118,7 @@ beat(1)::sound(['kick', 'fsnare'].dur(3, 1))
|
||||
.n([0,3].dur(3, 1)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Patterning with ternary statements",
|
||||
@ -137,7 +137,7 @@ 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()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Iteration using a counter
|
||||
|
||||
@ -150,7 +150,7 @@ ${makeExample(
|
||||
beat(0.5) :: sound("bd").gain(line(0,1,0.01).$("ramp")).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Manipulating notes and scales
|
||||
|
||||
@ -165,7 +165,7 @@ beat(0.25) :: snd('sine')
|
||||
.scale("minor").ad(0, .25).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>semitones(number[], ...args?)</ic>: Create scale from semitone intervals.
|
||||
|
||||
@ -176,7 +176,7 @@ ${makeExample(
|
||||
.semitones(1, 1, 3, 1, 1, 2, 3).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>cents(number[], ...args?)</ic>: Create scale from cent intervals.
|
||||
|
||||
@ -188,7 +188,7 @@ ${makeExample(
|
||||
.cents(120,270,540,670,785,950,1215).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>ratios(number[], ...args?)</ic>: Create scale from ratios.
|
||||
|
||||
@ -200,7 +200,7 @@ ${makeExample(
|
||||
.ratios(2/11,4/11,6/11,8/11,10/11,11/11).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>edo(number, scale?: string|number[])</ic>: Create scale from equal divisions of the octave. Creates chromatic scale by default.
|
||||
|
||||
@ -219,7 +219,7 @@ rhythm(2.0,26,32) :: sound("ST20").n([22,5,24,34,31,5,11,19].pick()).stretch(rI(
|
||||
.out()
|
||||
`,
|
||||
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/).
|
||||
@ -232,7 +232,7 @@ beat(1) :: snd('gtr')
|
||||
.out()
|
||||
`,
|
||||
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>.
|
||||
|
||||
@ -244,7 +244,7 @@ beat(1) :: snd('gtr')
|
||||
.out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Iteration using the mouse
|
||||
|
||||
@ -260,7 +260,7 @@ beat(0.25)::sound('wt_piano')
|
||||
.ad(0, .2).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Simple data operations
|
||||
|
||||
@ -278,7 +278,7 @@ beat([1,.5,.25].beat()) :: snd('wt_stereo')
|
||||
.lpad(4, 0, .25).sustain(0.125).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>random(index: number)</ic>: pick a random element in the given list.
|
||||
- <ic>rand(index: number)</ic>: shorter alias for the same method.
|
||||
@ -297,7 +297,7 @@ beat([.5, 1].rand() / 2) :: snd(
|
||||
.end(0.5).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>pick()</ic>: pick a random element in the list.
|
||||
|
||||
@ -309,7 +309,7 @@ beat(0.25)::sound(['ftabla', 'fwood'].pick())
|
||||
.room(0.5).size(1).out()
|
||||
`,
|
||||
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.
|
||||
|
||||
@ -320,7 +320,7 @@ ${makeExample(
|
||||
beat(.25)::snd('amencutup').n([1,2,3,4,5,6,7,8,9].degrade(20).loop($(1))).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <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.
|
||||
@ -332,7 +332,7 @@ ${makeExample(
|
||||
beat(.25)::sound('amencutup').n([1,2,3,4,5,6,7,8].repeat(4).beat(.25)).out()
|
||||
`,
|
||||
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>.
|
||||
|
||||
@ -342,7 +342,7 @@ ${makeExample(
|
||||
beat(1) :: sound('numbers').n([1,2,3,4,5].loop($(3, 10, 2))).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>shuffle(): this</ic>: shuffles a list! Simple enough!
|
||||
|
||||
@ -352,7 +352,7 @@ ${makeExample(
|
||||
beat(1) :: sound('numbers').n([1,2,3,4,5].shuffle().loop($(1)).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
- <ic>rotate(steps: number)</ic>: rotate a list to the right _n_ times. The last value become the first, rinse and repeat.
|
||||
|
||||
@ -370,7 +370,7 @@ beat(.25) :: snd('sine').fmi([1.99, 2])
|
||||
.out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Filtering
|
||||
|
||||
@ -383,7 +383,7 @@ ${makeExample(
|
||||
beat(1)::snd('sine').sustain(0.1).freq([100,100,100,100,200].unique().beat()).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Simple math operations
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const probabilities = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -18,7 +18,7 @@ ${makeExample(
|
||||
rhythm(0.125, 10, 16) :: sound('sid').n(4).note(50 + irand(50, 62) % 8).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
|
||||
- <ic>prob(p: number)</ic>: return <ic>true</ic> _p_% of time, <ic>false</ic> in other cases.
|
||||
@ -33,7 +33,7 @@ prob(60) :: script(2);
|
||||
prob(80) :: script(toss() ? script(3) : script(4))
|
||||
`,
|
||||
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.
|
||||
|
||||
@ -66,7 +66,7 @@ ${makeExample(
|
||||
rarely(8) :: sound('east').out(); // Rarely in 8 beats is even less
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Using chance with other operators",
|
||||
@ -76,7 +76,7 @@ ${makeExample(
|
||||
sometimes() :: onbeat(1,3) :: sound('snare').out();
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Using chance with chaining",
|
||||
@ -93,6 +93,6 @@ ${makeExample(
|
||||
.out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../main";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
import { makeExampleFactory } from "../Documentation";
|
||||
|
||||
export const variables = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -18,7 +18,7 @@ ${makeExample(
|
||||
global.my_variable = 2
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Getting that variable back and printing!",
|
||||
@ -27,7 +27,7 @@ ${makeExample(
|
||||
log(global.my_variable)
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
Now your scripts can share information with each other!
|
||||
|
||||
@ -52,7 +52,7 @@ ${makeExample(
|
||||
rhythm(.25, 6, 8) :: sound('dr').n($(1)).end(.25).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Using a more complex counter",
|
||||
@ -61,7 +61,7 @@ ${makeExample(
|
||||
rhythm(.25, 6, 8) :: sound('dr').n($(1, 20, 5)).end(.25).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Calling the drunk mechanism",
|
||||
@ -70,7 +70,7 @@ ${makeExample(
|
||||
rhythm(.25, 6, 8) :: sound('dr').n(drunk()).end(.25).out()
|
||||
`,
|
||||
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 { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const ziffers_algorithmic = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const ziffers_basics = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -30,7 +30,7 @@ z3('can can:2').sound().gain(1).cutoff(osci).out()
|
||||
z4('1/4 kick kick snare kick').sound().gain(1).cutoff(osci).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Evaluation
|
||||
|
||||
@ -63,7 +63,7 @@ ${makeExample(
|
||||
z1('0.25 0 1 2 3 4 5 6 7 8 9').sound('wt_stereo')
|
||||
.adsr(0, .1, 0, 0).out()`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Escaped pitches using curly brackets",
|
||||
@ -72,7 +72,7 @@ ${makeExample(
|
||||
.cutoff(usaw(1/2) * 4000)
|
||||
.room(0.9).size(0.9).out()`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Durations using fractions and floating point numbers",
|
||||
@ -82,7 +82,7 @@ z1('1/8 0 2 4 0 2 4 1/4 0 3 5 0.25 _ 0 7 0 7')
|
||||
.adsr(0, .1, 0, 0).delayfb(0.45).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Disco was invented thanks to Ziffers",
|
||||
@ -92,7 +92,7 @@ beat(1)::snd('bd').out(); beat(2)::snd('sd').out()
|
||||
beat(3) :: snd('cp').room(0.5).size(0.5).orbit(2).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Accidentals and rests for nice melodies",
|
||||
@ -104,7 +104,7 @@ z1('^ 1/8 0 1 b2 3 4 _ 4 b5 4 3 b2 1 0')
|
||||
.adsr(0, .1, 0, 0).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Repeat items n-times",
|
||||
@ -117,7 +117,7 @@ z2('1/8 _ 0!4 5!4 4!2 7!2')
|
||||
.shape(0.2).sustain(0.1).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Subdivided durations",
|
||||
@ -127,7 +127,7 @@ z1('w [0 [5 [3 7]]] h [0 4]')
|
||||
.fmi(usine(.5)).fmh(2).out()
|
||||
`,
|
||||
false,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Rests
|
||||
|
||||
@ -138,7 +138,7 @@ z1('q 0 ^ e0 r _ 0 _ r 4 ^4 4')
|
||||
.sound('sine').scale("godian").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Rests with durations",
|
||||
@ -147,7 +147,7 @@ ${makeExample(
|
||||
.sound('sine').scale("aeryptian").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Chords
|
||||
|
||||
@ -232,7 +232,7 @@ ${makeExample(
|
||||
z1("(i v vi%-3 iv%-2)@(s 0 2 0 1 2 1 0 2)")
|
||||
.sound("sine").out()
|
||||
`,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Arpeggio from named chords with durations",
|
||||
@ -241,7 +241,7 @@ z1("_ Gm7 ^ C9 D7 Gm7")
|
||||
.arpeggio("e 0 2 q 3 e 1 2")
|
||||
.sound("sine").out()
|
||||
`,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Arpeggio from roman chords with inversions",
|
||||
@ -251,7 +251,7 @@ ${makeExample(
|
||||
.noteLength(0.125)
|
||||
.sound("sine").out()
|
||||
`,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Chaining
|
||||
|
||||
@ -264,7 +264,7 @@ z1('0 1 2 3').key('G3')
|
||||
.scale('minor').sound('sine').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"More complex chaining",
|
||||
@ -272,7 +272,7 @@ ${makeExample(
|
||||
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,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Alternative way for inputting options",
|
||||
@ -280,7 +280,7 @@ ${makeExample(
|
||||
z1('0 3 2 4',{key: 'D3', scale: 'minor pentatonic'}).sound('sine').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## String prototypes
|
||||
|
||||
@ -294,7 +294,7 @@ ${makeExample(
|
||||
"q 2 7 8 6".z2({key: "C2", scale: "aeolian"}).sound('sine').scale("minor").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const ziffers_rhythm = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -14,7 +14,7 @@ ${makeExample(
|
||||
z1('q 0 0 4 4 5 5 h4 q 3 3 2 2 1 1 h0').sound('sine').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Fraction durations",
|
||||
@ -23,7 +23,7 @@ ${makeExample(
|
||||
.sound('sine').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Decimal durations",
|
||||
@ -32,7 +32,7 @@ z1('0.25 5 1 2 6 0.125 3 8 0.5 4 1.0 0')
|
||||
.sound('sine').scale("galian").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## List of all duration characters
|
||||
|
||||
@ -95,7 +95,7 @@ ${makeExample(
|
||||
z1('bd [hh hh]').octave(-2).sound('sine').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"More complex pattern",
|
||||
@ -103,7 +103,7 @@ ${makeExample(
|
||||
z1('bd [hh <hh <cp cp:2>>]').octave(-2).sound('sine').out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Pitched samples",
|
||||
@ -113,7 +113,7 @@ ${makeExample(
|
||||
.adsr(0.25,0.125,0.125,0.25).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Pitched samples from list operation",
|
||||
@ -124,7 +124,7 @@ ${makeExample(
|
||||
.sound().out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Pitched samples with list notation",
|
||||
@ -134,7 +134,7 @@ ${makeExample(
|
||||
.adsr(0.25,0.125,0.125,0.25).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Sample indices",
|
||||
@ -143,7 +143,7 @@ ${makeExample(
|
||||
.octave(-1).sound("east").out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
${makeExample(
|
||||
"Pitched samples with sample indices",
|
||||
@ -151,7 +151,7 @@ ${makeExample(
|
||||
z1('_e 1@east:2 4@bd:3 6@arp:2 9@baa').sound().out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const ziffers_scales = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -95,7 +95,7 @@ ${makeExample(
|
||||
onbeat(1,1.5,3) :: sound('bd').cutoff(100 + usine(.25) * 1000).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
`;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const ziffers_syncing = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
@ -13,13 +13,13 @@ 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.
|
||||
|
||||
${makeExample(
|
||||
"Sending cue from event and wait",
|
||||
`
|
||||
"Sending cue from event and wait",
|
||||
`
|
||||
beat(4.0) :: sound("bd").cue("foo").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.
|
||||
|
||||
@ -65,7 +65,7 @@ beat([2.0,0.5,1.5].bar(1)) ::
|
||||
.dur(0.5).out()
|
||||
`,
|
||||
true,
|
||||
)}
|
||||
)}
|
||||
|
||||
## Automatic sync for ziffers patterns
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Editor } from "../../../main";
|
||||
import { makeExampleFactory } from "../../../Documentation";
|
||||
import { makeExampleFactory } from "../../Documentation";
|
||||
|
||||
export const ziffers_tonnetz = (application: Editor): string => {
|
||||
const makeExample = makeExampleFactory(application);
|
||||
|
||||
12
src/main.ts
12
src/main.ts
@ -13,11 +13,11 @@ import {
|
||||
loadUniverserFromUrl,
|
||||
} from "./FileManagement";
|
||||
import { singleElements, buttonGroups, ElementMap, createDocumentationStyle } from "./DomElements";
|
||||
import { registerFillKeys, registerOnKeyDown } from "./KeyActions";
|
||||
import { registerFillKeys, registerOnKeyDown } from "./Keyboard";
|
||||
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 { Clock } from "./Clock";
|
||||
import { Clock } from "./clock/Clock";
|
||||
import { loadSamples, UserAPI } from "./API";
|
||||
import * as oeis from "jisg";
|
||||
import * as zpatterns from "zifferjs/src/patterns.ts";
|
||||
@ -28,7 +28,7 @@ import { tryEvaluate } from "./Evaluator";
|
||||
// @ts-ignore
|
||||
import showdown from "showdown";
|
||||
import { makeStringExtensions } from "./extensions/StringExtensions";
|
||||
import { installInterfaceLogic } from "./InterfaceLogic";
|
||||
import { installInterfaceLogic } from "./UILogic";
|
||||
import { installWindowBehaviors } from "./WindowBehavior";
|
||||
import { makeNumberExtensions } from "./extensions/NumberExtensions";
|
||||
import colors from "./colors.json";
|
||||
@ -124,7 +124,6 @@ export class Editor {
|
||||
this.initializeElements();
|
||||
this.initializeButtonGroups();
|
||||
this.setCanvas(this.interface.feedback as HTMLCanvasElement);
|
||||
this.setCanvas(this.interface.scope as HTMLCanvasElement);
|
||||
this.setCanvas(this.interface.drawings as HTMLCanvasElement);
|
||||
try {
|
||||
this.loadHydraSynthAsync();
|
||||
@ -198,7 +197,7 @@ export class Editor {
|
||||
// ================================================================================
|
||||
|
||||
installEditor(this);
|
||||
runOscilloscope(this.interface.scope as HTMLCanvasElement, this);
|
||||
runOscilloscope(this.interface.feedback as HTMLCanvasElement, this);
|
||||
|
||||
// First evaluation of the init file
|
||||
tryEvaluate(this, this.universes[this.selected_universe.toString()].init);
|
||||
@ -581,7 +580,6 @@ export class Editor {
|
||||
private setCanvas(canvas: HTMLCanvasElement): void {
|
||||
/**
|
||||
* Sets the canvas element and configures its size and context.
|
||||
*
|
||||
* @param canvas - The HTMLCanvasElement to set.
|
||||
*/
|
||||
if (!canvas) return;
|
||||
|
||||
Reference in New Issue
Block a user