Open a Compressor as a device in a window of one size (#379)
The tab from #378 shows a Compressor as an editor. The user wanted it to look like a device as well, after a brushed aluminium plug-in, with a meter of the gain reduction instead of the pictures. The tab stays and is switched to per node. - Hardware look is a switch under Settings, on by default for new and existing Compressors. Only the editor reads it. - The panel is 820x280 px and opens straight in a window of that size. The window has no sizing corner and no Dock. A pane says so through `fixedSize`, and `keptSize` keeps the window's middle when it changes to that size. - A Compressor in this look never sits in the tab row. Opening one floats it, and switching the look on moves its tab into the window. - The panel has chrome knobs (threshold and makeup large), a meter with a needle that moves like a VU's, an LCD with the name and the reading, a lever with a lamp for auto-gain, and LEDs for the level going out. Everything is drawn in code. - The Knob takes a size and a chrome look, and leaves out its caption when it has no name, so the panel engraves its own. - `autoGainOn` is now `switchOn`, because the new switch reads the same way. - Where parts sit, the meter's scale, the needle's speed, the LEDs and the plate's grain are in `hardwareView.ts`, apart from the drawing. Decided myself: - The meter's scale runs by the square root, so the first dB is about as wide as the last nine. It is red from 10 dB on. - The LEDs light one every 3 dB from -39 to 0 dB and fall by 20 dB a second. - Switching the look changes the graph's fingerprint, like any other setting of a node. The sound FX is built again once. Findings, fixed on the way: - Pixi's `arc` goes on from the last point of the path. The meter's scale had a line from the corner of the face until each arc got a `moveTo` to its own start. - A text put into a Graphics makes Pixi warn that only Containers take children. The LCD is a Container now. - The first browser check read the needle at one moment and missed the short sound. The panel keeps the most its needle and LEDs showed. Tests: - Unit: hardware-view (10 new), documents (1 new) - e2e 34 (melektaus-atx): ALL PASSED, 122 checks (4 new). Played, the needle reached 20.9 dB and 5 LEDs lit. - Gate (melektaus-atx): CHECK EXIT 0, 283 files, 4355 tests (11 new) - Counter-checks: a window that keeps its corner instead of its middle, and a linear meter scale, each turn exactly their test red. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2d4909d248
commit
9917253751
14 files changed
+1153
-52
No files matched your search
+24
-3
@@ -98,7 +98,8 @@ import { PluginsPane } from './plugins/PluginsPane';
|
||||
import { ManagementPane } from './users/ManagementPane';
|
||||
import { UsersPane } from './users/UsersPane';
|
||||
import { RoutingEditor } from './routing/RoutingEditor';
|
||||
import { CompressorEditor } from './soundfx/CompressorEditor';
|
||||
import { CompressorEditor, compressorNodeOf } from './soundfx/CompressorEditor';
|
||||
import { COMPRESS_HARDWARE_LOOK, switchOn } from '../core/soundfx/nodes';
|
||||
import { EqEditor } from './soundfx/EqEditor';
|
||||
import { NODE_TAB_KINDS, nodeOfTab, nodeTabLabel, type NodeTabKind, nodeTabOf } from './soundfx/nodeTabs';
|
||||
|
||||
@@ -866,6 +867,10 @@ export class Editor implements PlayHost {
|
||||
this.showInWindow(kind, doc);
|
||||
return;
|
||||
}
|
||||
if (this.windowOnly(doc)) {
|
||||
this.floatDocument(doc);
|
||||
return;
|
||||
}
|
||||
if (this.documents.active === doc) {
|
||||
// Still worth a look at the name: a Variables tab's owner may have been renamed.
|
||||
this.syncStrip();
|
||||
@@ -959,7 +964,7 @@ export class Editor implements PlayHost {
|
||||
/** Puts a window's document back into the tab row, showing, and its pane back below the row. */
|
||||
dockWindow(kind: CentreTab): void {
|
||||
const float = this.floats.get(kind);
|
||||
if (!float) return;
|
||||
if (!float || this.windowOnly(float.doc)) return;
|
||||
this.takeBack(kind);
|
||||
this.documents = openDocument(this.documents, float.doc);
|
||||
this.syncStrip();
|
||||
@@ -1002,6 +1007,7 @@ export class Editor implements PlayHost {
|
||||
this.forget(old);
|
||||
}
|
||||
this.pointPane(kind, doc);
|
||||
float.window.refit();
|
||||
float.window.setTitle(this.labelOf(doc), this.iconOf(doc));
|
||||
float.window.toFront();
|
||||
this.pressedWindow = kind;
|
||||
@@ -1018,6 +1024,7 @@ export class Editor implements PlayHost {
|
||||
dock: { x: number; y: number };
|
||||
close: { x: number; y: number };
|
||||
front: boolean;
|
||||
fixed: boolean;
|
||||
}[] {
|
||||
const centre = (w: Widget) => {
|
||||
const at = w.getGlobalPosition();
|
||||
@@ -1033,6 +1040,7 @@ export class Editor implements PlayHost {
|
||||
dock: centre(window.dockButton),
|
||||
close: centre(window.closeButton),
|
||||
front: window.parent?.children.at(-1) === window,
|
||||
fixed: window.fixedSize !== null,
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1190,12 +1198,25 @@ export class Editor implements PlayHost {
|
||||
/** After an edit: a deleted asset takes its tab along, a renamed one renames it. */
|
||||
private syncDocuments(): void {
|
||||
for (const doc of this.documents.docs) if (!this.kindOf(doc)) this.closeDocument(doc);
|
||||
// Switched to its hardware look, a Compressor leaves the tab row for a window (#379).
|
||||
for (const doc of [...this.documents.docs]) if (this.windowOnly(doc)) this.floatDocument(doc);
|
||||
for (const [kind, { doc, window }] of [...this.floats])
|
||||
if (!this.kindOf(doc)) this.closeWindow(kind);
|
||||
else window.setTitle(this.labelOf(doc), this.iconOf(doc));
|
||||
else {
|
||||
window.refit();
|
||||
window.setTitle(this.labelOf(doc), this.iconOf(doc));
|
||||
}
|
||||
this.syncStrip();
|
||||
}
|
||||
|
||||
/** Whether a document has no place in the tab row: a Compressor in its hardware look (#379). */
|
||||
private windowOnly(doc: DocumentId): boolean {
|
||||
const target = this.nodeTargets.get(doc);
|
||||
if (nodeTabOfDocument(doc) !== 'compressor' || !target) return false;
|
||||
const node = compressorNodeOf(this.state.project, target.assetId, target.nodeId);
|
||||
return node !== null && switchOn(node.params, COMPRESS_HARDWARE_LOOK);
|
||||
}
|
||||
|
||||
/** Shows the pane for `tab`, with `strip` lit in the row – none for an empty kind reached by `showTab`. */
|
||||
private display(tab: TabId, strip: StripTab | null): void {
|
||||
// Fullscreen is the game view's; a tab that takes its place (Stop goes back to the scene) ends it.
|
||||
|
||||
Reference in new issue
Block a user