@audiofab-io/fv1-core 0.4.0 → 0.5.0
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/spnbank/index.d.ts +55 -0
- package/dist/spnbank/index.d.ts.map +1 -0
- package/dist/spnbank/index.js +104 -0
- package/dist/spnbank/index.js.map +1 -0
- package/package.json +8 -2
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.spnbank` — Easy Spin Program Bank file format.
|
|
3
|
+
*
|
|
4
|
+
* A `.spnbank` file is a small JSON manifest describing the eight program
|
|
5
|
+
* slots of an Easy Spin pedal. Each slot points at a workspace-relative
|
|
6
|
+
* `.spn` (FV-1 assembly) or `.spndiagram` (block diagram) file. The manifest
|
|
7
|
+
* is the unit of "program the whole pedal" — tooling resolves each slot to a
|
|
8
|
+
* compiled binary at programming time.
|
|
9
|
+
*
|
|
10
|
+
* Slot indices in the manifest are 1-based (slot 1..8) for human readability.
|
|
11
|
+
* The runtime API uses 0-based indices via `bankSlotIndex0()`.
|
|
12
|
+
*
|
|
13
|
+
* Round-trip:
|
|
14
|
+
* parseSpnBankJson(serializeSpnBankJson(b)) === b // structurally equal
|
|
15
|
+
*/
|
|
16
|
+
/** A single entry in a `.spnbank` file. */
|
|
17
|
+
export interface SpnBankSlot {
|
|
18
|
+
/** 1-based slot number (1..8). */
|
|
19
|
+
slot: number;
|
|
20
|
+
/** Workspace-relative path to a `.spn` or `.spndiagram` file. Empty
|
|
21
|
+
* string indicates an unassigned slot. */
|
|
22
|
+
path: string;
|
|
23
|
+
}
|
|
24
|
+
/** Parsed `.spnbank` file. */
|
|
25
|
+
export interface SpnBankFile {
|
|
26
|
+
/** Display name. Defaults to the filename's basename when not set. */
|
|
27
|
+
name?: string;
|
|
28
|
+
/** Always exactly `PROGRAM_SLOT_COUNT` (8) entries, in slot-number order. */
|
|
29
|
+
slots: SpnBankSlot[];
|
|
30
|
+
}
|
|
31
|
+
/** True if a slot has no assigned program. */
|
|
32
|
+
export declare function isSlotEmpty(slot: SpnBankSlot): boolean;
|
|
33
|
+
/** Build an empty bank. All slots unassigned. */
|
|
34
|
+
export declare function createEmptyBank(name?: string): SpnBankFile;
|
|
35
|
+
/**
|
|
36
|
+
* Parse the JSON text of a `.spnbank` file. Always returns a structurally
|
|
37
|
+
* complete bank (8 slots in order); malformed JSON or missing fields fall
|
|
38
|
+
* back to defaults so tooling can render a usable editor over a corrupt or
|
|
39
|
+
* empty file.
|
|
40
|
+
*
|
|
41
|
+
* @param text Raw file contents.
|
|
42
|
+
* @param fallbackName Display name to use when the file's `name` field is
|
|
43
|
+
* missing — typically the file basename without `.spnbank`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseSpnBankJson(text: string, fallbackName?: string): SpnBankFile;
|
|
46
|
+
/**
|
|
47
|
+
* Serialise a `.spnbank` file to JSON text. Output is pretty-printed with
|
|
48
|
+
* 2-space indentation and a trailing newline.
|
|
49
|
+
*/
|
|
50
|
+
export declare function serializeSpnBankJson(bank: SpnBankFile): string;
|
|
51
|
+
/** Convenience: 0-based index for a slot. */
|
|
52
|
+
export declare function bankSlotIndex0(slot: SpnBankSlot): number;
|
|
53
|
+
/** Re-exported for convenience so callers don't have to also import from `/pedal`. */
|
|
54
|
+
export { PROGRAM_SLOT_COUNT } from '../pedal/constants.js';
|
|
55
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/spnbank/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,2CAA2C;AAC3C,MAAM,WAAW,WAAW;IAC1B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ;+CAC2C;IAC3C,IAAI,EAAE,MAAM,CAAA;CACb;AAED,8BAA8B;AAC9B,MAAM,WAAW,WAAW;IAC1B,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,6EAA6E;IAC7E,KAAK,EAAE,WAAW,EAAE,CAAA;CACrB;AAED,8CAA8C;AAC9C,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAEtD;AAED,iDAAiD;AACjD,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,CAQ1D;AA6BD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,WAAW,CAoBjF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAM9D;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAExD;AAED,sFAAsF;AACtF,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.spnbank` — Easy Spin Program Bank file format.
|
|
3
|
+
*
|
|
4
|
+
* A `.spnbank` file is a small JSON manifest describing the eight program
|
|
5
|
+
* slots of an Easy Spin pedal. Each slot points at a workspace-relative
|
|
6
|
+
* `.spn` (FV-1 assembly) or `.spndiagram` (block diagram) file. The manifest
|
|
7
|
+
* is the unit of "program the whole pedal" — tooling resolves each slot to a
|
|
8
|
+
* compiled binary at programming time.
|
|
9
|
+
*
|
|
10
|
+
* Slot indices in the manifest are 1-based (slot 1..8) for human readability.
|
|
11
|
+
* The runtime API uses 0-based indices via `bankSlotIndex0()`.
|
|
12
|
+
*
|
|
13
|
+
* Round-trip:
|
|
14
|
+
* parseSpnBankJson(serializeSpnBankJson(b)) === b // structurally equal
|
|
15
|
+
*/
|
|
16
|
+
import { PROGRAM_SLOT_COUNT } from '../pedal/constants.js';
|
|
17
|
+
/** True if a slot has no assigned program. */
|
|
18
|
+
export function isSlotEmpty(slot) {
|
|
19
|
+
return !slot.path;
|
|
20
|
+
}
|
|
21
|
+
/** Build an empty bank. All slots unassigned. */
|
|
22
|
+
export function createEmptyBank(name) {
|
|
23
|
+
return {
|
|
24
|
+
name,
|
|
25
|
+
slots: Array.from({ length: PROGRAM_SLOT_COUNT }, (_, i) => ({
|
|
26
|
+
slot: i + 1,
|
|
27
|
+
path: '',
|
|
28
|
+
})),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function normaliseSlots(input) {
|
|
32
|
+
const empty = () => Array.from({ length: PROGRAM_SLOT_COUNT }, (_, i) => ({ slot: i + 1, path: '' }));
|
|
33
|
+
if (!Array.isArray(input))
|
|
34
|
+
return empty();
|
|
35
|
+
// Build a lookup by slot number, tolerant of duplicate / missing entries
|
|
36
|
+
// and out-of-range slot numbers in the input.
|
|
37
|
+
const bySlot = new Map();
|
|
38
|
+
for (const entry of input) {
|
|
39
|
+
if (typeof entry !== 'object' || entry === null)
|
|
40
|
+
continue;
|
|
41
|
+
const e = entry;
|
|
42
|
+
const slot = typeof e.slot === 'number' ? e.slot : NaN;
|
|
43
|
+
const path = typeof e.path === 'string' ? e.path : '';
|
|
44
|
+
if (!Number.isFinite(slot))
|
|
45
|
+
continue;
|
|
46
|
+
if (slot < 1 || slot > PROGRAM_SLOT_COUNT)
|
|
47
|
+
continue;
|
|
48
|
+
bySlot.set(slot, path);
|
|
49
|
+
}
|
|
50
|
+
const result = empty();
|
|
51
|
+
for (const slot of result) {
|
|
52
|
+
const path = bySlot.get(slot.slot);
|
|
53
|
+
if (path !== undefined)
|
|
54
|
+
slot.path = path;
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse the JSON text of a `.spnbank` file. Always returns a structurally
|
|
60
|
+
* complete bank (8 slots in order); malformed JSON or missing fields fall
|
|
61
|
+
* back to defaults so tooling can render a usable editor over a corrupt or
|
|
62
|
+
* empty file.
|
|
63
|
+
*
|
|
64
|
+
* @param text Raw file contents.
|
|
65
|
+
* @param fallbackName Display name to use when the file's `name` field is
|
|
66
|
+
* missing — typically the file basename without `.spnbank`.
|
|
67
|
+
*/
|
|
68
|
+
export function parseSpnBankJson(text, fallbackName) {
|
|
69
|
+
if (!text || !text.trim()) {
|
|
70
|
+
return createEmptyBank(fallbackName);
|
|
71
|
+
}
|
|
72
|
+
let raw;
|
|
73
|
+
try {
|
|
74
|
+
raw = JSON.parse(text);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return createEmptyBank(fallbackName);
|
|
78
|
+
}
|
|
79
|
+
if (typeof raw !== 'object' || raw === null) {
|
|
80
|
+
return createEmptyBank(fallbackName);
|
|
81
|
+
}
|
|
82
|
+
const obj = raw;
|
|
83
|
+
const name = typeof obj.name === 'string' && obj.name ? obj.name : fallbackName;
|
|
84
|
+
const slots = normaliseSlots(obj.slots);
|
|
85
|
+
return { name, slots };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Serialise a `.spnbank` file to JSON text. Output is pretty-printed with
|
|
89
|
+
* 2-space indentation and a trailing newline.
|
|
90
|
+
*/
|
|
91
|
+
export function serializeSpnBankJson(bank) {
|
|
92
|
+
const json = {
|
|
93
|
+
...(bank.name ? { name: bank.name } : {}),
|
|
94
|
+
slots: bank.slots,
|
|
95
|
+
};
|
|
96
|
+
return JSON.stringify(json, null, 2) + '\n';
|
|
97
|
+
}
|
|
98
|
+
/** Convenience: 0-based index for a slot. */
|
|
99
|
+
export function bankSlotIndex0(slot) {
|
|
100
|
+
return slot.slot - 1;
|
|
101
|
+
}
|
|
102
|
+
/** Re-exported for convenience so callers don't have to also import from `/pedal`. */
|
|
103
|
+
export { PROGRAM_SLOT_COUNT } from '../pedal/constants.js';
|
|
104
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/spnbank/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@audiofab-io/fv1-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "FV-1 DSP toolchain: assembler, simulator, Intel HEX parser, and block-diagram compiler",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -22,7 +22,12 @@
|
|
|
22
22
|
"./blockDiagram/node": {
|
|
23
23
|
"import": "./dist/blockDiagram/blocks/BlockDirectoryLoader.js",
|
|
24
24
|
"types": "./dist/blockDiagram/blocks/BlockDirectoryLoader.d.ts"
|
|
25
|
-
}
|
|
25
|
+
},
|
|
26
|
+
"./spnbank": {
|
|
27
|
+
"import": "./dist/spnbank/index.js",
|
|
28
|
+
"types": "./dist/spnbank/index.d.ts"
|
|
29
|
+
},
|
|
30
|
+
"./package.json": "./package.json"
|
|
26
31
|
},
|
|
27
32
|
"files": [
|
|
28
33
|
"dist",
|
|
@@ -32,6 +37,7 @@
|
|
|
32
37
|
"build:manifest": "node scripts/build-manifest.mjs",
|
|
33
38
|
"build": "npm run build:manifest && tsc",
|
|
34
39
|
"clean": "rm -rf dist src/blockDiagram/builtinBlocks.ts",
|
|
40
|
+
"test": "node test/spnbank-test.mjs",
|
|
35
41
|
"prepublishOnly": "npm run build"
|
|
36
42
|
},
|
|
37
43
|
"dependencies": {
|