import type { Concept } from "../model/Agent.js"; import { Expression, Note } from "../model/Symbol.js"; import { Millimeters, SpeedMeasure, Track } from "../model/Quantity.js"; /** * What a tracker bar position does: sound a note, or operate one of * the expression valves on the bass or the treble side. * @category Systems and emulation */ export type TrackRole = 'bass-expression' | 'note' | 'treble-expression'; /** * A contiguous block of tracker bar positions serving one role. * Both bounds are inclusive. * @category Systems and emulation */ export interface TrackArea { readonly role: TrackRole; readonly from: Track; readonly to: Track; } /** * How a scale words a function: as a command that turns it on, one that * cancels it, or one that holds it for as long as it lasts. * @category Systems and emulation */ export type Spelling = 'on' | 'off' | 'held'; /** * What a word of a scale operates, rather than the word itself, so that * two scales can be compared at all. * @category Systems and emulation */ export interface Operation { /** The function operated, named the same wherever a scale has it. */ operates: string; spelling: Spelling; /** * Whether the half of the keyboard the valve serves is part of the * function operated. The dynamics are per half; the pedals are not, * and the two Welte scales put them on opposite edges of the paper, * so a rule that compared sides would leave every pedal unpaired. */ sided: boolean; } /** * What a position in the note block reads: a note of one pitch. * @category Systems and emulation */ export type NoteMeaning = Pick; /** * What an expression position reads: an expression type, on the side of * the keyboard the position serves. * @category Systems and emulation */ export type ExpressionMeaning = Pick; /** * What a position of the bar reads: a note or an expression. * @category Systems and emulation */ export type TrackMeaning = NoteMeaning | ExpressionMeaning; /** * Describes a tracker bar. Track numbers are 1-based and count from * the bass edge of the roll, which is the numbering used throughout * the edition: a feature's `vertical.from` is a track in this sense. * * This is the only place where track numbers are given a meaning. * Anything that needs to know where the note block ends, which side * an expression belongs to, or how a track maps to a pitch, should * ask the tracker bar rather than repeat the boundaries. * @category Systems and emulation */ export interface TrackerBar { /** * Names the reproducing system in the type vocabulary: * the system is `https://w3id.org/reo/type/system/` and its * expression types live under `https://w3id.org/reo/type//`. */ readonly id: string; readonly name: string; /** Width of the roll the bar reads. */ readonly width: Millimeters; /** Number of positions on the bar. Tracks run from 1 to this. */ readonly trackCount: number; /** The blocks of positions, from the bass edge upwards. */ readonly areas: readonly TrackArea[]; /** The expression types the bar reads, each a term of the system. */ readonly expressionTypes: readonly string[]; /** * How the system spells a single added accent, each spelling a * sequence of its expression types: a latched system turns a valve on * and off again, a held one holds one perforation for the accent. */ readonly accents: readonly (readonly string[])[]; /** * The position carrying the rewind perforation, which runs at * the very end of a roll and is the usual landmark for calibrating * a scan against the bar. */ readonly rewindTrack: Track; /** * The paper speed the system runs its rolls at, where the * literature states one. A system whose rolls each carry a tempo * of their own, as the Licensee's do, states none. */ readonly paperSpeed?: SpeedMeasure; /** * Where the roll's own content ends, from its perforations alone, or * `undefined` where nothing on the paper says. A copy that reads * `undefined` runs to the end of whatever was scanned, which is a fact * about the scan rather than about the roll and should be reported as one. * * Takes anything with a place and a position, so a reader can ask it of a * copy's features before there are symbols, and a collation can ask it of * the symbols afterwards. */ endsAt(features: readonly PlacedOnBar[]): RollEnd | undefined; /** * `undefined` for a position the bar does not read. A measured place * is snapped to the nearest position: perforations sit on the grid and * measurements of them scatter around it. */ meaningOf(position: Track): TrackMeaning | undefined; /** * What the bar reads off a feature, which may lie across more than one * position. A perforation lifts every valve whose bar hole it uncovers, * so an opening across two positions reads as two commands; one on a * single position reads as the one `meaningOf` gives, and one on * positions the bar does not read as none at all. */ meaningsOf(span: OnBar): readonly TrackMeaning[]; /** * `meaningOf` inverted: the position this bar reads the meaning on, * or `undefined` where it does not read it at all. A symbol's track * is this rather than anything measured, since a note of one pitch * sits on exactly one position of a given bar. */ positionOf(meaning: TrackMeaning): Track | undefined; /** `undefined` for a position the bar does not read; snapped as `meaningOf` is. */ roleOf(position: Track): TrackRole | undefined; /** * What the expression type operates, or `undefined` for one the bar * does not read or whose function has no counterpart in another scale. */ operationOf(expressionType: string): Operation | undefined; /** The positions a feature lies across, snapped to the grid. */ positionsIn(span: OnBar): readonly Track[]; } /** * What a position says, as a key. Two bars read the same thing exactly * where their keys agree, which is what lets a symbol cross from one * system to another and what decides whether two symbols collate. * @category Systems and emulation */ export declare const keyOf: (meaning: TrackMeaning) => string; /** * The roll system a tracker bar belongs to, as the roll metadata states it. * @category Vocabulary */ export declare const systemOf: (bar: TrackerBar) => Concept; /** * The identifier of a system the type vocabulary knows, from the IRI naming it. * @category Vocabulary */ export declare const systemIdIn: (id: string | undefined) => string | undefined; /** * The identifier of a system the type vocabulary knows, from its concept. * @category Vocabulary */ export declare const systemIdOf: (system: Concept | undefined) => string | undefined; /** * Where a roll's own content ends, as far as its perforations say. * * This is a question about the paper, not about the mechanism: it asks where * the rewind is *punched*, not when the rewind pneumatic takes hold. The second * is a matter of valve lift and belongs to whatever performs the roll. Keeping * them apart is what lets collation and counting ask this without an emulator. * @category Systems and emulation */ export type RollEnd = { readonly at: Millimeters; readonly because: 'rewind'; }; /** * Anything carrying a place on the roll and a position on the bar. * @category Systems and emulation */ export type PlacedOnBar = { readonly horizontal: { readonly from: Millimeters; readonly to: Millimeters; }; readonly vertical: { readonly from: Track; }; }; /** * Where a feature lies across the bar: one place, or a run of them where * `to` is given. Structural, so a feature's `vertical` passes as it is and * this module need know nothing about features. * @category Systems and emulation */ export type OnBar = { readonly from: Track; readonly to?: Track; }; /** * A tracker bar as written down, with its positions as plain numbers * in the bar's own 1-based numbering; `describeTrackerBar` gives them * their type. * @category Systems and emulation */ export interface TrackerBarSpec { id: string; name: string; width: Millimeters; trackCount: number; /** The contiguous block of note positions. */ notes: { from: number; to: number; lowestPitch: number; }; /** Every position outside the note block, keyed by track. */ expressions: ReadonlyMap; /** * The position the rewind runs on, where the system gives it no * valve of its own to be named after. The T-98 drives its rewind * with a long perforation on the bass sforzando-piano position. * Left out, it is the position typed `Rewind`. */ rewindTrack?: number; /** The speed the system runs its rolls at, where the literature states one. */ paperSpeed?: SpeedMeasure; /** * How long a perforation on a *shared* rewind position has to be before it * is the rewind rather than the command the position usually carries. Only * meaningful with `rewindTrack`: a system that gives the rewind a line of * its own needs no threshold, since anything there is the rewind. */ rewindHold?: Millimeters; /** * What each expression type operates, keyed by type. A type left out * operates a function no other scale has a word for, and a transfer * leaves it a plain deletion. */ operations?: Readonly>; /** How the system spells a single added accent; see `TrackerBar.accents`. */ accents?: readonly (readonly string[])[]; } /** * The tracker bar a description gives, its positions typed and its * readings worked out. Throws where the description names no rewind * position, or names expression types its bar does not read. * @category Systems and emulation */ export declare const describeTrackerBar: (spec: TrackerBarSpec) => TrackerBar; /** * Puts a position of one bar onto the position of another that reads * the same thing, or nowhere when the other bar does not read it. This * is how a copy read in one system's numbering is put into another's, * as the migration does for a Licensee copy stored on T-100 tracks. * @category Systems and emulation */ export declare const translationBetween: (from: TrackerBar, to: TrackerBar) => (position: Track) => Track | undefined;