notations 0.0.69 → 0.0.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/notations.umd.js +17409 -23615
- package/dist/notations.umd.min.js +8 -3
- package/dist/notations.umd.min.js.LICENSE.txt +0 -14
- package/dist/notations.umd.min.js.map +1 -1
- package/lib/cjs/beats.d.ts +4 -0
- package/lib/cjs/beats.js +19 -2
- package/lib/cjs/beats.js.map +1 -1
- package/lib/cjs/block.d.ts +73 -0
- package/lib/cjs/block.js +247 -0
- package/lib/cjs/block.js.map +1 -0
- package/lib/cjs/carnatic/NotationView.d.ts +11 -4
- package/lib/cjs/carnatic/NotationView.js +26 -11
- package/lib/cjs/carnatic/NotationView.js.map +1 -1
- package/lib/cjs/commands.d.ts +25 -11
- package/lib/cjs/commands.js +87 -34
- package/lib/cjs/commands.js.map +1 -1
- package/lib/cjs/entity.d.ts +3 -7
- package/lib/cjs/entity.js +7 -37
- package/lib/cjs/entity.js.map +1 -1
- package/lib/cjs/grids.d.ts +32 -3
- package/lib/cjs/grids.js +96 -9
- package/lib/cjs/grids.js.map +1 -1
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/loader.js +1 -41
- package/lib/cjs/loader.js.map +1 -1
- package/lib/cjs/notation.d.ts +28 -33
- package/lib/cjs/notation.js +144 -122
- package/lib/cjs/notation.js.map +1 -1
- package/lib/cjs/parser.d.ts +21 -6
- package/lib/cjs/parser.js +122 -23
- package/lib/cjs/parser.js.map +1 -1
- package/lib/esm/beats.d.ts +4 -0
- package/lib/esm/beats.js +19 -2
- package/lib/esm/beats.js.map +1 -1
- package/lib/esm/block.d.ts +73 -0
- package/lib/esm/block.js +230 -0
- package/lib/esm/block.js.map +1 -0
- package/lib/esm/carnatic/NotationView.d.ts +11 -4
- package/lib/esm/carnatic/NotationView.js +26 -11
- package/lib/esm/carnatic/NotationView.js.map +1 -1
- package/lib/esm/commands.d.ts +25 -11
- package/lib/esm/commands.js +84 -34
- package/lib/esm/commands.js.map +1 -1
- package/lib/esm/entity.d.ts +3 -7
- package/lib/esm/entity.js +7 -37
- package/lib/esm/entity.js.map +1 -1
- package/lib/esm/grids.d.ts +32 -3
- package/lib/esm/grids.js +96 -9
- package/lib/esm/grids.js.map +1 -1
- package/lib/esm/index.d.ts +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/loader.js +1 -8
- package/lib/esm/loader.js.map +1 -1
- package/lib/esm/notation.d.ts +28 -33
- package/lib/esm/notation.js +129 -118
- package/lib/esm/notation.js.map +1 -1
- package/lib/esm/parser.d.ts +21 -6
- package/lib/esm/parser.js +122 -24
- package/lib/esm/parser.js.map +1 -1
- package/package.json +3 -2
package/lib/cjs/beats.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { CycleIterator } from "./cycle";
|
|
|
4
4
|
import { WindowIterator } from "./iterators";
|
|
5
5
|
import { LayoutParams } from "./layouts";
|
|
6
6
|
import { GridModel, GridCell, ColAlign, GridLayoutGroup } from "./grids";
|
|
7
|
+
import { Block, BlockItem } from "./notation";
|
|
7
8
|
type Fraction = TSU.Num.Fraction;
|
|
8
9
|
export declare class Beat {
|
|
9
10
|
readonly index: number;
|
|
@@ -67,9 +68,12 @@ export declare class GlobalBeatLayout {
|
|
|
67
68
|
roleBeatsForLine: Map<number, Beat[][]>;
|
|
68
69
|
beatColDAGsByLP: Map<number, BeatColDAG>;
|
|
69
70
|
readonly gridLayoutGroup: GridLayoutGroup;
|
|
71
|
+
constructor(sharedGridLayoutGroup?: GridLayoutGroup);
|
|
70
72
|
getGridModelForLine(lineid: LineId): GridModel;
|
|
71
73
|
protected beatColDAGForLP(lpid: LPID): BeatColDAG;
|
|
72
74
|
addLine(line: Line): void;
|
|
75
|
+
processBlock(block: Block): void;
|
|
76
|
+
protected processBlockItem(item: BlockItem): void;
|
|
73
77
|
protected lineToRoleBeats(line: Line, gridModel: GridModel): Beat[][];
|
|
74
78
|
protected addBeat(beat: Beat, gridModel: GridModel): GridCell;
|
|
75
79
|
}
|
package/lib/cjs/beats.js
CHANGED
|
@@ -38,6 +38,7 @@ const TSU = __importStar(require("@panyam/tsutils"));
|
|
|
38
38
|
const _1 = require("./");
|
|
39
39
|
const iterators_1 = require("./iterators");
|
|
40
40
|
const grids_1 = require("./grids");
|
|
41
|
+
const notation_1 = require("./notation");
|
|
41
42
|
const ZERO = TSU.Num.Fraction.ZERO;
|
|
42
43
|
const ONE = TSU.Num.Fraction.ONE;
|
|
43
44
|
class Beat {
|
|
@@ -239,11 +240,11 @@ class BeatColDAG {
|
|
|
239
240
|
}
|
|
240
241
|
exports.BeatColDAG = BeatColDAG;
|
|
241
242
|
class GlobalBeatLayout {
|
|
242
|
-
constructor() {
|
|
243
|
+
constructor(sharedGridLayoutGroup) {
|
|
243
244
|
this.gridModelsForLine = new Map();
|
|
244
245
|
this.roleBeatsForLine = new Map();
|
|
245
246
|
this.beatColDAGsByLP = new Map();
|
|
246
|
-
this.gridLayoutGroup = new grids_1.GridLayoutGroup();
|
|
247
|
+
this.gridLayoutGroup = sharedGridLayoutGroup !== null && sharedGridLayoutGroup !== void 0 ? sharedGridLayoutGroup : new grids_1.GridLayoutGroup();
|
|
247
248
|
}
|
|
248
249
|
getGridModelForLine(lineid) {
|
|
249
250
|
let out = this.gridModelsForLine.get(lineid) || null;
|
|
@@ -269,6 +270,22 @@ class GlobalBeatLayout {
|
|
|
269
270
|
this.lineToRoleBeats(line, gridModel);
|
|
270
271
|
(_b = gridModel.eventHub) === null || _b === void 0 ? void 0 : _b.commitBatch();
|
|
271
272
|
}
|
|
273
|
+
processBlock(block) {
|
|
274
|
+
for (const child of block.children()) {
|
|
275
|
+
this.processBlockItem(child);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
processBlockItem(item) {
|
|
279
|
+
if ((0, notation_1.isLine)(item)) {
|
|
280
|
+
const line = item;
|
|
281
|
+
if (!line.isEmpty && line.layoutParams != null) {
|
|
282
|
+
this.addLine(line);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
else if ((0, notation_1.isBlock)(item)) {
|
|
286
|
+
this.processBlock(item);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
272
289
|
lineToRoleBeats(line, gridModel) {
|
|
273
290
|
const lp = line.layoutParams;
|
|
274
291
|
const roleBeats = [];
|
package/lib/cjs/beats.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"beats.js","sourceRoot":"","sources":["../../src/beats.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { AtomType, Marker, Group, Line, Atom, Space, Role } from \"./\";\nimport { CycleIterator, CyclePosition } from \"./cycle\";\nimport { WindowIterator } from \"./iterators\";\nimport { LayoutParams } from \"./layouts\";\nimport { GridModel, GridRow, GridCell, ColAlign, GridLayoutGroup } from \"./grids\";\n\ntype Fraction = TSU.Num.Fraction;\nconst ZERO = TSU.Num.Fraction.ZERO;\nconst ONE = TSU.Num.Fraction.ONE;\n\n/**\n * Represents a single beat in the notation.\n * A beat contains one or more atoms and has a specific position in a bar.\n */\nexport class Beat {\n private static idCounter = 0;\n readonly uuid = Beat.idCounter++;\n // Should this be as flat Atoms or should we keep it as atoms and breakdown later?\n\n /** The atom contained in this beat */\n atom: Atom;\n protected atomIsPlaceholder = false;\n\n /**\n * Creates a new Beat.\n * @param index The index of this beat in the sequence\n * @param role The role this beat belongs to\n * @param offset The time offset of this beat from the start\n * @param duration The duration of this beat\n * @param barIndex The index of the bar containing this beat\n * @param beatIndex The index of this beat within its bar\n * @param instance The instance number of this beat\n * @param prevBeat The previous beat in the sequence, if any\n * @param nextBeat The next beat in the sequence, if any\n */\n constructor(\n public readonly index: number,\n public readonly role: Role,\n public readonly offset: Fraction,\n public readonly duration: Fraction,\n public readonly barIndex: number,\n public readonly beatIndex: number,\n public readonly instance: number,\n public readonly prevBeat: null | Beat,\n public nextBeat: null | Beat,\n ) {}\n\n /**\n * Returns a debug-friendly representation of this Beat.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return {\n index: this.index,\n role: this.role.name,\n offset: this.offset.toString(),\n duration: this.duration.toString(),\n barIndex: this.barIndex,\n beatIndex: this.beatIndex,\n instance: this.instance,\n atom: this.atom.debugValue(),\n };\n }\n\n /**\n * Gets the end offset of this beat (offset + duration).\n */\n get endOffset(): Fraction {\n return this.offset.plus(this.duration);\n }\n\n /**\n * Checks if this beat is filled completely (no remaining space).\n */\n get filled(): boolean {\n return this.remaining.isZero;\n }\n\n /**\n * Gets the remaining duration available in this beat.\n */\n get remaining(): Fraction {\n return this.atom ? this.duration.minus(this.atom.duration, true) : this.duration;\n }\n\n /**\n * Adds an atom to this beat.\n * @param atom The atom to add\n * @returns True if the atom was added successfully, false if there's not enough space\n */\n add(atom: Atom): boolean {\n if (this.remaining.cmp(atom.duration) < 0) {\n return false;\n }\n if (!this.atom) {\n this.atom = atom;\n } else {\n if (!this.atomIsPlaceholder) {\n this.atomIsPlaceholder = true;\n this.atom = new Group(this.atom).setDuration(ONE, true);\n }\n (this.atom as Group).addAtoms(true, atom);\n }\n return true;\n }\n\n /**\n * Gets all markers that should be displayed before this beat.\n * @returns An array of Marker objects\n */\n get preMarkers(): Marker[] {\n const out = [] as Marker[];\n let curr: Atom | null = this.atom;\n while (curr != null) {\n for (const marker of curr.markersBefore || []) {\n out.push(marker);\n }\n if (curr.TYPE == AtomType.GROUP) {\n curr = (curr as Group).atoms.first;\n } else {\n curr = null;\n }\n }\n return out;\n }\n\n /**\n * Gets all markers that should be displayed after this beat.\n * @returns An array of Marker objects\n */\n get postMarkers(): Marker[] {\n const out = [] as Marker[];\n let curr: Atom | null = this.atom;\n while (curr != null) {\n out.splice(0, 0, ...(curr.markersAfter || []));\n if (curr.TYPE == AtomType.GROUP) {\n curr = (curr as Group).atoms.last;\n } else {\n curr = null;\n }\n }\n return out;\n }\n}\n\n/**\n * Builds a sequence of beats from atoms according to layout parameters.\n * Used to convert a flat sequence of atoms into structured beats for display.\n */\nexport class BeatsBuilder {\n /** All atoms divided into beats */\n readonly beats: Beat[] = [];\n readonly startIndex: number;\n readonly beatOffset: Fraction;\n cycleIter: CycleIterator;\n windowIter: WindowIterator;\n\n /** Callback for when an atom is added to this role */\n onAtomAdded: (atom: Atom, beat: Beat) => void;\n\n /** Callback for when a new beat is added */\n onBeatAdded: (beat: Beat) => void;\n\n /** Callback for when a beat has been filled */\n onBeatFilled: (beat: Beat) => void;\n\n /**\n * Creates a new BeatsBuilder.\n * @param role The role containing the atoms\n * @param layoutParams Layout parameters for structuring beats\n * @param startOffset The starting offset for the first beat, defaults to ZERO\n * @param atoms Initial atoms to add to the beats\n */\n constructor(\n public readonly role: Role,\n public readonly layoutParams: LayoutParams,\n public readonly startOffset: Fraction = ZERO,\n ...atoms: Atom[]\n ) {\n const [, [bar, beat, instance], beatOffset, index] = layoutParams.cycle.getPosition(startOffset);\n this.cycleIter = layoutParams.cycle.iterateBeats(bar, beat, instance);\n this.windowIter = new WindowIterator();\n this.beatOffset = beatOffset;\n\n // evaluate the start beatindex - typically it would be 0 if things start\n // at beginning of a cycle. But if the start offset is < 0 then the\n // startIndex should also shift accordingly\n this.startIndex = index;\n this.addAtoms(...atoms);\n }\n\n /**\n * Adds atoms to be processed into beats.\n * @param atoms The atoms to add\n */\n addAtoms(...atoms: Atom[]): void {\n // First add all atoms to the atom Iterator so we can\n // fetch them as FlatAtoms. This is needed because atoms\n // passed here could be unflatted (via groups) or much larger\n // than what can fit in the given role/bar etc. So this\n // flattening and windowing is needed before we add them\n // to the views - and this is done by the durationIterators.\n this.windowIter.push(...atoms);\n while (this.windowIter.hasMore) {\n // get the last/current row and add a new one if it is full\n let currBeat = this.beats[this.beats.length - 1];\n\n // First add a row if last row is filled\n if (this.beats.length == 0 || currBeat.filled) {\n // what should be the beatlengths be here?\n currBeat = this.addBeat();\n }\n\n // For this beat get symbols in all roles\n const [remAtoms, filled] = this.windowIter.get(currBeat.remaining);\n TSU.assert(remAtoms.length > 0, \"Atleast one element should have been available here\");\n // render the atoms now\n for (const atom of remAtoms) {\n // console.log(\"Adding FA: \", flatAtom.debugValue(), flatAtom.atom);\n TSU.assert(currBeat.add(atom), \"Should return true as we are already using a duration iterator here\");\n if (this.onAtomAdded) this.onAtomAdded(atom, currBeat);\n }\n if (currBeat.filled) {\n if (this.onBeatFilled) this.onBeatFilled(currBeat);\n }\n }\n }\n\n /**\n * Adds a new beat to the sequence.\n * @returns The newly created beat\n */\n protected addBeat(): Beat {\n const numBeats = this.beats.length;\n const lastBeat = numBeats == 0 ? null : this.beats[numBeats - 1];\n const nextCP: [CyclePosition, Fraction] = this.cycleIter.next().value;\n const apb = this.layoutParams.beatDuration;\n const newBeat = new Beat(\n lastBeat == null ? this.startIndex : lastBeat.index + 1,\n this.role,\n lastBeat == null ? this.startOffset.minus(this.beatOffset).timesNum(apb, true) : lastBeat.endOffset,\n nextCP[1].timesNum(apb),\n nextCP[0][0],\n nextCP[0][1],\n nextCP[0][2],\n lastBeat,\n null,\n );\n if (lastBeat == null && this.beatOffset.isGT(ZERO)) {\n // Add spaces to fill up empty beats\n newBeat.add(new Space(this.beatOffset.timesNum(apb)));\n }\n if (lastBeat) lastBeat.nextBeat = newBeat;\n this.beats.push(newBeat);\n if (this.onBeatAdded) this.onBeatAdded(newBeat);\n return newBeat;\n }\n}\n\n/**\n * Represents a column of beats in a layout grid.\n * Used for aligning beats vertically in the notation.\n */\nexport class BeatColumn extends ColAlign {\n /** Spacing between atoms in this column */\n atomSpacing = 5;\n /** Unique key for this column */\n readonly key: string;\n\n /**\n * Creates a new BeatColumn.\n * @param offset The starting offset of this column\n * @param endOffset The ending offset of this column\n * @param markerType The type of marker for this column (negative: before, positive: after, zero: normal)\n */\n constructor(\n public readonly offset: Fraction,\n public readonly endOffset: Fraction,\n public readonly markerType: number,\n ) {\n super();\n offset = offset.factorized;\n endOffset = endOffset.factorized;\n this.key = BeatColumn.keyFor(offset, endOffset, markerType);\n }\n\n /**\n * Generates a key for identifying columns with the same offsets and marker type.\n * @param offset The starting offset\n * @param endOffset The ending offset\n * @param markerType The type of marker (negative: before, positive: after, zero: normal)\n * @returns A string key\n */\n static keyFor(offset: Fraction, endOffset: Fraction, markerType = 0): string {\n offset = offset.factorized;\n endOffset = endOffset.factorized;\n if (markerType < 0) {\n // return the column for the marker \"before\" this col\n // int his case only the \"start offset\" is needed and length doesnt matter\n return \":\" + offset.toString();\n } else if (markerType > 0) {\n // return the column for the marker \"after\" this col\n // in this case only thd end offset matters\n return endOffset.toString() + \":\";\n } else {\n return offset.toString() + \":\" + endOffset.toString();\n }\n }\n}\n\n/**\n * Manages the organization of beats into columns based on their offsets.\n * Used to create a directed acyclic graph (DAG) of beat columns for layout purposes.\n *\n * Grouping of beats by their column based on the layout params.\n * The confusion is we have beats broken up and saved in columns\n * but we are loosing how a line is supposed to access it in its own way\n * we have beatsByRole for getting all beats for a role (in a line)\n * sequentially we have beatColumns for getting all beats in a particular\n * column across all lines and roles globally.\n *\n * What we want here is for a given line get all roles, their beats\n * in zipped way. eg for a Line with 3 roles and say 10 beats each\n * (with the breaks of 4, 1) we need:\n *\n * R1 B1 R1 B2 R1 B3 R1 B4\n * R2 B1 R2 B2 R2 B3 R2 B4\n * R3 B1 R3 B2 R3 B3 R3 B4\n *\n * R1 B5\n * R2 B5\n * R3 B5\n *\n * R1 B6 R1 B7 R1 B8 R1 B9\n * R2 B6 R2 B7 R2 B8 R2 B9\n * R3 B6 R3 B7 R3 B8 R3 B9\n *\n * R1 B10\n * R2 B10\n * R3 B10\n *\n *\n * Here we have 5 distinct beat columns:\n *\n * 1: R1B1, R2B1, R3B1, R1B6, R2B6, R3B6,\n * 2: R1B2, R2B2, R3B2, R1B7, R2B7, R3B7,\n * 3: R1B3, R2B3, R3B3, R1B8, R2B8, R3B8,\n * 4: R1B4, R2B4, R3B4, R1B9, R2B9, R3B9,\n * 5: R1B5, R2B5, R3B5, R1B10, R2B10, R3B10,\n *\n */\nexport class BeatColDAG {\n /** Map of column keys to BeatColumn objects */\n beatColumns = new Map<string, BeatColumn>();\n\n /**\n * Creates a new BeatColDAG.\n * @param layoutGroup The layout group to associate with this DAG\n */\n constructor(public readonly layoutGroup: GridLayoutGroup) {\n //\n }\n\n /**\n * Gets the beat column for a given duration at the specified offset.\n * Creates a new column if none exists.\n * @param offset The starting offset\n * @param endOffset The ending offset\n * @param markerType The type of marker\n * @returns The BeatColumn for the specified parameters\n */\n getBeatColumn(offset: Fraction, endOffset: Fraction, markerType = 0): BeatColumn {\n const [bcol, newcreated] = this.ensureBeatColumn(offset, endOffset, markerType);\n if (newcreated) {\n if (markerType == 0) {\n const [prevcol] = this.ensureBeatColumn(offset, endOffset, -1);\n const [nextcol] = this.ensureBeatColumn(offset, endOffset, 1);\n prevcol.addSuccessor(bcol);\n bcol.addSuccessor(nextcol);\n for (const other of this.beatColumns.values()) {\n // only join the \"marker\" columns\n if (other.markerType == -1 && endOffset.equals(other.offset)) {\n // our next col is a preecessor of other\n nextcol.addSuccessor(other);\n } else if (other.markerType == 1 && other.endOffset.equals(offset)) {\n // our prev col is a predecessor of other\n other.addSuccessor(prevcol);\n }\n }\n }\n }\n return bcol;\n }\n\n /**\n * Ensures a beat column exists for the given parameters.\n * @param offset The starting offset\n * @param endOffset The ending offset\n * @param markerType The type of marker\n * @returns A tuple containing the column and whether it was newly created\n */\n protected ensureBeatColumn(offset: Fraction, endOffset: Fraction, markerType = 0): [BeatColumn, boolean] {\n const key = BeatColumn.keyFor(offset, endOffset, markerType);\n let bcol = this.beatColumns.get(key) || null;\n const newcreated = bcol == null;\n if (!bcol) {\n bcol = new BeatColumn(offset, endOffset, markerType);\n this.beatColumns.set(key, bcol);\n }\n return [bcol, newcreated];\n }\n}\n\n/** Type alias for line IDs */\ntype LineId = number;\n/** Type alias for layout parameter IDs */\ntype LPID = number;\n\n/**\n * Manages the beat layouts for all lines in a notation.\n * Handles the creation of grid models, positioning of beats, and alignment of beats across lines.\n */\nexport class GlobalBeatLayout {\n /** Map of line IDs to grid models */\n gridModelsForLine = new Map<LineId, GridModel>();\n /** Map of line IDs to arrays of beats for each role */\n roleBeatsForLine = new Map<LineId, Beat[][]>();\n /** Map of layout parameter IDs to beat column DAGs */\n beatColDAGsByLP = new Map<LPID, BeatColDAG>();\n /** The global layout group for all grid models */\n readonly gridLayoutGroup = new GridLayoutGroup();\n\n /**\n * Gets the GridModel associated with a particular line, creating one if it doesn't exist.\n * @param lineid The ID of the line\n * @returns The GridModel for the line\n */\n getGridModelForLine(lineid: LineId): GridModel {\n let out = this.gridModelsForLine.get(lineid) || null;\n if (!out) {\n out = new GridModel();\n this.gridLayoutGroup.addGridModel(out);\n this.gridModelsForLine.set(lineid, out);\n }\n return out;\n }\n\n /**\n * Gets the BeatColDAG for a specific layout parameter ID, creating one if it doesn't exist.\n * @param lpid The layout parameter ID\n * @returns The BeatColDAG for the layout parameters\n */\n protected beatColDAGForLP(lpid: LPID): BeatColDAG {\n let out = this.beatColDAGsByLP.get(lpid) || null;\n if (!out) {\n out = new BeatColDAG(this.gridLayoutGroup);\n this.beatColDAGsByLP.set(lpid, out);\n }\n return out;\n }\n\n /**\n * Adds a line to the beat layout.\n * This ensures that a line is broken down into beats and added into a dedicated GridModel.\n *\n * A line must also be given the layout params by which the beat breakdown will happen.\n * This LayoutParams object does not have to be unique per line (this non-constraint allows\n * beats to be aligned across lines).\n *\n * @param line The line to add\n */\n addLine(line: Line): void {\n const gridModel = this.getGridModelForLine(line.uuid) as GridModel;\n gridModel.eventHub?.startBatchMode();\n this.lineToRoleBeats(line, gridModel);\n gridModel.eventHub?.commitBatch();\n }\n\n /**\n * Converts a line into a series of beats for each role.\n * @param line The line to convert\n * @param gridModel The grid model to use\n * @returns Arrays of beats for each role\n */\n protected lineToRoleBeats(line: Line, gridModel: GridModel): Beat[][] {\n const lp = line.layoutParams;\n const roleBeats = [] as Beat[][];\n this.roleBeatsForLine.set(line.uuid, roleBeats);\n const lineOffset = line.offset.divbyNum(lp.beatDuration);\n for (const role of line.roles) {\n const bb = new BeatsBuilder(role, lp, lineOffset, ...role.atoms);\n roleBeats.push(bb.beats);\n\n // Add these to the beat layout too\n for (const beat of bb.beats) {\n // beat.ensureUniformSpaces(layoutParams.beatDuration);\n this.addBeat(beat, gridModel);\n }\n }\n return roleBeats;\n }\n\n /**\n * Adds a beat to the layout.\n * @param beat The beat to add\n * @param gridModel The grid model to add the beat to\n * @returns The grid cell containing the beat\n */\n protected addBeat(beat: Beat, gridModel: GridModel): GridCell {\n // Get the beat column at this index (and line) and add to it.\n const line = beat.role.line;\n const lp = line.layoutParams;\n const beatColDAG = this.beatColDAGForLP(lp.uuid);\n const [layoutLine, layoutColumn, rowOffset] = lp.getBeatLocation(beat);\n const colEnd = rowOffset.plus(beat.duration, true);\n const bcol = beatColDAG.getBeatColumn(rowOffset, colEnd, 0);\n\n // Since a beat's column has a \"pre\" and \"post\" col to, each\n // beat has 3 columns for it\n const roleIndex = beat.role.line.indexOfRole(beat.role.name);\n const nthLine = Math.floor(beat.index / lp.totalBeats);\n const realLine = lp.lineBreaks.length * nthLine + layoutLine;\n const realRow = line.roles.length * realLine + roleIndex;\n // pre marker goes on realCol - 1, post marker goes on realCol + 1\n const realCol = 1 + layoutColumn * 3;\n const preMarkers = beat.preMarkers;\n if (preMarkers.length > 0) {\n const val = {\n beat: beat,\n markers: preMarkers,\n };\n const precol = beatColDAG.getBeatColumn(rowOffset, colEnd, -1);\n gridModel.setValue(realRow, realCol - 1, val, (gridRow: GridRow, col: number) => {\n const cell = new GridCell(gridRow, col);\n cell.colAlign = precol;\n return cell;\n });\n }\n const postMarkers = beat.postMarkers;\n if (postMarkers.length > 0) {\n const val = {\n beat: beat,\n markers: postMarkers,\n };\n const postcol = beatColDAG.getBeatColumn(rowOffset, colEnd, 1);\n gridModel.setValue(realRow, realCol + 1, val, (gridRow: GridRow, col: number) => {\n const cell = new GridCell(gridRow, col);\n cell.colAlign = postcol;\n return cell;\n });\n }\n return gridModel.setValue(realRow, realCol, beat, (gridRow: GridRow, col: number) => {\n const cell = new GridCell(gridRow, col);\n cell.colAlign = bcol;\n return cell;\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"beats.js","sourceRoot":"","sources":["../../src/beats.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { AtomType, Marker, Group, Line, Atom, Space, Role } from \"./\";\nimport { CycleIterator, CyclePosition } from \"./cycle\";\nimport { WindowIterator } from \"./iterators\";\nimport { LayoutParams } from \"./layouts\";\nimport { GridModel, GridRow, GridCell, ColAlign, GridLayoutGroup } from \"./grids\";\nimport { Block, BlockItem, isLine, isBlock } from \"./notation\";\n\ntype Fraction = TSU.Num.Fraction;\nconst ZERO = TSU.Num.Fraction.ZERO;\nconst ONE = TSU.Num.Fraction.ONE;\n\n/**\n * Represents a single beat in the notation.\n * A beat contains one or more atoms and has a specific position in a bar.\n */\nexport class Beat {\n private static idCounter = 0;\n readonly uuid = Beat.idCounter++;\n // Should this be as flat Atoms or should we keep it as atoms and breakdown later?\n\n /** The atom contained in this beat */\n atom: Atom;\n protected atomIsPlaceholder = false;\n\n /**\n * Creates a new Beat.\n * @param index The index of this beat in the sequence\n * @param role The role this beat belongs to\n * @param offset The time offset of this beat from the start\n * @param duration The duration of this beat\n * @param barIndex The index of the bar containing this beat\n * @param beatIndex The index of this beat within its bar\n * @param instance The instance number of this beat\n * @param prevBeat The previous beat in the sequence, if any\n * @param nextBeat The next beat in the sequence, if any\n */\n constructor(\n public readonly index: number,\n public readonly role: Role,\n public readonly offset: Fraction,\n public readonly duration: Fraction,\n public readonly barIndex: number,\n public readonly beatIndex: number,\n public readonly instance: number,\n public readonly prevBeat: null | Beat,\n public nextBeat: null | Beat,\n ) {}\n\n /**\n * Returns a debug-friendly representation of this Beat.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return {\n index: this.index,\n role: this.role.name,\n offset: this.offset.toString(),\n duration: this.duration.toString(),\n barIndex: this.barIndex,\n beatIndex: this.beatIndex,\n instance: this.instance,\n atom: this.atom.debugValue(),\n };\n }\n\n /**\n * Gets the end offset of this beat (offset + duration).\n */\n get endOffset(): Fraction {\n return this.offset.plus(this.duration);\n }\n\n /**\n * Checks if this beat is filled completely (no remaining space).\n */\n get filled(): boolean {\n return this.remaining.isZero;\n }\n\n /**\n * Gets the remaining duration available in this beat.\n */\n get remaining(): Fraction {\n return this.atom ? this.duration.minus(this.atom.duration, true) : this.duration;\n }\n\n /**\n * Adds an atom to this beat.\n * @param atom The atom to add\n * @returns True if the atom was added successfully, false if there's not enough space\n */\n add(atom: Atom): boolean {\n if (this.remaining.cmp(atom.duration) < 0) {\n return false;\n }\n if (!this.atom) {\n this.atom = atom;\n } else {\n if (!this.atomIsPlaceholder) {\n this.atomIsPlaceholder = true;\n this.atom = new Group(this.atom).setDuration(ONE, true);\n }\n (this.atom as Group).addAtoms(true, atom);\n }\n return true;\n }\n\n /**\n * Gets all markers that should be displayed before this beat.\n * @returns An array of Marker objects\n */\n get preMarkers(): Marker[] {\n const out = [] as Marker[];\n let curr: Atom | null = this.atom;\n while (curr != null) {\n for (const marker of curr.markersBefore || []) {\n out.push(marker);\n }\n if (curr.TYPE == AtomType.GROUP) {\n curr = (curr as Group).atoms.first;\n } else {\n curr = null;\n }\n }\n return out;\n }\n\n /**\n * Gets all markers that should be displayed after this beat.\n * @returns An array of Marker objects\n */\n get postMarkers(): Marker[] {\n const out = [] as Marker[];\n let curr: Atom | null = this.atom;\n while (curr != null) {\n out.splice(0, 0, ...(curr.markersAfter || []));\n if (curr.TYPE == AtomType.GROUP) {\n curr = (curr as Group).atoms.last;\n } else {\n curr = null;\n }\n }\n return out;\n }\n}\n\n/**\n * Builds a sequence of beats from atoms according to layout parameters.\n * Used to convert a flat sequence of atoms into structured beats for display.\n */\nexport class BeatsBuilder {\n /** All atoms divided into beats */\n readonly beats: Beat[] = [];\n readonly startIndex: number;\n readonly beatOffset: Fraction;\n cycleIter: CycleIterator;\n windowIter: WindowIterator;\n\n /** Callback for when an atom is added to this role */\n onAtomAdded: (atom: Atom, beat: Beat) => void;\n\n /** Callback for when a new beat is added */\n onBeatAdded: (beat: Beat) => void;\n\n /** Callback for when a beat has been filled */\n onBeatFilled: (beat: Beat) => void;\n\n /**\n * Creates a new BeatsBuilder.\n * @param role The role containing the atoms\n * @param layoutParams Layout parameters for structuring beats\n * @param startOffset The starting offset for the first beat, defaults to ZERO\n * @param atoms Initial atoms to add to the beats\n */\n constructor(\n public readonly role: Role,\n public readonly layoutParams: LayoutParams,\n public readonly startOffset: Fraction = ZERO,\n ...atoms: Atom[]\n ) {\n const [, [bar, beat, instance], beatOffset, index] = layoutParams.cycle.getPosition(startOffset);\n this.cycleIter = layoutParams.cycle.iterateBeats(bar, beat, instance);\n this.windowIter = new WindowIterator();\n this.beatOffset = beatOffset;\n\n // evaluate the start beatindex - typically it would be 0 if things start\n // at beginning of a cycle. But if the start offset is < 0 then the\n // startIndex should also shift accordingly\n this.startIndex = index;\n this.addAtoms(...atoms);\n }\n\n /**\n * Adds atoms to be processed into beats.\n * @param atoms The atoms to add\n */\n addAtoms(...atoms: Atom[]): void {\n // First add all atoms to the atom Iterator so we can\n // fetch them as FlatAtoms. This is needed because atoms\n // passed here could be unflatted (via groups) or much larger\n // than what can fit in the given role/bar etc. So this\n // flattening and windowing is needed before we add them\n // to the views - and this is done by the durationIterators.\n this.windowIter.push(...atoms);\n while (this.windowIter.hasMore) {\n // get the last/current row and add a new one if it is full\n let currBeat = this.beats[this.beats.length - 1];\n\n // First add a row if last row is filled\n if (this.beats.length == 0 || currBeat.filled) {\n // what should be the beatlengths be here?\n currBeat = this.addBeat();\n }\n\n // For this beat get symbols in all roles\n const [remAtoms, filled] = this.windowIter.get(currBeat.remaining);\n TSU.assert(remAtoms.length > 0, \"Atleast one element should have been available here\");\n // render the atoms now\n for (const atom of remAtoms) {\n // console.log(\"Adding FA: \", flatAtom.debugValue(), flatAtom.atom);\n TSU.assert(currBeat.add(atom), \"Should return true as we are already using a duration iterator here\");\n if (this.onAtomAdded) this.onAtomAdded(atom, currBeat);\n }\n if (currBeat.filled) {\n if (this.onBeatFilled) this.onBeatFilled(currBeat);\n }\n }\n }\n\n /**\n * Adds a new beat to the sequence.\n * @returns The newly created beat\n */\n protected addBeat(): Beat {\n const numBeats = this.beats.length;\n const lastBeat = numBeats == 0 ? null : this.beats[numBeats - 1];\n const nextCP: [CyclePosition, Fraction] = this.cycleIter.next().value;\n const apb = this.layoutParams.beatDuration;\n const newBeat = new Beat(\n lastBeat == null ? this.startIndex : lastBeat.index + 1,\n this.role,\n lastBeat == null ? this.startOffset.minus(this.beatOffset).timesNum(apb, true) : lastBeat.endOffset,\n nextCP[1].timesNum(apb),\n nextCP[0][0],\n nextCP[0][1],\n nextCP[0][2],\n lastBeat,\n null,\n );\n if (lastBeat == null && this.beatOffset.isGT(ZERO)) {\n // Add spaces to fill up empty beats\n newBeat.add(new Space(this.beatOffset.timesNum(apb)));\n }\n if (lastBeat) lastBeat.nextBeat = newBeat;\n this.beats.push(newBeat);\n if (this.onBeatAdded) this.onBeatAdded(newBeat);\n return newBeat;\n }\n}\n\n/**\n * Represents a column of beats in a layout grid.\n * Used for aligning beats vertically in the notation.\n */\nexport class BeatColumn extends ColAlign {\n /** Spacing between atoms in this column */\n atomSpacing = 5;\n /** Unique key for this column */\n readonly key: string;\n\n /**\n * Creates a new BeatColumn.\n * @param offset The starting offset of this column\n * @param endOffset The ending offset of this column\n * @param markerType The type of marker for this column (negative: before, positive: after, zero: normal)\n */\n constructor(\n public readonly offset: Fraction,\n public readonly endOffset: Fraction,\n public readonly markerType: number,\n ) {\n super();\n offset = offset.factorized;\n endOffset = endOffset.factorized;\n this.key = BeatColumn.keyFor(offset, endOffset, markerType);\n }\n\n /**\n * Generates a key for identifying columns with the same offsets and marker type.\n * @param offset The starting offset\n * @param endOffset The ending offset\n * @param markerType The type of marker (negative: before, positive: after, zero: normal)\n * @returns A string key\n */\n static keyFor(offset: Fraction, endOffset: Fraction, markerType = 0): string {\n offset = offset.factorized;\n endOffset = endOffset.factorized;\n if (markerType < 0) {\n // return the column for the marker \"before\" this col\n // int his case only the \"start offset\" is needed and length doesnt matter\n return \":\" + offset.toString();\n } else if (markerType > 0) {\n // return the column for the marker \"after\" this col\n // in this case only thd end offset matters\n return endOffset.toString() + \":\";\n } else {\n return offset.toString() + \":\" + endOffset.toString();\n }\n }\n}\n\n/**\n * Manages the organization of beats into columns based on their offsets.\n * Used to create a directed acyclic graph (DAG) of beat columns for layout purposes.\n *\n * Grouping of beats by their column based on the layout params.\n * The confusion is we have beats broken up and saved in columns\n * but we are loosing how a line is supposed to access it in its own way\n * we have beatsByRole for getting all beats for a role (in a line)\n * sequentially we have beatColumns for getting all beats in a particular\n * column across all lines and roles globally.\n *\n * What we want here is for a given line get all roles, their beats\n * in zipped way. eg for a Line with 3 roles and say 10 beats each\n * (with the breaks of 4, 1) we need:\n *\n * R1 B1 R1 B2 R1 B3 R1 B4\n * R2 B1 R2 B2 R2 B3 R2 B4\n * R3 B1 R3 B2 R3 B3 R3 B4\n *\n * R1 B5\n * R2 B5\n * R3 B5\n *\n * R1 B6 R1 B7 R1 B8 R1 B9\n * R2 B6 R2 B7 R2 B8 R2 B9\n * R3 B6 R3 B7 R3 B8 R3 B9\n *\n * R1 B10\n * R2 B10\n * R3 B10\n *\n *\n * Here we have 5 distinct beat columns:\n *\n * 1: R1B1, R2B1, R3B1, R1B6, R2B6, R3B6,\n * 2: R1B2, R2B2, R3B2, R1B7, R2B7, R3B7,\n * 3: R1B3, R2B3, R3B3, R1B8, R2B8, R3B8,\n * 4: R1B4, R2B4, R3B4, R1B9, R2B9, R3B9,\n * 5: R1B5, R2B5, R3B5, R1B10, R2B10, R3B10,\n *\n */\nexport class BeatColDAG {\n /** Map of column keys to BeatColumn objects */\n beatColumns = new Map<string, BeatColumn>();\n\n /**\n * Creates a new BeatColDAG.\n * @param layoutGroup The layout group to associate with this DAG\n */\n constructor(public readonly layoutGroup: GridLayoutGroup) {\n //\n }\n\n /**\n * Gets the beat column for a given duration at the specified offset.\n * Creates a new column if none exists.\n * @param offset The starting offset\n * @param endOffset The ending offset\n * @param markerType The type of marker\n * @returns The BeatColumn for the specified parameters\n */\n getBeatColumn(offset: Fraction, endOffset: Fraction, markerType = 0): BeatColumn {\n const [bcol, newcreated] = this.ensureBeatColumn(offset, endOffset, markerType);\n if (newcreated) {\n if (markerType == 0) {\n const [prevcol] = this.ensureBeatColumn(offset, endOffset, -1);\n const [nextcol] = this.ensureBeatColumn(offset, endOffset, 1);\n prevcol.addSuccessor(bcol);\n bcol.addSuccessor(nextcol);\n for (const other of this.beatColumns.values()) {\n // only join the \"marker\" columns\n if (other.markerType == -1 && endOffset.equals(other.offset)) {\n // our next col is a preecessor of other\n nextcol.addSuccessor(other);\n } else if (other.markerType == 1 && other.endOffset.equals(offset)) {\n // our prev col is a predecessor of other\n other.addSuccessor(prevcol);\n }\n }\n }\n }\n return bcol;\n }\n\n /**\n * Ensures a beat column exists for the given parameters.\n * @param offset The starting offset\n * @param endOffset The ending offset\n * @param markerType The type of marker\n * @returns A tuple containing the column and whether it was newly created\n */\n protected ensureBeatColumn(offset: Fraction, endOffset: Fraction, markerType = 0): [BeatColumn, boolean] {\n const key = BeatColumn.keyFor(offset, endOffset, markerType);\n let bcol = this.beatColumns.get(key) || null;\n const newcreated = bcol == null;\n if (!bcol) {\n bcol = new BeatColumn(offset, endOffset, markerType);\n this.beatColumns.set(key, bcol);\n }\n return [bcol, newcreated];\n }\n}\n\n/** Type alias for line IDs */\ntype LineId = number;\n/** Type alias for layout parameter IDs */\ntype LPID = number;\n\n/**\n * Manages the beat layouts for all lines in a notation.\n * Handles the creation of grid models, positioning of beats, and alignment of beats across lines.\n */\nexport class GlobalBeatLayout {\n /** Map of line IDs to grid models */\n gridModelsForLine = new Map<LineId, GridModel>();\n /** Map of line IDs to arrays of beats for each role */\n roleBeatsForLine = new Map<LineId, Beat[][]>();\n /** Map of layout parameter IDs to beat column DAGs */\n beatColDAGsByLP = new Map<LPID, BeatColDAG>();\n /** The global layout group for all grid models */\n readonly gridLayoutGroup: GridLayoutGroup;\n\n /**\n * Creates a new GlobalBeatLayout.\n * @param sharedGridLayoutGroup Optional shared GridLayoutGroup for column alignment across multiple views.\n * If not provided, a new GridLayoutGroup is created internally.\n */\n constructor(sharedGridLayoutGroup?: GridLayoutGroup) {\n this.gridLayoutGroup = sharedGridLayoutGroup ?? new GridLayoutGroup();\n }\n\n /**\n * Gets the GridModel associated with a particular line, creating one if it doesn't exist.\n * @param lineid The ID of the line\n * @returns The GridModel for the line\n */\n getGridModelForLine(lineid: LineId): GridModel {\n let out = this.gridModelsForLine.get(lineid) || null;\n if (!out) {\n out = new GridModel();\n this.gridLayoutGroup.addGridModel(out);\n this.gridModelsForLine.set(lineid, out);\n }\n return out;\n }\n\n /**\n * Gets the BeatColDAG for a specific layout parameter ID, creating one if it doesn't exist.\n * @param lpid The layout parameter ID\n * @returns The BeatColDAG for the layout parameters\n */\n protected beatColDAGForLP(lpid: LPID): BeatColDAG {\n let out = this.beatColDAGsByLP.get(lpid) || null;\n if (!out) {\n out = new BeatColDAG(this.gridLayoutGroup);\n this.beatColDAGsByLP.set(lpid, out);\n }\n return out;\n }\n\n /**\n * Adds a line to the beat layout.\n * This ensures that a line is broken down into beats and added into a dedicated GridModel.\n *\n * A line must also be given the layout params by which the beat breakdown will happen.\n * This LayoutParams object does not have to be unique per line (this non-constraint allows\n * beats to be aligned across lines).\n *\n * @param line The line to add\n */\n addLine(line: Line): void {\n const gridModel = this.getGridModelForLine(line.uuid) as GridModel;\n gridModel.eventHub?.startBatchMode();\n this.lineToRoleBeats(line, gridModel);\n gridModel.eventHub?.commitBatch();\n }\n\n /**\n * Recursively processes a block and its children to build beat layouts.\n * Uses block.children() to get expanded children (e.g., RepeatBlock expands to N copies).\n *\n * @param block The block to process\n */\n processBlock(block: Block): void {\n for (const child of block.children()) {\n this.processBlockItem(child);\n }\n }\n\n /**\n * Processes a single block item (Block, Line, or RawBlock).\n *\n * @param item The item to process\n */\n protected processBlockItem(item: BlockItem): void {\n if (isLine(item)) {\n const line = item as Line;\n if (!line.isEmpty && line.layoutParams != null) {\n this.addLine(line);\n }\n } else if (isBlock(item)) {\n this.processBlock(item as Block);\n }\n // RawBlocks are ignored (no beat layout for raw content)\n }\n\n /**\n * Converts a line into a series of beats for each role.\n * @param line The line to convert\n * @param gridModel The grid model to use\n * @returns Arrays of beats for each role\n */\n protected lineToRoleBeats(line: Line, gridModel: GridModel): Beat[][] {\n const lp = line.layoutParams;\n const roleBeats = [] as Beat[][];\n this.roleBeatsForLine.set(line.uuid, roleBeats);\n const lineOffset = line.offset.divbyNum(lp.beatDuration);\n for (const role of line.roles) {\n const bb = new BeatsBuilder(role, lp, lineOffset, ...role.atoms);\n roleBeats.push(bb.beats);\n\n // Add these to the beat layout too\n for (const beat of bb.beats) {\n // beat.ensureUniformSpaces(layoutParams.beatDuration);\n this.addBeat(beat, gridModel);\n }\n }\n return roleBeats;\n }\n\n /**\n * Adds a beat to the layout.\n * @param beat The beat to add\n * @param gridModel The grid model to add the beat to\n * @returns The grid cell containing the beat\n */\n protected addBeat(beat: Beat, gridModel: GridModel): GridCell {\n // Get the beat column at this index (and line) and add to it.\n const line = beat.role.line;\n const lp = line.layoutParams;\n const beatColDAG = this.beatColDAGForLP(lp.uuid);\n const [layoutLine, layoutColumn, rowOffset] = lp.getBeatLocation(beat);\n const colEnd = rowOffset.plus(beat.duration, true);\n const bcol = beatColDAG.getBeatColumn(rowOffset, colEnd, 0);\n\n // Since a beat's column has a \"pre\" and \"post\" col to, each\n // beat has 3 columns for it\n const roleIndex = beat.role.line.indexOfRole(beat.role.name);\n const nthLine = Math.floor(beat.index / lp.totalBeats);\n const realLine = lp.lineBreaks.length * nthLine + layoutLine;\n const realRow = line.roles.length * realLine + roleIndex;\n // pre marker goes on realCol - 1, post marker goes on realCol + 1\n const realCol = 1 + layoutColumn * 3;\n const preMarkers = beat.preMarkers;\n if (preMarkers.length > 0) {\n const val = {\n beat: beat,\n markers: preMarkers,\n };\n const precol = beatColDAG.getBeatColumn(rowOffset, colEnd, -1);\n gridModel.setValue(realRow, realCol - 1, val, (gridRow: GridRow, col: number) => {\n const cell = new GridCell(gridRow, col);\n cell.colAlign = precol;\n return cell;\n });\n }\n const postMarkers = beat.postMarkers;\n if (postMarkers.length > 0) {\n const val = {\n beat: beat,\n markers: postMarkers,\n };\n const postcol = beatColDAG.getBeatColumn(rowOffset, colEnd, 1);\n gridModel.setValue(realRow, realCol + 1, val, (gridRow: GridRow, col: number) => {\n const cell = new GridCell(gridRow, col);\n cell.colAlign = postcol;\n return cell;\n });\n }\n return gridModel.setValue(realRow, realCol, beat, (gridRow: GridRow, col: number) => {\n const cell = new GridCell(gridRow, col);\n cell.colAlign = bcol;\n return cell;\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as TSU from "@panyam/tsutils";
|
|
2
|
+
import { Entity } from "./entity";
|
|
3
|
+
import { Cycle } from "./cycle";
|
|
4
|
+
import { Line } from "./core";
|
|
5
|
+
export declare class RoleDef {
|
|
6
|
+
name: string;
|
|
7
|
+
notesOnly: boolean;
|
|
8
|
+
index: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class RawBlock extends Entity {
|
|
11
|
+
content: string;
|
|
12
|
+
contentType: string;
|
|
13
|
+
readonly TYPE: string;
|
|
14
|
+
constructor(content: string, contentType?: string);
|
|
15
|
+
debugValue(): any;
|
|
16
|
+
}
|
|
17
|
+
export type BlockItem = Block | Line | RawBlock;
|
|
18
|
+
export declare function isBlock(item: BlockItem): item is Block;
|
|
19
|
+
export declare function isLine(item: BlockItem): item is Line;
|
|
20
|
+
export declare function isRawBlock(item: BlockItem): item is RawBlock;
|
|
21
|
+
export declare class Block extends Entity {
|
|
22
|
+
readonly TYPE: string;
|
|
23
|
+
readonly blockType: string;
|
|
24
|
+
readonly name: TSU.Nullable<string>;
|
|
25
|
+
readonly blockItems: BlockItem[];
|
|
26
|
+
localCycle: TSU.Nullable<Cycle>;
|
|
27
|
+
localAtomsPerBeat: TSU.Nullable<number>;
|
|
28
|
+
localBreaks: TSU.Nullable<number[]>;
|
|
29
|
+
readonly localRoles: Map<string, RoleDef>;
|
|
30
|
+
private _parentBlock;
|
|
31
|
+
protected _currRoleDef: TSU.Nullable<RoleDef>;
|
|
32
|
+
protected _currentLine: TSU.Nullable<Line>;
|
|
33
|
+
constructor(blockType: string, parent?: TSU.Nullable<Block>, name?: TSU.Nullable<string>);
|
|
34
|
+
children(): BlockItem[];
|
|
35
|
+
get parentBlock(): TSU.Nullable<Block>;
|
|
36
|
+
get cycle(): TSU.Nullable<Cycle>;
|
|
37
|
+
get atomsPerBeat(): number;
|
|
38
|
+
get breaks(): number[];
|
|
39
|
+
getRole(name: string): TSU.Nullable<RoleDef>;
|
|
40
|
+
get currRoleDef(): TSU.Nullable<RoleDef>;
|
|
41
|
+
setCurrRole(name: string): void;
|
|
42
|
+
get currentLine(): Line;
|
|
43
|
+
newLine(): Line;
|
|
44
|
+
newRoleDef(name: string, notesOnly?: boolean): RoleDef;
|
|
45
|
+
addBlockItem(item: BlockItem): void;
|
|
46
|
+
removeBlockItem(item: BlockItem): number;
|
|
47
|
+
debugValue(): any;
|
|
48
|
+
}
|
|
49
|
+
export declare function findContainingBlock(entity: Entity): TSU.Nullable<Block>;
|
|
50
|
+
export declare class SectionBlock extends Block {
|
|
51
|
+
constructor(sectionName: string, parent?: TSU.Nullable<Block>);
|
|
52
|
+
children(): BlockItem[];
|
|
53
|
+
}
|
|
54
|
+
export declare class RepeatBlock extends Block {
|
|
55
|
+
readonly repeatCount: number;
|
|
56
|
+
constructor(repeatCount: number, parent?: TSU.Nullable<Block>);
|
|
57
|
+
children(): BlockItem[];
|
|
58
|
+
}
|
|
59
|
+
export declare class CycleBlock extends Block {
|
|
60
|
+
constructor(cycle: Cycle, parent?: TSU.Nullable<Block>);
|
|
61
|
+
}
|
|
62
|
+
export declare class BeatDurationBlock extends Block {
|
|
63
|
+
constructor(atomsPerBeat: number, parent?: TSU.Nullable<Block>);
|
|
64
|
+
}
|
|
65
|
+
export declare class BreaksBlock extends Block {
|
|
66
|
+
constructor(breaks: number[], parent?: TSU.Nullable<Block>);
|
|
67
|
+
}
|
|
68
|
+
export declare class RoleBlock extends Block {
|
|
69
|
+
constructor(roleName: string, notesOnly: boolean, parent?: TSU.Nullable<Block>);
|
|
70
|
+
}
|
|
71
|
+
export declare class GroupBlock extends Block {
|
|
72
|
+
constructor(groupName: string | null, parent?: TSU.Nullable<Block>);
|
|
73
|
+
}
|
package/lib/cjs/block.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GroupBlock = exports.RoleBlock = exports.BreaksBlock = exports.BeatDurationBlock = exports.CycleBlock = exports.RepeatBlock = exports.SectionBlock = exports.Block = exports.RawBlock = exports.RoleDef = void 0;
|
|
4
|
+
exports.isBlock = isBlock;
|
|
5
|
+
exports.isLine = isLine;
|
|
6
|
+
exports.isRawBlock = isRawBlock;
|
|
7
|
+
exports.findContainingBlock = findContainingBlock;
|
|
8
|
+
const entity_1 = require("./entity");
|
|
9
|
+
const core_1 = require("./core");
|
|
10
|
+
class RoleDef {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.name = "";
|
|
13
|
+
this.notesOnly = false;
|
|
14
|
+
this.index = 0;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.RoleDef = RoleDef;
|
|
18
|
+
class RawBlock extends entity_1.Entity {
|
|
19
|
+
constructor(content, contentType = "md") {
|
|
20
|
+
super();
|
|
21
|
+
this.content = content;
|
|
22
|
+
this.contentType = contentType;
|
|
23
|
+
this.TYPE = "RawBlock";
|
|
24
|
+
}
|
|
25
|
+
debugValue() {
|
|
26
|
+
return Object.assign(Object.assign({}, super.debugValue()), { content: this.content, contentType: this.contentType });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.RawBlock = RawBlock;
|
|
30
|
+
function isBlock(item) {
|
|
31
|
+
return item.TYPE === "Block";
|
|
32
|
+
}
|
|
33
|
+
function isLine(item) {
|
|
34
|
+
return item.TYPE === "Line";
|
|
35
|
+
}
|
|
36
|
+
function isRawBlock(item) {
|
|
37
|
+
return item.TYPE === "RawBlock";
|
|
38
|
+
}
|
|
39
|
+
class Block extends entity_1.Entity {
|
|
40
|
+
constructor(blockType, parent = null, name = null) {
|
|
41
|
+
super();
|
|
42
|
+
this.TYPE = "Block";
|
|
43
|
+
this.blockItems = [];
|
|
44
|
+
this.localCycle = null;
|
|
45
|
+
this.localAtomsPerBeat = null;
|
|
46
|
+
this.localBreaks = null;
|
|
47
|
+
this.localRoles = new Map();
|
|
48
|
+
this._parentBlock = null;
|
|
49
|
+
this._currRoleDef = null;
|
|
50
|
+
this._currentLine = null;
|
|
51
|
+
this.blockType = blockType;
|
|
52
|
+
this.name = name;
|
|
53
|
+
this._parentBlock = parent;
|
|
54
|
+
if (parent) {
|
|
55
|
+
this.setParent(parent);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
children() {
|
|
59
|
+
return this.blockItems;
|
|
60
|
+
}
|
|
61
|
+
get parentBlock() {
|
|
62
|
+
return this._parentBlock;
|
|
63
|
+
}
|
|
64
|
+
get cycle() {
|
|
65
|
+
var _a, _b;
|
|
66
|
+
if (this.localCycle !== null) {
|
|
67
|
+
return this.localCycle;
|
|
68
|
+
}
|
|
69
|
+
return (_b = (_a = this.parentBlock) === null || _a === void 0 ? void 0 : _a.cycle) !== null && _b !== void 0 ? _b : null;
|
|
70
|
+
}
|
|
71
|
+
get atomsPerBeat() {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
if (this.localAtomsPerBeat !== null) {
|
|
74
|
+
return this.localAtomsPerBeat;
|
|
75
|
+
}
|
|
76
|
+
return (_b = (_a = this.parentBlock) === null || _a === void 0 ? void 0 : _a.atomsPerBeat) !== null && _b !== void 0 ? _b : 1;
|
|
77
|
+
}
|
|
78
|
+
get breaks() {
|
|
79
|
+
var _a, _b;
|
|
80
|
+
if (this.localBreaks !== null) {
|
|
81
|
+
return this.localBreaks;
|
|
82
|
+
}
|
|
83
|
+
return (_b = (_a = this.parentBlock) === null || _a === void 0 ? void 0 : _a.breaks) !== null && _b !== void 0 ? _b : [];
|
|
84
|
+
}
|
|
85
|
+
getRole(name) {
|
|
86
|
+
var _a, _b;
|
|
87
|
+
const local = this.localRoles.get(name.toLowerCase());
|
|
88
|
+
if (local) {
|
|
89
|
+
return local;
|
|
90
|
+
}
|
|
91
|
+
return (_b = (_a = this.parentBlock) === null || _a === void 0 ? void 0 : _a.getRole(name)) !== null && _b !== void 0 ? _b : null;
|
|
92
|
+
}
|
|
93
|
+
get currRoleDef() {
|
|
94
|
+
if (this._currRoleDef !== null) {
|
|
95
|
+
return this._currRoleDef;
|
|
96
|
+
}
|
|
97
|
+
if (this.parentBlock) {
|
|
98
|
+
return this.parentBlock.currRoleDef;
|
|
99
|
+
}
|
|
100
|
+
const roles = Array.from(this.localRoles.values());
|
|
101
|
+
return roles.length > 0 ? roles[roles.length - 1] : null;
|
|
102
|
+
}
|
|
103
|
+
setCurrRole(name) {
|
|
104
|
+
name = name.trim().toLowerCase();
|
|
105
|
+
if (name === "") {
|
|
106
|
+
throw new Error("Role name cannot be empty");
|
|
107
|
+
}
|
|
108
|
+
let roleDef = this.getRole(name);
|
|
109
|
+
if (roleDef == null) {
|
|
110
|
+
roleDef = this.newRoleDef(name, name === "sw");
|
|
111
|
+
}
|
|
112
|
+
this._currRoleDef = roleDef;
|
|
113
|
+
}
|
|
114
|
+
get currentLine() {
|
|
115
|
+
if (this._currentLine === null) {
|
|
116
|
+
return this.newLine();
|
|
117
|
+
}
|
|
118
|
+
return this._currentLine;
|
|
119
|
+
}
|
|
120
|
+
newLine() {
|
|
121
|
+
if (this._currentLine !== null && this._currentLine.isEmpty) {
|
|
122
|
+
this.removeBlockItem(this._currentLine);
|
|
123
|
+
}
|
|
124
|
+
this._currentLine = new core_1.Line();
|
|
125
|
+
this.addBlockItem(this._currentLine);
|
|
126
|
+
return this._currentLine;
|
|
127
|
+
}
|
|
128
|
+
newRoleDef(name, notesOnly = false) {
|
|
129
|
+
name = name.trim().toLowerCase();
|
|
130
|
+
if (name === "") {
|
|
131
|
+
throw new Error("Role name cannot be empty");
|
|
132
|
+
}
|
|
133
|
+
if (this.localRoles.has(name)) {
|
|
134
|
+
throw new Error(`Role '${name}' already exists in this block`);
|
|
135
|
+
}
|
|
136
|
+
const rd = new RoleDef();
|
|
137
|
+
rd.name = name;
|
|
138
|
+
rd.notesOnly = notesOnly;
|
|
139
|
+
rd.index = this.localRoles.size;
|
|
140
|
+
this.localRoles.set(name, rd);
|
|
141
|
+
return rd;
|
|
142
|
+
}
|
|
143
|
+
addBlockItem(item) {
|
|
144
|
+
item.setParent(this);
|
|
145
|
+
this.blockItems.push(item);
|
|
146
|
+
}
|
|
147
|
+
removeBlockItem(item) {
|
|
148
|
+
const index = this.blockItems.indexOf(item);
|
|
149
|
+
if (index >= 0) {
|
|
150
|
+
this.blockItems.splice(index, 1);
|
|
151
|
+
item.setParent(null);
|
|
152
|
+
}
|
|
153
|
+
return index;
|
|
154
|
+
}
|
|
155
|
+
debugValue() {
|
|
156
|
+
const out = Object.assign(Object.assign({}, super.debugValue()), { blockType: this.blockType, blockItems: this.blockItems.map((c) => c.debugValue()) });
|
|
157
|
+
if (this.name) {
|
|
158
|
+
out.name = this.name;
|
|
159
|
+
}
|
|
160
|
+
if (this.localCycle) {
|
|
161
|
+
out.localCycle = this.localCycle.uuid;
|
|
162
|
+
}
|
|
163
|
+
if (this.localAtomsPerBeat !== null) {
|
|
164
|
+
out.localAtomsPerBeat = this.localAtomsPerBeat;
|
|
165
|
+
}
|
|
166
|
+
if (this.localBreaks !== null) {
|
|
167
|
+
out.localBreaks = this.localBreaks;
|
|
168
|
+
}
|
|
169
|
+
if (this.localRoles.size > 0) {
|
|
170
|
+
out.localRoles = Array.from(this.localRoles.keys());
|
|
171
|
+
}
|
|
172
|
+
return out;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
exports.Block = Block;
|
|
176
|
+
function findContainingBlock(entity) {
|
|
177
|
+
let current = entity.parent;
|
|
178
|
+
while (current !== null) {
|
|
179
|
+
if (current instanceof Block) {
|
|
180
|
+
return current;
|
|
181
|
+
}
|
|
182
|
+
current = current.parent;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
class SectionBlock extends Block {
|
|
187
|
+
constructor(sectionName, parent = null) {
|
|
188
|
+
super("section", parent, sectionName);
|
|
189
|
+
}
|
|
190
|
+
children() {
|
|
191
|
+
const heading = new RawBlock(`# ${this.name}`, "md");
|
|
192
|
+
return [heading, ...this.blockItems];
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
exports.SectionBlock = SectionBlock;
|
|
196
|
+
class RepeatBlock extends Block {
|
|
197
|
+
constructor(repeatCount, parent = null) {
|
|
198
|
+
super("repeat", parent);
|
|
199
|
+
this.repeatCount = repeatCount;
|
|
200
|
+
}
|
|
201
|
+
children() {
|
|
202
|
+
if (this.repeatCount <= 0) {
|
|
203
|
+
return this.blockItems;
|
|
204
|
+
}
|
|
205
|
+
const expanded = [];
|
|
206
|
+
for (let i = 0; i < this.repeatCount; i++) {
|
|
207
|
+
expanded.push(...this.blockItems);
|
|
208
|
+
}
|
|
209
|
+
return expanded;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.RepeatBlock = RepeatBlock;
|
|
213
|
+
class CycleBlock extends Block {
|
|
214
|
+
constructor(cycle, parent = null) {
|
|
215
|
+
super("cycle", parent);
|
|
216
|
+
this.localCycle = cycle;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
exports.CycleBlock = CycleBlock;
|
|
220
|
+
class BeatDurationBlock extends Block {
|
|
221
|
+
constructor(atomsPerBeat, parent = null) {
|
|
222
|
+
super("beatduration", parent);
|
|
223
|
+
this.localAtomsPerBeat = atomsPerBeat;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.BeatDurationBlock = BeatDurationBlock;
|
|
227
|
+
class BreaksBlock extends Block {
|
|
228
|
+
constructor(breaks, parent = null) {
|
|
229
|
+
super("breaks", parent);
|
|
230
|
+
this.localBreaks = breaks;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
exports.BreaksBlock = BreaksBlock;
|
|
234
|
+
class RoleBlock extends Block {
|
|
235
|
+
constructor(roleName, notesOnly, parent = null) {
|
|
236
|
+
super("role", parent);
|
|
237
|
+
this.newRoleDef(roleName, notesOnly);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.RoleBlock = RoleBlock;
|
|
241
|
+
class GroupBlock extends Block {
|
|
242
|
+
constructor(groupName, parent = null) {
|
|
243
|
+
super("group", parent, groupName);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.GroupBlock = GroupBlock;
|
|
247
|
+
//# sourceMappingURL=block.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"block.js","sourceRoot":"","sources":["../../src/block.ts"],"names":[],"mappings":"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","sourcesContent":["import * as TSU from \"@panyam/tsutils\";\nimport { Entity } from \"./entity\";\nimport { Cycle } from \"./cycle\";\nimport { Line } from \"./core\";\n\n/**\n * Definition of a role in a block context.\n * This is used for block-scoped role definitions.\n */\nexport class RoleDef {\n /** Name of the role */\n name = \"\";\n\n /** Whether this role contains only notes (true) or can also contain syllables/text (false) */\n notesOnly = false;\n\n /** Index of this role in the notation */\n index = 0;\n}\n\n/**\n * Represents a raw block of content in the notation.\n * Raw blocks can contain arbitrary content like markdown, HTML, etc.\n */\nexport class RawBlock extends Entity {\n readonly TYPE: string = \"RawBlock\";\n\n /**\n * Creates a new RawBlock.\n * @param content The content of the block\n * @param contentType The type of content (e.g., \"md\" for markdown)\n */\n constructor(\n public content: string,\n public contentType: string = \"md\",\n ) {\n super();\n }\n\n /**\n * Returns a debug-friendly representation of this raw block.\n * @returns An object containing debug information\n */\n debugValue(): any {\n return { ...super.debugValue(), content: this.content, contentType: this.contentType };\n }\n}\n\n/**\n * Union type for items that can appear in a block.\n */\nexport type BlockItem = Block | Line | RawBlock;\n\n/**\n * Type guard to check if an entity is a Block.\n */\nexport function isBlock(item: BlockItem): item is Block {\n return item.TYPE === \"Block\";\n}\n\n/**\n * Type guard to check if an entity is a Line.\n */\nexport function isLine(item: BlockItem): item is Line {\n return item.TYPE === \"Line\";\n}\n\n/**\n * Type guard to check if an entity is a RawBlock.\n */\nexport function isRawBlock(item: BlockItem): item is RawBlock {\n return item.TYPE === \"RawBlock\";\n}\n\n/**\n * Represents a scoped block created by a command with braces.\n * For example: \\section(\"Pallavi\") { ... }\n *\n * Blocks inherit properties from their parent Block and can override them locally.\n * Properties are resolved lazily by walking up the tree.\n *\n * Block = Command + Children (unified model)\n */\nexport class Block extends Entity {\n readonly TYPE: string = \"Block\";\n\n /** The type of block (e.g., \"section\", \"repeat\", \"cycle\") */\n readonly blockType: string;\n\n /** Optional name for the block (e.g., section name) */\n readonly name: TSU.Nullable<string>;\n\n /** Child items (before expansion by subclasses) */\n readonly blockItems: BlockItem[] = [];\n\n // Local properties\n localCycle: TSU.Nullable<Cycle> = null;\n localAtomsPerBeat: TSU.Nullable<number> = null;\n localBreaks: TSU.Nullable<number[]> = null;\n readonly localRoles = new Map<string, RoleDef>();\n\n // Store parent reference (Block or null for root)\n private _parentBlock: TSU.Nullable<Block> = null;\n\n // State tracking for command application (protected for Notation override)\n protected _currRoleDef: TSU.Nullable<RoleDef> = null;\n protected _currentLine: TSU.Nullable<Line> = null;\n\n /**\n * Creates a new Block.\n * @param blockType The type of block (e.g., \"section\", \"group\")\n * @param parent The parent block (null for root)\n * @param name Optional name for the block\n */\n constructor(blockType: string, parent: TSU.Nullable<Block> = null, name: TSU.Nullable<string> = null) {\n super();\n this.blockType = blockType;\n this.name = name;\n this._parentBlock = parent;\n // Also set Entity's parent for tree traversal\n if (parent) {\n this.setParent(parent);\n }\n }\n\n /**\n * Returns the expanded children for layout iteration.\n * Subclasses can override this to transform children (e.g., Repeat, Section).\n */\n children(): BlockItem[] {\n return this.blockItems;\n }\n\n /**\n * Gets the parent block.\n */\n get parentBlock(): TSU.Nullable<Block> {\n return this._parentBlock;\n }\n\n // ============================================\n // Property inheritance via tree walking\n // ============================================\n\n /**\n * Gets the effective cycle by walking up the tree.\n */\n get cycle(): TSU.Nullable<Cycle> {\n if (this.localCycle !== null) {\n return this.localCycle;\n }\n return this.parentBlock?.cycle ?? null;\n }\n\n /**\n * Gets the effective atoms per beat by walking up the tree.\n * Defaults to 1 if not set anywhere in the tree.\n */\n get atomsPerBeat(): number {\n if (this.localAtomsPerBeat !== null) {\n return this.localAtomsPerBeat;\n }\n return this.parentBlock?.atomsPerBeat ?? 1;\n }\n\n /**\n * Gets the effective line breaks by walking up the tree.\n * Defaults to empty array if not set anywhere.\n */\n get breaks(): number[] {\n if (this.localBreaks !== null) {\n return this.localBreaks;\n }\n return this.parentBlock?.breaks ?? [];\n }\n\n /**\n * Gets a role definition by name, walking up the tree if not found locally.\n * @param name The name of the role\n */\n getRole(name: string): TSU.Nullable<RoleDef> {\n const local = this.localRoles.get(name.toLowerCase());\n if (local) {\n return local;\n }\n return this.parentBlock?.getRole(name) ?? null;\n }\n\n // ============================================\n // State tracking for command application\n // ============================================\n\n /**\n * Gets the current role definition.\n * Falls back to parent's current role or the last defined role.\n */\n get currRoleDef(): TSU.Nullable<RoleDef> {\n if (this._currRoleDef !== null) {\n return this._currRoleDef;\n }\n // Fall back to parent's current role\n if (this.parentBlock) {\n return this.parentBlock.currRoleDef;\n }\n // Or use the last locally defined role\n const roles = Array.from(this.localRoles.values());\n return roles.length > 0 ? roles[roles.length - 1] : null;\n }\n\n /**\n * Sets the current role by name.\n * If the role doesn't exist, tries to create it via the root container's onMissingRole.\n * @param name The name of the role to activate\n * @throws Error if the role is not found and cannot be created\n */\n setCurrRole(name: string): void {\n name = name.trim().toLowerCase();\n if (name === \"\") {\n throw new Error(\"Role name cannot be empty\");\n }\n let roleDef = this.getRole(name);\n // If role not found, try auto-creation\n if (roleDef == null) {\n // Create the role locally in this block\n // Default: \"sw\" is notes-only, others are not\n roleDef = this.newRoleDef(name, name === \"sw\");\n }\n this._currRoleDef = roleDef;\n }\n\n /**\n * Gets the current line, creating one if needed.\n */\n get currentLine(): Line {\n if (this._currentLine === null) {\n return this.newLine();\n }\n return this._currentLine;\n }\n\n /**\n * Creates a new line in this block.\n */\n newLine(): Line {\n if (this._currentLine !== null && this._currentLine.isEmpty) {\n // Remove empty line before creating new one\n this.removeBlockItem(this._currentLine);\n }\n this._currentLine = new Line();\n this.addBlockItem(this._currentLine);\n return this._currentLine;\n }\n\n /**\n * Creates a new role definition local to this block.\n * @param name The name of the role\n * @param notesOnly Whether this role contains only notes\n */\n newRoleDef(name: string, notesOnly = false): RoleDef {\n name = name.trim().toLowerCase();\n if (name === \"\") {\n throw new Error(\"Role name cannot be empty\");\n }\n if (this.localRoles.has(name)) {\n throw new Error(`Role '${name}' already exists in this block`);\n }\n const rd = new RoleDef();\n rd.name = name;\n rd.notesOnly = notesOnly;\n rd.index = this.localRoles.size;\n this.localRoles.set(name, rd);\n return rd;\n }\n\n // ============================================\n // Child management\n // ============================================\n\n /**\n * Adds a child item to this block.\n * @param item The item to add\n */\n addBlockItem(item: BlockItem): void {\n item.setParent(this);\n this.blockItems.push(item);\n }\n\n /**\n * Removes a child item from this block.\n * @param item The item to remove\n * @returns The index of the removed item, or -1 if not found\n */\n removeBlockItem(item: BlockItem): number {\n const index = this.blockItems.indexOf(item);\n if (index >= 0) {\n this.blockItems.splice(index, 1);\n item.setParent(null);\n }\n return index;\n }\n\n /**\n * Returns a debug-friendly representation of this block.\n */\n debugValue(): any {\n const out: any = {\n ...super.debugValue(),\n blockType: this.blockType,\n blockItems: this.blockItems.map((c) => c.debugValue()),\n };\n if (this.name) {\n out.name = this.name;\n }\n if (this.localCycle) {\n out.localCycle = this.localCycle.uuid;\n }\n if (this.localAtomsPerBeat !== null) {\n out.localAtomsPerBeat = this.localAtomsPerBeat;\n }\n if (this.localBreaks !== null) {\n out.localBreaks = this.localBreaks;\n }\n if (this.localRoles.size > 0) {\n out.localRoles = Array.from(this.localRoles.keys());\n }\n return out;\n }\n}\n\n/**\n * Helper function to find the containing block of an entity by walking up the tree.\n * @param entity The entity to start from\n * @returns The containing Block, or null if not found\n */\nexport function findContainingBlock(entity: Entity): TSU.Nullable<Block> {\n let current: TSU.Nullable<Entity> = entity.parent;\n while (current !== null) {\n if (current instanceof Block) {\n return current;\n }\n current = current.parent;\n }\n return null;\n}\n\n// ============================================\n// Block Subclasses\n// ============================================\n\n/**\n * A section block with a heading.\n * Expands children to include a heading RawBlock followed by the content.\n *\n * Usage: \\section(\"Pallavi\") { ... }\n */\nexport class SectionBlock extends Block {\n constructor(sectionName: string, parent: TSU.Nullable<Block> = null) {\n super(\"section\", parent, sectionName);\n }\n\n /**\n * Expands children to include a heading RawBlock.\n */\n children(): BlockItem[] {\n const heading = new RawBlock(`# ${this.name}`, \"md\");\n return [heading, ...this.blockItems];\n }\n}\n\n/**\n * A repeat block that expands its children N times.\n *\n * Usage: \\repeat(2) { ... }\n */\nexport class RepeatBlock extends Block {\n /** Number of times to repeat (0 = visual markers only) */\n readonly repeatCount: number;\n\n constructor(repeatCount: number, parent: TSU.Nullable<Block> = null) {\n super(\"repeat\", parent);\n this.repeatCount = repeatCount;\n }\n\n /**\n * Expands children by repeating them N times.\n * If count is 0, returns children as-is (visual repeat markers only).\n */\n children(): BlockItem[] {\n if (this.repeatCount <= 0) {\n return this.blockItems;\n }\n const expanded: BlockItem[] = [];\n for (let i = 0; i < this.repeatCount; i++) {\n expanded.push(...this.blockItems);\n }\n return expanded;\n }\n}\n\n/**\n * A cycle block that sets localCycle for scoped notation.\n *\n * Usage: \\cycle(\"|4|4|\") { ... }\n */\nexport class CycleBlock extends Block {\n constructor(cycle: Cycle, parent: TSU.Nullable<Block> = null) {\n super(\"cycle\", parent);\n this.localCycle = cycle;\n }\n}\n\n/**\n * A beat duration block that sets localAtomsPerBeat for scoped notation.\n *\n * Usage: \\beatDuration(2) { ... }\n */\nexport class BeatDurationBlock extends Block {\n constructor(atomsPerBeat: number, parent: TSU.Nullable<Block> = null) {\n super(\"beatduration\", parent);\n this.localAtomsPerBeat = atomsPerBeat;\n }\n}\n\n/**\n * A breaks block that sets localBreaks for scoped notation.\n *\n * Usage: \\breaks(4, 2, 2) { ... }\n */\nexport class BreaksBlock extends Block {\n constructor(breaks: number[], parent: TSU.Nullable<Block> = null) {\n super(\"breaks\", parent);\n this.localBreaks = breaks;\n }\n}\n\n/**\n * A role block that creates a local role definition.\n *\n * Usage: \\role(\"Vocals\", notes=false) { ... }\n */\nexport class RoleBlock extends Block {\n constructor(roleName: string, notesOnly: boolean, parent: TSU.Nullable<Block> = null) {\n super(\"role\", parent);\n // Create the role locally\n this.newRoleDef(roleName, notesOnly);\n }\n}\n\n/**\n * A group block for organizing notation without special semantics.\n *\n * Usage: \\group(\"optional-name\") { ... }\n */\nexport class GroupBlock extends Block {\n constructor(groupName: string | null, parent: TSU.Nullable<Block> = null) {\n super(\"group\", parent, groupName);\n }\n}\n"]}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import * as TSU from "@panyam/tsutils";
|
|
2
2
|
import { LineView } from "./LineView";
|
|
3
|
-
import { Notation, RawBlock } from "../notation";
|
|
3
|
+
import { Notation, RawBlock, Block, BlockItem } from "../notation";
|
|
4
4
|
import { GlobalBeatLayout } from "../beats";
|
|
5
|
-
import { GridCell, GridCellView } from "../grids";
|
|
5
|
+
import { GridCell, GridCellView, GridLayoutGroup } from "../grids";
|
|
6
6
|
import { Line } from "../core";
|
|
7
7
|
import { BeatView, MarkerView } from "./beatviews";
|
|
8
|
+
export interface NotationViewConfig {
|
|
9
|
+
sharedGridLayoutGroup?: GridLayoutGroup;
|
|
10
|
+
markdownParser?: (contents: string) => string;
|
|
11
|
+
}
|
|
8
12
|
export declare class NotationView {
|
|
9
13
|
readonly rootElement: HTMLElement;
|
|
10
|
-
readonly config?:
|
|
14
|
+
readonly config?: NotationViewConfig | undefined;
|
|
11
15
|
headerElement: HTMLDivElement;
|
|
12
16
|
notation: Notation;
|
|
13
17
|
lineViews: LineView[];
|
|
@@ -15,7 +19,8 @@ export declare class NotationView {
|
|
|
15
19
|
tableElement: HTMLTableElement;
|
|
16
20
|
markdownParser: (contents: string) => string;
|
|
17
21
|
_beatLayout: GlobalBeatLayout;
|
|
18
|
-
|
|
22
|
+
private layoutChangeUnsubscribe;
|
|
23
|
+
constructor(rootElement: HTMLElement, config?: NotationViewConfig | undefined);
|
|
19
24
|
get beatLayout(): GlobalBeatLayout;
|
|
20
25
|
set beatLayout(beatLayout: GlobalBeatLayout);
|
|
21
26
|
loadChildViews(): void;
|
|
@@ -27,6 +32,8 @@ export declare class NotationView {
|
|
|
27
32
|
get currentLineView(): LineView;
|
|
28
33
|
clear(): void;
|
|
29
34
|
refreshLayout(): void;
|
|
35
|
+
protected processBlock(block: Block, lineViews: LineView[]): void;
|
|
36
|
+
protected processBlockItem(item: BlockItem, lineViews: LineView[]): void;
|
|
30
37
|
renderBlock(raw: RawBlock): void;
|
|
31
38
|
beatViews: Map<number, BeatView>;
|
|
32
39
|
markerViews: Map<string, MarkerView>;
|