standard library - pannous/warp GitHub Wiki

Standard library

Made by warp help --markdown from lib/*.warp: each module with its words, a word with the comment above it. A module comes with use <module>; the prelude needs none.

prelude

The prelude (notes/stdlib.md §8): words every program has without use; only those it calls come along. Each is name(parameters) := body (modules::prelude_word_arity reads the parameters); library_words maps other spellings and method forms onto them (isdigit(c), xs.first(), round(x, 2) → round_to)

  • first(xs)
  • last(xs)
  • first_items(xs, n): the first or last n items (fewer when xs has fewer): xs.first(3), first 3 of xs
  • last_items(xs, n)
  • round_to(x, places): x rounded to that many digits after the point
  • mean(xs): the arithmetic mean, also spelled average
  • replace(t, old, new)
  • is_digit(c): ASCII character tests; a character compares by its code point
  • is_alpha(c)
  • is_alphanumeric(c)
  • is_space(c)
  • nearest(x, kind, limit = 0, within = 0): x as a fraction, by its continued fraction (src/real.rs computes it exactly for √2, π, … written in the program): within: 1e-6 the first convergent that close, a limit the closest fraction whose denominator is at most that (Python's limit_denominator), neither the first convergent that is the same float; 0 means not given
  • x as rational of a float is the exact fraction of its printed digits: sqrt(2.0) as rational is 14142135623730951/10000000000000000; nearest gives a short fraction close to it
  • dict(pairs): Python's dict(pairs) (card python-stdlib): a map of [key value] pairs
  • fromkeys(ks, value): Python's dict.fromkeys(ks, value) (card python-aliases): a map of each key with the one value
  • popped_position(xs, i): Python's xs.pop(i) and m.pop(k) (card python-aliases, declaration_lowering removed_key): the element at the 0-based position i (-1 the last) or the value of the key k, and the list or map without it
  • popped_item(x, k)
  • popped_rest(x, k)
  • cleared(x): Python's xs.clear() and m.clear() (card python-aliases, declaration_lowering cleared_collection): the empty list or map

memory

Linear memory by its bytes (samples/wasm/wasm_interop.warp): memory.slice(ptr, end) reads the bytes ptr…end-1, memory.copy(bytes, ptr) writes them from ptr on; addresses are 0-based byte offsets

net

The standard library module net (notes/stdlib.md section 7): use net; fetch (GET) is a prelude word. post sends a text through the adapter std_io and gives the answer's text (ureq natively, a synchronous request in the browser)

  • post(url:any, body:any)
  • post(url:any, body:any, headers:any): post(url, body, {"x-api-key": key}): the map's pairs are the request's headers; an answer of status >= 400 is the error, with the answer's text

collections

The standard library module collections (notes/stdlib.md): use collections, classes over a list field

  • class Stack
  • class Queue
  • class Deque
  • class Set
  • class Counter
  • OrderedMap(): warp maps keep insertion order: an ordered map is a map

hash

The standard library module hash (notes/stdlib.md section 7): use hash, through the adapter std_pure, of a text's UTF-8 bytes: sha256 as lowercase hex, crc32 as a number

  • sha256(subject:any)
  • crc32(subject:any)

regex

The standard library module regex (notes/stdlib.md section 7): use regex, through the adapter std_pure: Rust's regex natively, JS RegExp in the browser, held to what both do alike (no look-around, no backreferences)

  • matches(subject:any, pattern:any)
  • first_match(subject:any, pattern:any)
  • find_all(subject:any, pattern:any)
  • replace_all(subject:any, pattern:any, replacement:any)

file

The standard library module file (notes/stdlib.md section 7): use file, or a file URL in the program (P183). read, write, exists, write_bytes and read_bytes are prelude words (P171), the rest needs the module; append is written file.append(path, text). They call the adapter std_io: the file system natively, the page's in-memory files in the browser

  • write(path:any, text:any)
  • write_bytes(path:any, bytes:any): a file's bytes as a list of ints 0 to 255 (a .wasm a warp-written emitter writes)
  • read_bytes(path:any)
  • append_file(path:any, text:any)
  • exists(path:any)
  • list_files(folder:any)
  • lines(path)

json

The standard library module json (notes/stdlib.md section 7): use json. Warp data is a superset of JSON; the adapter std_pure parses and writes it (serde_json natively, JSON.parse / JSON.stringify in the browser); parse reads JSON5 too (comments, single quotes, trailing commas, bare keys), and json(t) is json.parse(t) without use json

  • parse_json(text:any)
  • to_json(value:any)
  • to_json_of_classes(value:any, classes:any): to_json in a program with classes (class_methods lower_json_classes): an instance is its fields

os

The standard library module os (notes/stdlib.md section 7): use os, through the adapter std_io; the browser has no environment (env gives ø) and no command line (args gives [])

  • env(name:any)
  • args: the command line arguments after the program file: warp run prog.warp a b gives ["a" "b"]
  • exec(command:any): exec sh "crontab -l": the command (a sh template, its argument vector) run without a shell, what it printed; natively only, the browser runs no processes

list

The standard library module list (notes/stdlib.md): standard functions of every program, unique(xs) or xs.unique(), no use needed (use list only for the qualified list.zip(a, b))

  • unique(xs)
  • zip(a, b)
  • enumerate(xs)
  • product(xs)
  • take(xs, n)
  • drop(xs, n)
  • flatten(xs)
  • chunk(xs, n)
  • window(xs, n)
  • median(xs)
  • flat_map(xs, f)
  • partition(xs, f): [kept, rest]: the elements f holds for, and the others
  • max_by(xs, f)
  • min_by(xs, f)
  • group_by(xs, f): {key: [elements]}: the elements by the text of f's value
  • tally(xs): {element: how often}
  • zip_with(a, b, f)
  • sum_by(xs, f)
  • count_by(xs, f)
  • rotate(xs, n): the elements moved n places to the left
  • interleave(a, b)
  • dedupe(xs): without runs of equal neighbours
  • scan(xs, start, f): the running results of f: scan([1, 2, 3], 0, (a, b) => a + b) is [1 3 6]
  • take_while(xs, f)
  • drop_while(xs, f)
  • argmax(xs): the index (from 0, like xs[i]) of the greatest element, the first of equal ones
  • argmin(xs)
  • pairwise(xs): the neighbours: pairwise([1, 2, 3]) is 1 2] [2 3
  • split_at(xs, n): [the first n, the rest]
  • cartesian(a, b): every pair of an element of a and one of b
  • mode(xs): the most frequent element, the first of equally frequent ones
  • variance(xs): the population variance and standard deviation
  • stdev(xs)
  • index_where(xs, f): the position (from 1, like index_of) of the first element f holds for, 0 when none does
  • last_n(xs, n)
  • fill(n, value): n copies of value: fill(3, 0) is [0 0 0]
  • minmax(xs): [smallest, greatest]
  • extend(xs, ys): Python's list methods (card python-stdlib): extend appends each of ys in place, index is the position from 0
  • concat(xs, ys): JavaScript's concat: a new list of xs then ys
  • index(xs, x)

math

The standard library module math (notes/stdlib.md): use math, together with the C library libm

  • gcd(a, b)
  • lcm(a, b)
  • clamp(x, low, high)
  • sign(x)
  • round_to(x, digits): x rounded to the given number of decimal places: round_to(3.14159, 2) is 3.14
  • factorial(n)
  • is_prime(n)
  • lerp(a, b, t): the value a fraction t of the way from a to b
  • is_even(n)
  • is_odd(n)
  • digits(n): the decimal digits of a whole number: digits(1234) is [1 2 3 4]
  • choose(n, k): the number of ways to choose k of n (the binomial coefficient)
  • mod_pow(base, exponent, modulus): base^exponent % modulus without the huge power
  • percent(part, whole): part as a percentage of whole: percent(1, 4) is 25
  • to_radians(degrees)
  • to_degrees(radians)
  • isqrt(n): the whole square root, rounded down
  • is_square(n)
  • divisors(n)
  • prime_factors(n)
  • to_base(n, base): the digits of n in a base up to 36: to_base(255, 16) is "ff"
  • bit_count(n): the one bits of whole numbers ≥ 0 (& and | are logical, xor is bitwise already): bit_count(6) is 2
  • bit_and(a, b): two's-complement bits of any whole numbers, by a + b = (a xor b) + 2 * bit_and(a, b): bit_and(-129, 127) is 127
  • bit_or(a, b)
  • from_base(t, base)
  • square(x): The C names still work after use math, each with a note naming the word here (modules STD_ALIASES)
  • square_root(x)
  • cube_root(x)
  • power(base, exponent)
  • exponential(x)
  • natural_log(x)
  • binary_log(x)
  • decimal_log(x)
  • logarithm(x, base): the logarithm of x to any base: logarithm(8, 2) is 3
  • sine(x)
  • cosine(x)
  • tangent(x)
  • arc_sine(x)
  • arc_cosine(x)
  • arc_tangent(x)
  • arcsin
  • arccos
  • arctan
  • angle(x, y): the angle of the point (x, y) from the x axis, in radians: C's atan2(y, x)
  • hyperbolic_sine(x)
  • hyperbolic_cosine(x)
  • hyperbolic_tangent(x)
  • hypotenuse(a, b): the length of the long side of a right triangle with sides a and b
  • ceiling(x)
  • whole_part(x): x without its fraction, toward zero: whole_part(-2.5) is -2
  • remainder(a, b): what remains of a after taking out b as often as it fits, with the sign of a (C's fmod)

text

The standard library module text (notes/stdlib.md): standard functions of every program, repeat(t, 2) or t.repeat(2), no use needed (use text only for the qualified text.repeat(t, 2))

  • repeat(t, n)
  • pad_left(t, width)
  • pad_right(t, width)
  • format(template, values): format("{} has {} items", ["cart", 3]): each {} takes the next value
  • words(t): the words between runs of spaces
  • lines(t)
  • capitalize(t)
  • center(t, width)
  • title(t)
  • slug(t): lower case letters and digits, the rest as single dashes: "Hello, World!" → "hello-world"
  • truncate(t, width)
  • is_blank(t): only spaces, tabs and line breaks, or nothing
  • is_upper(t): has letters, all upper (or lower) case
  • is_lower(t)
  • remove_prefix(t, prefix)
  • remove_suffix(t, suffix)
  • count_of(t, part): how often part occurs, not overlapping: count_of("banana", "an") is 2
  • is_palindrome(t)
  • word_count(t)
  • snake_case(t): "helloWorld", "Hello World", "hello-world" → "hello_world"
  • kebab_case(t)
  • camel_case(t): "hello_world" → "helloWorld"
  • indent(t, n): each line indented by n spaces
  • is_numeric(t): a whole or decimal number, optionally signed: "12.5", "-3"
  • between(t, opening, closing): the text between the first opening and the next closing after it, "" when either is missing
  • wrap(t, width): the words in lines of at most width characters
  • class Cursor: a reading position in a text, for scanners and parsers: c = Cursor("ab12"); c.take_while(is_letter) is "ab", then c.peek() is '1'; at counts the characters read (an index)

random

The standard library module random (notes/stdlib.md): use random, over the host words random and random_below

  • choice(xs)
  • shuffle(xs)
  • sample(xs, k)
  • seed(n): the same numbers after the same seed: seed(42); [random_below(100), random()]

map

The standard library module map (notes/stdlib.md): standard functions of every program, merge(a, b) or a.merge(b), no use needed (use map only for the qualified map.merge(a, b))

  • merge(a, b)
  • map_values(m, f)
  • invert(m): {a:1 b:2} → {1:"a" 2:"b"}: the values become the keys
  • pick(m, wanted): only the entries of the given keys that m has
  • from_pairs(pairs): "a", 1] ["b", 2 → {a:1 b:2}
  • omit(m, unwanted): the entries of m without the given keys
  • filter_values(m, f): the entries whose value f holds for
  • entries(m): {a:1 b:2} → "a", 1] ["b", 2, the opposite of from_pairs
  • get_or(m, key, fallback): the value of key, or fallback when m has none
  • find_key(m, f): the first key whose value f holds for, ø when none
  • update(m, other): Python's dict methods (card python-stdlib): update merges in place, items are the entries, setdefault keeps the default for a missing key and gives the key's value
  • items(m)
  • setdefault(m, key, fallback)
  • popitem(m): the last entry as [key value], removed from m in place (Python's dict.popitem)

time

The standard library module time (notes/stdlib.md): use time, the calendar over clock() (milliseconds since 1970, UTC)

  • day_number(ms)
  • date_of(ms): Howard Hinnant's civil_from_days: the proleptic Gregorian date of a day number
  • weekday(ms): ISO weekday: Monday 1 … Sunday 7
  • today()
  • add_days(ms, n)
  • days_between(from, to)
  • two_digits(n)
  • format_date(ms): ISO 8601: 2026-10-07
  • format_time(ms): the time of day, UTC: 13:05:09
  • days_from_date(year, month, day): Howard Hinnant's days_from_civil: the day number of a proleptic Gregorian date
  • parse_date(t): "2026-10-07" → milliseconds since 1970 at midnight UTC
  • format_duration(ms): milliseconds as the largest units: 5430000 → "1h 30m 30s", 250 → "250ms"
  • is_leap_year(year)
  • days_in_month(year, month)

matrix

The standard library matrix module (notes/stdlib.md): use matrix. A matrix is a list of rows: m[i][j] (m#i#j) reads and writes an element, printing and equality are those of lists. Locals are var: a program's own m or row stays apart from them

  • matrix(r, c, f)
  • filled_matrix(r, c, v)
  • zeros(r, c)
  • ones(r, c)
  • random_matrix(r, c)
  • identity(n)
  • rows(m)
  • cols(m)
  • shape(m)
  • transpose(m)
  • matrix_add(a, b)
  • scale(m, k)
  • map_matrix(m, f)
  • dot(u, v)
  • matmul(a, b)

draw

The standard library module draw (notes/stdlib.md, card drawing-words): use draw, a canvas of colored pixels shown by paint (the playground's canvas, natively a PNG). A color is a number 0xAARRGGBB: rgb, hsv, the named colors, with_alpha

  • paper: paper: the canvas before anything is drawn, as paint shows 0 (src/graphics/paint.rs PAPER)
  • black
  • white
  • gray
  • red
  • green
  • blue
  • yellow
  • orange
  • purple
  • cell(v): the pixel a coordinate falls in
  • rgb(r, g, b): r, g, b from 0 to 255
  • with_alpha(color, alpha): alpha from 0 (invisible) to 1 (opaque)
  • alpha_of(color)
  • clear_shape: what draw_shape's kind says (src/graphics/gpu_canvas.rs)
  • rect_shape
  • circle_shape
  • pixels_for(width, height): the pixels the canvas keeps here: none when they are on the GPU
  • channel_mix(color, under, a, place): one channel (its place 65536, 256 or 1) of color over under, by alpha a from 0 to 255

markup

The standard library module markup (card web-ssr, notes/web_framework.md "Built sites"): use markup (not html, which samples/web/html.warp would shadow). to_html(value) is the HTML of a markup value, div{ class:"box" h1{"Hi"} } →

Hi

, any other value as escaped text. Written in warp, so a page renders itself: the same function makes a built site's index.html at build time and its updates in the browser (page·html). A key named after an HTML element is an element; inside it a key named after an attribute with a plain value is an attribute (style: { fontSize: 12 } inline CSS), anything else a child in order.
  • html_elements
  • html_raw_text_elements: elements whose content is their own language as written (JavaScript, CSS), not escaped text
  • html_void_elements: elements without content or closing tag
  • html_attributes
  • html_boolean_attributes: attributes that are present or absent: checked: done
  • html_meta_attributes: a meta element's own attributes: meta{ charset: "utf-8" } stays the element, meta: { author: "Ann" } names metas
  • html_unitless_properties
  • to_html(value:any)
  • html_render(value:any, scope:any, chosen:any): scope: the component whose elements a style sheet styles (data-warp-scope, card web-scoped); chosen: the value of the select around, whose option is selected (select{ bind: fruit }, card web-bind-select)
  • html_is_element(value:any)
  • html_element(tag:any, content:any, scope:any, chosen:any)
  • html_is_page_fact(item:any): html{ title: "Shop" description: "…" meta: { author: "Ann" } }: facts about the page, for its head (card html-meta)
  • html_page_fact(name:any, value:any)
  • html_names_any(value:any, names:any): does a block of pairs name any of names
  • html_items(content:any): the items of an element's block, or its one item; a line of pairs (form{ method:"post" action:"/t" before more lines) is its pairs, attributes among them
  • html_is_group(value:any): a block {…} or a list […]: at run time a block is a map, no list (card inside-function)
  • html_is_attribute(item:any, tag:any): class:"box" inside an element: an attribute when its name is one and its value plain (or inline CSS for style)
  • html_holds_pairs(value:any): class:["btn" "btn-info"] is an attribute, style{ ".card": {…} } an element: its items are rules
  • html_attribute(item:any)
  • html_attribute_name(name:any): li{ key: todo.id … } names a list item: the attribute data-warp-key, by which the page moves its element
  • html_is_declarations(value:any): { color: theme padding: 8 }: a block of CSS properties with plain values
  • html_css(value:any): color: red; padding: 8px: camelCase names in kebab-case, numbers in pixels unless the property has no unit
  • html_declaration(item:any)
  • html_css_value(property:any, value:any): a number in pixels unless the property has no unit
  • html_style_rule(rule:any, scope:any): style{ ".card": { padding: 8 } }: a rule selector { declarations }; a text is CSS as written
  • html_scoped(selectors:any, scope:any): h2, p in the component Card: [data-warp-scope="Card"] h2, [data-warp-scope="Card"] p
  • html_kebab(name:any): CSS names are ASCII: lowered by hand, so a page carries no Unicode case table (card web-bundle-growth)
  • html_attribute_value(value:any): class:['btn' 'btn-info'] is the attribute btn btn-info
  • html_plain(value:any): a value as the text it shows: a text without quotes, anything else as warp writes it
  • html_is_true(value:any)
  • html_escaped(text:any)
  • html_tag(name:any): js{…} is the element script
  • html_element_at(value:any, path:any): The playground reads a component's holes from the page's rendering (card web-fine-components, lowering/component_state.rs): the element at path, its element indices from the root down as the page's children count them, and the text after after of its child elements
  • html_text_at(value:any, path:any, after:any)
  • html_child_elements(element:any)
  • html_child_items(element:any): an element's items that are no attributes
  • html_elements_in(item:any): the elements an item shows: itself, or those of a group

router

The standard library module router (card web-router, notes/web_framework.md "Routes"): a route pattern "/users/:id" matches the path "/users/7" with the parameter id = 7; "" matches any path (the not-found page). A parameter may declare its type (card route-typed): ":id:int" matches digits only, ":price:float" a decimal number, ":name:text" any part, given as text even when it is digits. The browser's URLPattern syntax too (card route-urlpattern): the last part may be optional (":tab?", ø when absent) or take the rest of the path (":path" zero or more parts, ":path+" one or more, joined by "/"; "*" unnamed); lowering/routes.rs checks a parameter's regular expression (":id(\d+)"), which matches any part here. lowering/routes.rs makes each route "…" {…} of a page a function and picks the first one matching page_path().

  • route_segments(path:any)
  • route_matches(pattern:any, path:any)
  • route_segment(pattern:any, path:any, name:any): the part of the path the parameter :name of the pattern stands for, as text; ø when the pattern has none
  • route_parameter(pattern:any, path:any, name:any): the parameter :name without a declared type: a number when it is digits ("/users/7" gives id 7), else its text (lowering/routes.rs converts a typed one itself)
  • route_part_name(part:any): the name of the parameter a pattern part declares (":id:int", ":id(\d+)", ":id?" → "id"), "" for a fixed part
  • route_part_type(part:any): the type a parameter declares (":id:int" → "int"), "" when it declares none (nor with a URLPattern mark or group)
  • route_part_mark(part:any): how often the last part of a pattern may come (URLPattern): "?" at most once, "*" any number, "+" at least once, "" exactly once
  • route_number(segment:any, dots:any): whether a path part is all digits, with at most dots decimal points among them
  • route_fits(kind:any, segment:any): whether a path part fits the declared type of its parameter

wagi

The standard library module wagi (card fermyon-hosting, notes/hosting.md "Fermyon"): warp build --wagi makes a program's routes answer one request the WAGI way (Spin's wagi executor, Akamai Functions): the request comes in the environment (REQUEST_METHOD, PATH_INFO, QUERY_STRING), the answer goes CGI-style to stdout: headers, a blank line, the body. A text answers as text, anything else as JSON, as warp serve answers (src/web/web_server.rs Answer::of). A route's status 418 and header "name" "value" (card wagi-build, lowering/serve.rs with_answer_headers) are wagi_header calls: the answer carries them. Not yet: request bodies (stdin), percent-decoded query values.

  • wagi_header(name:any, value:any)
  • wagi_variable(name:any)
  • wagi_query(query:any)
  • wagi_request()
  • wagi_json_text(t:any)
  • wagi_holds_pairs(value:any): a map ({n: 1, k: 2} in a route) is a list of pairs; ["a", "b"] holds none
  • wagi_json_fields(value:any)
  • wagi_json(value:any)
  • wagi_reply(status:any, content_type:any, body:any)
  • wagi_answer(value:any): the route's value with the status and headers it set
  • wagi_failed(message:any): lowering/serve.rs page·submitted throws "no route answers …" for a request no route takes

i18n

The standard library module i18n (card web-i18n, notes/i18n.md): use i18n. Translations are data, one map per language; a message is a text with {name} holes, or a map of plural categories (Unicode CLDR: zero one two few many other) chosen by the value count: messages = { en: { cart: { one: "{count} item", other: "{count} items" } }, de: { cart: { one: "{count} Artikel", other: "{count} Artikel" } } } translate(messages, "de", "cart", { count: 3 }) → "3 Artikel" A language the messages lack, or a message one language lacks, comes from the first language (de-AT reads de first).

  • translate(messages:any, language:text, key:text, values:any)
  • i18n_message(messages:any, language:text, key:text): The message of a key: in the language, its base language (de for de-AT), else the first language
  • i18n_plural_form(forms:any, category:text): A plural message's form for the category, else its form other
  • i18n_filled(message:text, values:any): The text with each {name} replaced by the value named name
  • plural_category(language:text, n:int): The CLDR plural category of a whole number in a language: "one", "few", "other", …

units

The standard library units module (card units-dynamic, notes/units_runtime.md): quantities whose unit is known only at run time, quantity("5 km") read from text or quantity(5, unit) of a unit named by data. A quantity carries its unit as data: the amount in SI base units (exact where the text is), its dimension and the unit it shows in. Units written in the program stay static (src/units): checked at compile time, plain numbers at run time.

  • unit_names: The units by name, their SI amount and dimension: the dimension packs the powers of length, mass and time as length + 256·mass + 65536·time, so multiplying quantities adds dimensions
  • unit_scales
  • unit_dimensions
  • class Quantity
  • same_dimension(q:Quantity, o:any, action): o when it measures what q measures, else the loud DimensionError
  • bound_of(x, bound): the bound of an amount with tolerance by name (inside Quantity, amount.low would call its method low)
  • quantity_text(q:Quantity): "5km": the amount in its own unit (str(q) of a parameter q:Quantity misses the text witness, card param-text-witness); a Gaussian amount keeps its σ apart from the unit, "12.00 ± 0.60σ m"
  • unit_product(first, second): m·m is m²
  • unit_factor(u): one unit by name, a power of one (m², s^2) or a product of them (m·kg, kg*m): [its SI amount, its dimension]
  • unit_measure(u): a unit as written, km/h or m/s²: [its SI amount, its dimension]
  • quantity(amount, u): quantity(5, "km"): amount of the unit u; quantity("5 km"), quantity("2.5km/h"): read from text
  • quantity(t:text)
  • exact_decimal(t:text): "-2.5" as the exact -5/2 (as number would read a float)

agent

The standard library module agent (card g_X_F0): agent "summarize this text" sends the prompt as given to Claude (the Anthropic Messages API) and gives its answer as text; agent(prompt, "claude-opus-5-5") names another model; with an expected type (x:int = agent "33/3", agent "…" as bool) it answers a value of that type (agent_as). The key is ANTHROPIC_API_KEY: natively the environment's (a terminal's export ANTHROPIC_API_KEY=sk-ant-…, in ~/.zshrc to keep it), in the browser the API key field of the playground's ⋯ menu (kept in that browser only). Loaded when a program calls agent, like units

  • agent(prompt:text)
  • agent(prompt:text, model:text)
  • agent_as(prompt:text, type:text): card int-let: a call with an expected type calls this companion (lowering/overloads.rs): x:int = agent "33/3" asks for a value of that type written as JSON and gives it as that value; text asks as agent does

sound

The standard library module sound (card basic-sound): play(440Hz, 0.5s), play(C4), play([C4 E4 G4]) (a chord, as in Sonic Pi), play(note("C#4")), melody([C4 E4 G4]) (one note after another), beep, tone(frequency, seconds, "square"). Frequencies and durations are numbers or quantities (440Hz, 0.5s, 250ms), read by si_amount as plain numbers (src/units/static_units.rs). The samples are made here and played by the host word sound_samples: natively a WAV file in the temporary folder (warp-sound/sound.wav), played only when warp may reach the user, and in the browser WebAudio. Loaded when a program calls one of its words (src/modules.rs SOUND_WORDS)

  • beat_seconds(beats)
  • bar_seconds(bars)
  • sample_offset: the samples cross to the host as whole numbers ≥ 0: amplitude + 32768 (src/sound/mod.rs SAMPLE_OFFSET), a stereo sound's interleaved left, right
  • loudest_sample
  • scale_letters: a note letter's semitone above C is its place here, from 0
  • midi_hertz(n): the frequency of MIDI note n (C4 is 60) at the tuning, equal-tempered, to a hundredth of a Hz as tables write it (C4 = 261.63): a note name lowers to it (src/lowering/music_words.rs)
  • midi(pitch): the MIDI note nearest a frequency: midi(C4) is 60, midi(440Hz) 69
  • note_names: the name of the note nearest a frequency, with sharps: note_name(Eb4) is "D#4"
  • note_name(pitch)
  • note(name): the frequency of a note name: note("A4") is 440, note("C#4") a semitone above C4, note("Eb5") one below E5
  • transpose(pitch, semitones): a pitch (or list of them) semitones higher, lower when negative: a note stays that note (transpose(C4, 12) == C5), any other frequency is multiplied (transpose(300Hz, 12) is 600)
  • transposed(frequency, semitones)
  • chord_intervals: the semitones of a chord's notes above its root, and of a scale's up to its octave: chord(C4, major7), scale(D4, dorian) (a kind word the program doesn't define is its text, src/lowering/music_words.rs)
  • scale_intervals
  • chord(root, kind)
  • scale(root, kind)
  • transpose_each(root, intervals)
  • decibels(level): the gain factor of decibels: loudness = -6 dB is about half (src/lowering/music_words.rs reads -6 dB)
  • wave(shape, p, dt = 0.0): one wave at phase p (0 to 1) of its period, from -1 to 1, a sample advancing the phase by dt; the jumps of square and sawtooth are band-limited (card reason-beep), sharp without dt
  • step_smoothing(p, dt): the correction of a wave's upward jump of 2 at phase 0 within a sample of it (PolyBLEP): a sharp jump has harmonics above half the sample rate, which fold back as an inharmonic buzz (880 Hz beep at 22050 samples a second)
  • sample_time(i): the seconds at sample i: a float source (decision exact-decimals), so the samples' math runs in f64, not in ratios
  • ramp(steps, seconds): how far a ramp of seconds has come after steps samples: 0 to 1
  • envelope(i, n): the level of sample i of n (ADSR): 0 at both ends
  • phase(f, i): the cycles a wave of frequency f has run at sample i, its vibrato included: the integral of f · (1 + c·sin(2π r t))
  • tremolo_gain(i): the gain of the tremolo at sample i: 1 at the start, 1 - tremolo at its lowest
  • voices_of(pitches)
  • chord_samples(pitches, duration, shape): the samples of frequencies sounding together
  • echo_floor: below this share of the level the echoes and the room's tail are cut off
  • max_echoes
  • reverb_seconds
  • reverb_delays: the delays (seconds) and the feedback of the four parallel combs of the reverb (Schroeder)
  • reverb_feedback
  • effects_on()
  • echoes_of(feedback): the number of repeats until a feedback has died below echo_floor
  • dry_at(amplitudes, i)
  • panned(samples): the samples for the speakers: mono in the middle, else interleaved left, right, the far side quieter by the pan
  • sound(samples)
  • tone(pitch, duration, shape): one wave shape: tone(440Hz, 0.5s) (a sine), tone(220Hz, 100ms, "square")
  • beep()
  • pitches_of(x): a frequency, or a list of them sounding together (a chord)
  • play_file(path): a music file in the background (wav, mp3, ogg, flac, aiff, m4a): play "song.mp3"; stop_sound stops it
  • stop_sound(handle = 0): play gives the sound's handle: h = play(C4, 2s); stop_sound(h) stops that one alone, stop_sound (handle 0) all
  • fade_sound(handle, gain, seconds = 0.05): a playing sound's gain ramps to gain (1 as played, 0 silent) over the seconds, sample by sample: h = play(C4, 4s); fade_sound(h, 0, 2) fades it out over 2 seconds; handle 0 fades all. render_sound writes the fade too
  • play_signal(signal, seconds): a signal computed while it plays (card real-time): hum(t) := 0.3 * sin(2 * pi * 220 * t); play(hum, 2s) (or play_signal(hum, 2s); play([left, right], 2s) in stereo) calls hum for every sample, t its time in seconds, a block ahead of the speaker; returns the handle when the last is queued
  • sound_queued(): play returns at once, its sound queued behind those before it: sound_queued() is how many seconds its voice still sounds, wait_sound waits for them (a program's end does too)
  • wait_sound()
  • render_sound(path): the sounds since the last render (or the start) one after another in one WAV file, offline (also without speakers): render_sound("song.wav") gives its seconds
  • sound_at(seconds): at 2 beats play C4, at 1 bar { … } (card sample-accurate): the statement's sounds start that many seconds after the voice's first sound, exactly so in render_sound; the voice goes on where it stood (src/lowering/music_words.rs)
  • sound_at_end()
  • melody_samples(notes, seconds): one note (or chord) after another: melody([C4 E4 G4]), melody([C4 E4 G4], 250ms). Plain seconds: the unit check reads a quantity parameter in a loop as unsupported (notes/units_runtime.md)
  • pattern_note(word): a pattern item is [0, items] (a group) or [1, frequencies] (a sound, no frequencies: a rest)
  • pattern_euclid(item, k, n): k notes over n steps as evenly as possible: step i sounds when (i * k) mod n < k
  • pattern_end(text: text, from: int, stops: text)
  • silence(n)
  • midi_send(status, data1, data2 = 0, port = ""): MIDI (card midi-out): midi_on C4, midi_off C4, midi_send(144, 60, 100) to the first output device (or the browser's Web MIDI output), midi_outputs() their names; channels count from 1, velocity 1 to 127
  • midi_on(pitch, velocity = 100, channel = 1)
  • midi_off(pitch, channel = 1)
  • midi_outputs()
  • midi_receive(): the next message [status, data1, data2] waiting at the input, ø when none (fails where there is no MIDI input)
  • write_midi(path, notes): a Standard MIDI File of notes [start, pitch, length, velocity] (seconds, frequency or note, seconds, 1 to 127) at 120 beats a minute, and the notes of such a file the same way: write_midi("tune.mid", 0, C4, 0.5, 100)
  • read_midi(path)
  • spectrum_window: the samples a spectrum looks at: 512 at 22050 Hz are 23 ms, bands 43 Hz apart are still told apart
  • band_frequency(i, count): the middle frequency of band i of count
  • nearest_band(frequency, count): the band whose middle frequency is nearest in pitch
⚠️ **GitHub.com Fallback** ⚠️