@opendaw/studio-core 0.0.112 → 0.0.114

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.
Files changed (63) hide show
  1. package/dist/AudioUnitFreeze.d.ts +15 -0
  2. package/dist/AudioUnitFreeze.d.ts.map +1 -0
  3. package/dist/AudioUnitFreeze.js +129 -0
  4. package/dist/Engine.d.ts +1 -0
  5. package/dist/Engine.d.ts.map +1 -1
  6. package/dist/EngineFacade.d.ts +1 -0
  7. package/dist/EngineFacade.d.ts.map +1 -1
  8. package/dist/EngineFacade.js +3 -0
  9. package/dist/EngineWorklet.d.ts +1 -0
  10. package/dist/EngineWorklet.d.ts.map +1 -1
  11. package/dist/EngineWorklet.js +4 -0
  12. package/dist/OfflineEngineRenderer.d.ts.map +1 -1
  13. package/dist/OfflineEngineRenderer.js +1 -0
  14. package/dist/StudioPreferences.d.ts +1 -0
  15. package/dist/StudioPreferences.d.ts.map +1 -1
  16. package/dist/StudioSettings.d.ts +1 -0
  17. package/dist/StudioSettings.d.ts.map +1 -1
  18. package/dist/StudioSettings.js +4 -2
  19. package/dist/capture/CaptureDevices.d.ts.map +1 -1
  20. package/dist/capture/CaptureDevices.js +6 -1
  21. package/dist/index.d.ts +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +1 -0
  24. package/dist/offline-engine.js.map +1 -1
  25. package/dist/processors.js +8 -8
  26. package/dist/processors.js.map +4 -4
  27. package/dist/project/Project.d.ts +2 -0
  28. package/dist/project/Project.d.ts.map +1 -1
  29. package/dist/project/Project.js +3 -0
  30. package/dist/ui/canvas/capturing.d.ts +17 -0
  31. package/dist/ui/canvas/capturing.d.ts.map +1 -0
  32. package/dist/ui/canvas/capturing.js +18 -0
  33. package/dist/ui/canvas/index.d.ts +4 -0
  34. package/dist/ui/canvas/index.d.ts.map +1 -0
  35. package/dist/ui/canvas/index.js +3 -0
  36. package/dist/ui/canvas/painter.d.ts +32 -0
  37. package/dist/ui/canvas/painter.d.ts.map +1 -0
  38. package/dist/ui/canvas/painter.js +81 -0
  39. package/dist/ui/canvas/scale.d.ts +22 -0
  40. package/dist/ui/canvas/scale.d.ts.map +1 -0
  41. package/dist/ui/canvas/scale.js +34 -0
  42. package/dist/ui/index.d.ts +2 -0
  43. package/dist/ui/index.d.ts.map +1 -1
  44. package/dist/ui/index.js +2 -0
  45. package/dist/ui/renderer/audio.d.ts +9 -0
  46. package/dist/ui/renderer/audio.d.ts.map +1 -0
  47. package/dist/ui/renderer/audio.js +277 -0
  48. package/dist/ui/renderer/env.d.ts +5 -0
  49. package/dist/ui/renderer/env.d.ts.map +1 -0
  50. package/dist/ui/renderer/env.js +1 -0
  51. package/dist/ui/renderer/fading.d.ts +7 -0
  52. package/dist/ui/renderer/fading.d.ts.map +1 -0
  53. package/dist/ui/renderer/fading.js +55 -0
  54. package/dist/ui/renderer/index.d.ts +6 -0
  55. package/dist/ui/renderer/index.d.ts.map +1 -0
  56. package/dist/ui/renderer/index.js +5 -0
  57. package/dist/ui/renderer/notes.d.ts +7 -0
  58. package/dist/ui/renderer/notes.d.ts.map +1 -0
  59. package/dist/ui/renderer/notes.js +23 -0
  60. package/dist/ui/renderer/value.d.ts +7 -0
  61. package/dist/ui/renderer/value.d.ts.map +1 -0
  62. package/dist/ui/renderer/value.js +101 -0
  63. package/package.json +10 -10
@@ -12,6 +12,7 @@ import { EngineWorklet } from "../EngineWorklet";
12
12
  import { MIDILearning } from "../midi";
13
13
  import { ppqn, TempoMap } from "@opendaw/lib-dsp";
14
14
  import { RegionOverlapResolver, TimelineFocus } from "../ui";
15
+ import { AudioUnitFreeze } from "../AudioUnitFreeze";
15
16
  export type RestartWorklet = {
16
17
  unload: Func<unknown, Promise<unknown>>;
17
18
  load: Procedure<EngineWorklet>;
@@ -47,6 +48,7 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
47
48
  readonly overlapResolver: RegionOverlapResolver;
48
49
  readonly timelineFocus: TimelineFocus;
49
50
  readonly engine: EngineFacade;
51
+ readonly audioUnitFreeze: AudioUnitFreeze;
50
52
  private constructor();
51
53
  startAudioWorklet(restart?: RestartWorklet, options?: ProcessorOptions): EngineWorklet;
52
54
  handleCpuOverload(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,IAAI,EAGJ,SAAS,EAIT,UAAU,EACV,eAAe,EACf,UAAU,EACV,IAAI,EACP,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,UAAU,EAAE,QAAQ,EAA0B,MAAM,kBAAkB,CAAA;AAC9E,OAAO,EACH,WAAW,EAGX,YAAY,EACZ,KAAK,EAEL,OAAO,EACP,WAAW,EAEX,gBAAgB,EACnB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACH,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAGhB,iBAAiB,EAEjB,sBAAsB,EACtB,gBAAgB,EAEhB,eAAe,EAEf,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAElB,kBAAkB,EAElB,eAAe,EAClB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,qBAAqB,EAAE,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AAC7E,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AACvC,OAAO,EAAC,KAAK,EAAC,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAEvC,OAAO,EAAC,cAAc,EAAY,MAAM,YAAY,CAAA;AACpD,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAC5C,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAc,YAAY,EAAC,MAAM,SAAS,CAAA;AAEjD,OAAO,EAAC,IAAI,EAAE,QAAQ,EAAW,MAAM,kBAAkB,CAAA;AAGzD,OAAO,EAAC,qBAAqB,EAAE,aAAa,EAAC,MAAM,OAAO,CAAA;AAE1D,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAA;AAElD,MAAM,MAAM,cAAc,GAAG;IAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;IAAC,IAAI,EAAE,SAAS,CAAC,aAAa,CAAC,CAAA;CAAE,CAAA;AAExG,MAAM,MAAM,oBAAoB,GAAG;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAA;CAC1B,CAAA;AAGD,qBAAa,OAAQ,YAAW,kBAAkB,EAAE,UAAU,EAAE,eAAe;;IAC3E,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO;IAYpE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO;WAIlD,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAOxF,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,GAAE,OAAc,GAAG,OAAO;IAYzG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAE1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAA;IAC5D,QAAQ,CAAC,kBAAkB,EAAE,WAAW,CAAA;IACxC,QAAQ,CAAC,mBAAmB,EAAE,YAAY,CAAA;IAC1C,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IAEjC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;IACxB,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAA;IACvC,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC,QAAQ,CAAC,eAAe,EAAE,iBAAiB,CAAC,gBAAgB,CAAC,CAAA;IAC7D,QAAQ,CAAC,eAAe,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAA;IAChE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,sBAAsB,EAAE,sBAAsB,CAAA;IACvD,QAAQ,CAAC,kBAAkB,EAAE,kBAAkB,CAAA;IAC/C,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAA;IACnC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,eAAe,EAAE,qBAAqB,CAAA;IAC/C,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;IACrC,QAAQ,CAAC,MAAM,eAAqB;IACpC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAA;IAKzC,OAAO;IAmEP,iBAAiB,CAAC,OAAO,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa;IAoBtF,iBAAiB,IAAI,IAAI;IASzB,cAAc,CAAC,OAAO,GAAE,OAAc;IAMtC,aAAa,IAAI,IAAI;IAKrB,WAAW,IAAI,OAAO;IAEtB,MAAM,CAAC,GAAG,EAAE,gBAAgB,GAAG,IAAI;IAMnC,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,UAAU,EAAE,CAAC,GAAG,CAAC;IAC3C,MAAM,CAAC,CAAC,SAAS,UAAU,EAAE,GAAG,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI;IAC5D,KAAK,IAAI,UAAU;IAEnB,IAAI,GAAG,IAAI,UAAU,CAAmB;IACxC,IAAI,cAAc,IAAI,cAAc,CAA8B;IAClE,IAAI,kBAAkB,IAAI,kBAAkB,CAAkC;IAC9E,IAAI,aAAa,IAAI,mBAAmB,CAAiC;IACzE,IAAI,gBAAgB,IAAI,sBAAsB,CAAoC;IAClF,IAAI,cAAc,IAAI,cAAc,CAAkD;IACtF,IAAI,cAAc,IAAI,OAAO,CAAe;IAC5C,IAAI,YAAY,IAAI,OAAO,CAAc;IACzC,IAAI,0BAA0B,IAAI,mBAAmB,CAEpD;IACD,IAAI,qBAAqB,IAAI,qBAAqB,CAAkD;IAEpG,IAAI,QAAQ,IAAI,eAAe,CAW9B;IAED,sBAAsB,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAe9F,kBAAkB,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC;IAM/C,gBAAgB,IAAI,IAAI;IAsBxB,aAAa,IAAI,eAAe;IAEhC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO;IAIxC,OAAO,IAAI,OAAO;IAuBlB,gBAAgB,IAAI,IAAI;IAOxB,sBAAsB,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI;IAI9C,SAAS,IAAI,IAAI;CA4BpB"}
@@ -15,6 +15,7 @@ import { MidiData } from "@opendaw/lib-midi";
15
15
  import { StudioPreferences } from "../StudioPreferences";
16
16
  import { RegionOverlapResolver, TimelineFocus } from "../ui";
17
17
  import { SampleStorage } from "../samples";
18
+ import { AudioUnitFreeze } from "../AudioUnitFreeze";
18
19
  // Main Entry Point for a Project
19
20
  export class Project {
20
21
  static new(env, options) {
@@ -73,6 +74,7 @@ export class Project {
73
74
  overlapResolver;
74
75
  timelineFocus;
75
76
  engine = new EngineFacade();
77
+ audioUnitFreeze;
76
78
  #rootBoxAdapter;
77
79
  #timelineBoxAdapter;
78
80
  constructor(env, boxGraph, { rootBox, userInterfaceBoxes, primaryAudioBusBox, primaryAudioUnitBox, timelineBox }) {
@@ -106,6 +108,7 @@ export class Project {
106
108
  this.mixer = new Mixer(this.#rootBoxAdapter.audioUnits);
107
109
  this.overlapResolver = new RegionOverlapResolver(this.editing, this.api, this.boxAdapters);
108
110
  this.timelineFocus = this.#terminator.own(new TimelineFocus());
111
+ this.audioUnitFreeze = this.#terminator.own(new AudioUnitFreeze(this));
109
112
  console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
110
113
  this.#sampleRegistrations = UUID.newSet(({ uuid }) => uuid);
111
114
  for (const box of this.boxGraph.boxes()) {
@@ -0,0 +1,17 @@
1
+ import { Nullable } from "@opendaw/lib-std";
2
+ export interface Capturing<T> {
3
+ capture(localX: number, localY: number): Nullable<T>;
4
+ }
5
+ export declare class ElementCapturing<T> {
6
+ #private;
7
+ constructor(element: Element, capturing: Capturing<T>);
8
+ get element(): Element;
9
+ get capturing(): Capturing<T>;
10
+ captureEvent(event: {
11
+ clientX: number;
12
+ clientY: number;
13
+ }): Nullable<T>;
14
+ capturePoint(clientX: number, clientY: number): Nullable<T>;
15
+ captureLocalPoint(x: number, y: number): Nullable<T>;
16
+ }
17
+ //# sourceMappingURL=capturing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capturing.d.ts","sourceRoot":"","sources":["../../../src/ui/canvas/capturing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,MAAM,WAAW,SAAS,CAAC,CAAC;IAAG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;CAAC;AAEpF,qBAAa,gBAAgB,CAAC,CAAC;;gBAIf,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAKrD,IAAI,OAAO,IAAI,OAAO,CAAuB;IAC7C,IAAI,SAAS,IAAI,SAAS,CAAC,CAAC,CAAC,CAAyB;IAEtD,YAAY,CAAC,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;IAItE,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;IAK3D,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC;CACvD"}
@@ -0,0 +1,18 @@
1
+ export class ElementCapturing {
2
+ #element;
3
+ #capturing;
4
+ constructor(element, capturing) {
5
+ this.#element = element;
6
+ this.#capturing = capturing;
7
+ }
8
+ get element() { return this.#element; }
9
+ get capturing() { return this.#capturing; }
10
+ captureEvent(event) {
11
+ return this.capturePoint(event.clientX, event.clientY);
12
+ }
13
+ capturePoint(clientX, clientY) {
14
+ const { left, top } = this.#element.getBoundingClientRect();
15
+ return this.captureLocalPoint(clientX - left, clientY - top);
16
+ }
17
+ captureLocalPoint(x, y) { return this.#capturing.capture(x, y); }
18
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./capturing";
2
+ export * from "./painter";
3
+ export * from "./scale";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/canvas/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from "./capturing";
2
+ export * from "./painter";
3
+ export * from "./scale";
@@ -0,0 +1,32 @@
1
+ import { Procedure, Terminable } from "@opendaw/lib-std";
2
+ import { Scale } from "./scale";
3
+ export declare class CanvasPainter implements Terminable {
4
+ #private;
5
+ constructor(canvas: HTMLCanvasElement, render: Procedure<CanvasPainter>);
6
+ readonly requestUpdate: () => void;
7
+ get isResized(): boolean;
8
+ get devicePixelRatio(): number;
9
+ get width(): number;
10
+ get height(): number;
11
+ get actualWidth(): number;
12
+ get actualHeight(): number;
13
+ get context(): CanvasRenderingContext2D;
14
+ terminate(): void;
15
+ }
16
+ export declare class CanvasUnitPainter implements Terminable {
17
+ #private;
18
+ constructor(canvas: HTMLCanvasElement, xAxis: Scale, yAxis: Scale, render: Procedure<CanvasUnitPainter>);
19
+ readonly requestUpdate: () => void;
20
+ xToUnit(x: number): number;
21
+ unitToX(value: number): number;
22
+ yToUnit(y: number): number;
23
+ unitToY(value: number): number;
24
+ get context(): CanvasRenderingContext2D;
25
+ get isResized(): boolean;
26
+ get width(): number;
27
+ get height(): number;
28
+ get actualWidth(): number;
29
+ get actualHeight(): number;
30
+ terminate(): void;
31
+ }
32
+ //# sourceMappingURL=painter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"painter.d.ts","sourceRoot":"","sources":["../../../src/ui/canvas/painter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,SAAS,EAAE,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAEnF,OAAO,EAAC,KAAK,EAAC,MAAM,SAAS,CAAA;AAE7B,qBAAa,aAAc,YAAW,UAAU;;gBAGhC,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,SAAS,CAAC,aAAa,CAAC;IAIvE,QAAQ,CAAC,aAAa,QAAO,IAAI,CAAqC;IAEtE,IAAI,SAAS,IAAI,OAAO,CAAmC;IAC3D,IAAI,gBAAgB,IAAI,MAAM,CAA0C;IACxE,IAAI,KAAK,IAAI,MAAM,CAA+B;IAClD,IAAI,MAAM,IAAI,MAAM,CAAgC;IACpD,IAAI,WAAW,IAAI,MAAM,CAAqC;IAC9D,IAAI,YAAY,IAAI,MAAM,CAAsC;IAChE,IAAI,OAAO,IAAI,wBAAwB,CAAiC;IACxE,SAAS,IAAI,IAAI;CACpB;AAED,qBAAa,iBAAkB,YAAW,UAAU;;gBAMpC,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,SAAS,CAAC,iBAAiB,CAAC;IAMhD,QAAQ,CAAC,aAAa,QAAO,IAAI,CAAqC;IAEtE,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAC1B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAC9B,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM;IAC1B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAC9B,IAAI,OAAO,IAAI,wBAAwB,CAAiC;IACxE,IAAI,SAAS,IAAI,OAAO,CAAmC;IAC3D,IAAI,KAAK,IAAI,MAAM,CAA+B;IAClD,IAAI,MAAM,IAAI,MAAM,CAAgC;IACpD,IAAI,WAAW,IAAI,MAAM,CAAqC;IAC9D,IAAI,YAAY,IAAI,MAAM,CAAsC;IAChE,SAAS,IAAI,IAAI;CACpB"}
@@ -0,0 +1,81 @@
1
+ import { asDefined, Terminator } from "@opendaw/lib-std";
2
+ import { AnimationFrame, Html } from "@opendaw/lib-dom";
3
+ export class CanvasPainter {
4
+ #rendering;
5
+ constructor(canvas, render) {
6
+ this.#rendering = new CanvasRenderer(canvas, () => render(this));
7
+ }
8
+ requestUpdate = () => { this.#rendering.requestUpdate(); };
9
+ get isResized() { return this.#rendering.isResized; }
10
+ get devicePixelRatio() { return this.#rendering.devicePixelRatio; }
11
+ get width() { return this.#rendering.width; }
12
+ get height() { return this.#rendering.height; }
13
+ get actualWidth() { return this.#rendering.actualWidth; }
14
+ get actualHeight() { return this.#rendering.actualHeight; }
15
+ get context() { return this.#rendering.context; }
16
+ terminate() { this.#rendering.terminate(); }
17
+ }
18
+ export class CanvasUnitPainter {
19
+ #rendering;
20
+ #xAxis;
21
+ #yAxis;
22
+ constructor(canvas, xAxis, yAxis, render) {
23
+ this.#rendering = new CanvasRenderer(canvas, () => render(this));
24
+ this.#xAxis = xAxis;
25
+ this.#yAxis = yAxis;
26
+ }
27
+ requestUpdate = () => { this.#rendering.requestUpdate(); };
28
+ xToUnit(x) { return this.#xAxis.normToUnit(x / this.#rendering.actualWidth); }
29
+ unitToX(value) { return this.#xAxis.unitToNorm(value) * this.#rendering.actualWidth; }
30
+ yToUnit(y) { return this.#yAxis.normToUnit(1.0 - y / this.#rendering.actualHeight); }
31
+ unitToY(value) { return (1.0 - this.#yAxis.unitToNorm(value)) * this.#rendering.actualHeight; }
32
+ get context() { return this.#rendering.context; }
33
+ get isResized() { return this.#rendering.isResized; }
34
+ get width() { return this.#rendering.width; }
35
+ get height() { return this.#rendering.height; }
36
+ get actualWidth() { return this.#rendering.actualWidth; }
37
+ get actualHeight() { return this.#rendering.actualHeight; }
38
+ terminate() { this.#rendering.terminate(); }
39
+ }
40
+ class CanvasRenderer {
41
+ #lifecycle = new Terminator();
42
+ #context;
43
+ #update;
44
+ #width = 0;
45
+ #height = 0;
46
+ #devicePixelRatio = 1;
47
+ #isResized = true;
48
+ #needsUpdate = true;
49
+ constructor(canvas, update) {
50
+ this.#context = asDefined(canvas.getContext("2d"));
51
+ this.#update = update;
52
+ this.#lifecycle.ownAll(Html.watchResize(canvas, () => {
53
+ this.#isResized = true;
54
+ this.#needsUpdate = true;
55
+ }), this.#lifecycle.own(AnimationFrame.add(() => {
56
+ const width = canvas.clientWidth;
57
+ const height = canvas.clientHeight;
58
+ if (!this.#needsUpdate || width === 0 || height === 0) {
59
+ return;
60
+ }
61
+ this.#isResized = width !== this.#width || height !== this.#height || devicePixelRatio !== this.#devicePixelRatio;
62
+ this.#width = width;
63
+ this.#height = height;
64
+ this.#devicePixelRatio = devicePixelRatio;
65
+ canvas.width = width * devicePixelRatio;
66
+ canvas.height = height * devicePixelRatio;
67
+ this.#update();
68
+ this.#isResized = false;
69
+ this.#needsUpdate = false;
70
+ })));
71
+ }
72
+ get isResized() { return this.#isResized; }
73
+ get devicePixelRatio() { return this.#devicePixelRatio; }
74
+ get width() { return this.#width; }
75
+ get height() { return this.#height; }
76
+ get actualWidth() { return this.#width * this.#devicePixelRatio; }
77
+ get actualHeight() { return this.#height * this.#devicePixelRatio; }
78
+ get context() { return this.#context; }
79
+ requestUpdate() { this.#needsUpdate = true; }
80
+ terminate() { this.#lifecycle.terminate(); }
81
+ }
@@ -0,0 +1,22 @@
1
+ import { unitValue } from "@opendaw/lib-std";
2
+ export interface Scale {
3
+ unitToNorm(unit: number): unitValue;
4
+ normToUnit(norm: unitValue): number;
5
+ }
6
+ export declare class LinearScale implements Scale {
7
+ #private;
8
+ constructor(min: number, max: number);
9
+ get min(): number;
10
+ get max(): number;
11
+ normToUnit(norm: number): number;
12
+ unitToNorm(unit: number): number;
13
+ }
14
+ export declare class LogScale implements Scale {
15
+ #private;
16
+ constructor(min: number, max: number);
17
+ get min(): number;
18
+ get max(): number;
19
+ normToUnit(norm: unitValue): number;
20
+ unitToNorm(unit: number): unitValue;
21
+ }
22
+ //# sourceMappingURL=scale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scale.d.ts","sourceRoot":"","sources":["../../../src/ui/canvas/scale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,kBAAkB,CAAA;AAE1C,MAAM,WAAW,KAAK;IAClB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACnC,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAA;CACtC;AAED,qBAAa,WAAY,YAAW,KAAK;;gBAMzB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAOpC,IAAI,GAAG,IAAI,MAAM,CAAmB;IACpC,IAAI,GAAG,IAAI,MAAM,CAAmB;IAEpC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAChC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CACnC;AAED,qBAAa,QAAS,YAAW,KAAK;;gBAOtB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAQpC,IAAI,GAAG,IAAI,MAAM,CAAmB;IACpC,IAAI,GAAG,IAAI,MAAM,CAAmB;IAEpC,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM;IACnC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS;CACtC"}
@@ -0,0 +1,34 @@
1
+ export class LinearScale {
2
+ #min;
3
+ #max;
4
+ #range;
5
+ #rangeInv;
6
+ constructor(min, max) {
7
+ this.#min = min;
8
+ this.#max = max;
9
+ this.#range = max - min;
10
+ this.#rangeInv = 1.0 / this.#range;
11
+ }
12
+ get min() { return this.#min; }
13
+ get max() { return this.#max; }
14
+ normToUnit(norm) { return this.#min + norm * this.#range; }
15
+ unitToNorm(unit) { return (unit - this.#min) * this.#rangeInv; }
16
+ }
17
+ export class LogScale {
18
+ #min;
19
+ #max;
20
+ #range;
21
+ #logMin;
22
+ #logRangeInv;
23
+ constructor(min, max) {
24
+ this.#min = min;
25
+ this.#max = max;
26
+ this.#range = Math.log(max / min);
27
+ this.#logMin = Math.log(min);
28
+ this.#logRangeInv = 1.0 / (Math.log(max) - this.#logMin);
29
+ }
30
+ get min() { return this.#min; }
31
+ get max() { return this.#max; }
32
+ normToUnit(norm) { return this.#min * Math.exp(norm * this.#range); }
33
+ unitToNorm(unit) { return (Math.log(unit) - this.#logMin) * this.#logRangeInv; }
34
+ }
@@ -1,3 +1,4 @@
1
+ export * from "./canvas";
1
2
  export * from "./clipboard/ClipboardManager";
2
3
  export * from "./clipboard/ClipboardUtils";
3
4
  export * from "./clipboard/ContextMenu";
@@ -7,6 +8,7 @@ export * from "./clipboard/types/NotesClipboardHandler";
7
8
  export * from "./clipboard/types/RegionsClipboardHandler";
8
9
  export * from "./clipboard/types/ValuesClipboardHandler";
9
10
  export * from "./menu/MenuItems";
11
+ export * from "./renderer";
10
12
  export * from "./timeline/RegionClipResolver";
11
13
  export * from "./timeline/RegionKeepExistingResolver";
12
14
  export * from "./timeline/RegionModifyStrategies";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAA;AAC5C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,8CAA8C,CAAA;AAC5D,cAAc,2CAA2C,CAAA;AACzD,cAAc,yCAAyC,CAAA;AACvD,cAAc,2CAA2C,CAAA;AACzD,cAAc,0CAA0C,CAAA;AACxD,cAAc,kBAAkB,CAAA;AAChC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uCAAuC,CAAA;AACrD,cAAc,mCAAmC,CAAA;AACjD,cAAc,kCAAkC,CAAA;AAChD,cAAc,uCAAuC,CAAA;AACrD,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,8BAA8B,CAAA;AAC5C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,cAAc,8CAA8C,CAAA;AAC5D,cAAc,2CAA2C,CAAA;AACzD,cAAc,yCAAyC,CAAA;AACvD,cAAc,2CAA2C,CAAA;AACzD,cAAc,0CAA0C,CAAA;AACxD,cAAc,kBAAkB,CAAA;AAChC,cAAc,YAAY,CAAA;AAC1B,cAAc,+BAA+B,CAAA;AAC7C,cAAc,uCAAuC,CAAA;AACrD,cAAc,mCAAmC,CAAA;AACjD,cAAc,kCAAkC,CAAA;AAChD,cAAc,uCAAuC,CAAA;AACrD,cAAc,0BAA0B,CAAA;AACxC,cAAc,qBAAqB,CAAA;AACnC,cAAc,0BAA0B,CAAA;AACxC,cAAc,0BAA0B,CAAA"}
package/dist/ui/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from "./canvas";
1
2
  export * from "./clipboard/ClipboardManager";
2
3
  export * from "./clipboard/ClipboardUtils";
3
4
  export * from "./clipboard/ContextMenu";
@@ -7,6 +8,7 @@ export * from "./clipboard/types/NotesClipboardHandler";
7
8
  export * from "./clipboard/types/RegionsClipboardHandler";
8
9
  export * from "./clipboard/types/ValuesClipboardHandler";
9
10
  export * from "./menu/MenuItems";
11
+ export * from "./renderer";
10
12
  export * from "./timeline/RegionClipResolver";
11
13
  export * from "./timeline/RegionKeepExistingResolver";
12
14
  export * from "./timeline/RegionModifyStrategies";
@@ -0,0 +1,9 @@
1
+ import { RegionBound } from "./env";
2
+ import { Option } from "@opendaw/lib-std";
3
+ import { LoopableRegion, TempoMap } from "@opendaw/lib-dsp";
4
+ import { AudioFileBoxAdapter, AudioPlayMode } from "@opendaw/studio-adapters";
5
+ import { TimelineRange } from "../timeline/TimelineRange";
6
+ export declare namespace AudioRenderer {
7
+ const render: (context: CanvasRenderingContext2D, range: TimelineRange, file: AudioFileBoxAdapter, tempoMap: TempoMap, playMode: Option<AudioPlayMode>, waveformOffset: number, gain: number, { top, bottom }: RegionBound, contentColor: string, { rawStart, resultStart, resultEnd }: LoopableRegion.LoopCycle, clip?: boolean) => void;
8
+ }
9
+ //# sourceMappingURL=audio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/audio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AACjC,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAW,cAAc,EAAyB,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAE1F,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,0BAA0B,CAAA;AAC3E,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAA;AAEvD,yBAAiB,aAAa,CAAC;IASpB,MAAM,MAAM,GACf,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,MAAM,mBAAmB,EACzB,UAAU,QAAQ,EAClB,UAAU,MAAM,CAAC,aAAa,CAAC,EAC/B,gBAAgB,MAAM,EACtB,MAAM,MAAM,EACZ,iBAAe,WAAW,EAC1B,cAAc,MAAM,EACpB,sCAAoC,cAAc,CAAC,SAAS,EAC5D,OAAM,OAAc,SA2VvB,CAAA;CACJ"}
@@ -0,0 +1,277 @@
1
+ import { dbToGain, PPQN, TempoChangeGrid } from "@opendaw/lib-dsp";
2
+ import { PeaksPainter } from "@opendaw/lib-fusion";
3
+ export var AudioRenderer;
4
+ (function (AudioRenderer) {
5
+ AudioRenderer.render = (context, range, file, tempoMap, playMode, waveformOffset, gain, { top, bottom }, contentColor, { rawStart, resultStart, resultEnd }, clip = true) => {
6
+ if (file.peaks.isEmpty()) {
7
+ return;
8
+ }
9
+ const peaks = file.peaks.unwrap();
10
+ const durationInSeconds = file.endInSeconds - file.startInSeconds;
11
+ const numFrames = peaks.numFrames;
12
+ const numberOfChannels = peaks.numChannels;
13
+ const ht = bottom - top;
14
+ const peaksHeight = Math.floor((ht - 4) / numberOfChannels);
15
+ const scale = dbToGain(-gain);
16
+ const segments = [];
17
+ if (playMode.nonEmpty()) {
18
+ const { warpMarkers } = playMode.unwrap();
19
+ const markers = warpMarkers.asArray();
20
+ if (markers.length < 2) {
21
+ return;
22
+ }
23
+ const first = markers[0];
24
+ const second = markers[1];
25
+ const secondLast = markers[markers.length - 2];
26
+ const last = markers[markers.length - 1];
27
+ const firstRate = (second.seconds - first.seconds) /
28
+ (second.position - first.position);
29
+ const lastRate = (last.seconds - secondLast.seconds) /
30
+ (last.position - secondLast.position);
31
+ const addSegment = (posStart, posEnd, audioStart, audioEnd, outside) => {
32
+ if (posStart >= posEnd) {
33
+ return;
34
+ }
35
+ if (posStart > range.unitMax || posEnd < range.unitMin) {
36
+ return;
37
+ }
38
+ const clippedStart = Math.max(posStart, range.unitMin - range.unitPadding);
39
+ const clippedEnd = Math.min(posEnd, range.unitMax);
40
+ if (clippedStart >= clippedEnd) {
41
+ return;
42
+ }
43
+ const t0 = (clippedStart - posStart) / (posEnd - posStart);
44
+ const t1 = (clippedEnd - posStart) / (posEnd - posStart);
45
+ let aStart = audioStart + t0 * (audioEnd - audioStart) + waveformOffset;
46
+ let aEnd = audioStart + t1 * (audioEnd - audioStart) + waveformOffset;
47
+ let x0 = range.unitToX(clippedStart) * devicePixelRatio;
48
+ let x1 = range.unitToX(clippedEnd) * devicePixelRatio;
49
+ if (aStart < 0.0) {
50
+ const ratio = -aStart / (aEnd - aStart);
51
+ x0 = x0 + ratio * (x1 - x0);
52
+ aStart = 0.0;
53
+ }
54
+ if (aEnd > durationInSeconds) {
55
+ const ratio = (aEnd - durationInSeconds) / (aEnd - aStart);
56
+ x1 = x1 - ratio * (x1 - x0);
57
+ aEnd = durationInSeconds;
58
+ }
59
+ if (aStart >= aEnd) {
60
+ return;
61
+ }
62
+ segments.push({
63
+ x0,
64
+ x1,
65
+ u0: (aStart / durationInSeconds) * numFrames,
66
+ u1: (aEnd / durationInSeconds) * numFrames,
67
+ outside
68
+ });
69
+ };
70
+ const handleSegment = (segmentStart, segmentEnd, audioStartSeconds, audioEndSeconds) => {
71
+ if (segmentStart >= segmentEnd) {
72
+ return;
73
+ }
74
+ if (clip) {
75
+ if (segmentEnd <= resultStart || segmentStart >= resultEnd) {
76
+ return;
77
+ }
78
+ const clippedStart = Math.max(segmentStart, resultStart);
79
+ const clippedEnd = Math.min(segmentEnd, resultEnd);
80
+ const t0 = (clippedStart - segmentStart) / (segmentEnd - segmentStart);
81
+ const t1 = (clippedEnd - segmentStart) / (segmentEnd - segmentStart);
82
+ const aStart = audioStartSeconds + t0 * (audioEndSeconds - audioStartSeconds);
83
+ const aEnd = audioStartSeconds + t1 * (audioEndSeconds - audioStartSeconds);
84
+ addSegment(clippedStart, clippedEnd, aStart, aEnd, false);
85
+ }
86
+ else {
87
+ const rate = (audioEndSeconds - audioStartSeconds) / (segmentEnd - segmentStart);
88
+ // Before audible
89
+ if (segmentStart < resultStart) {
90
+ const endPos = Math.min(segmentEnd, resultStart);
91
+ const aEnd = audioStartSeconds + (endPos - segmentStart) * rate;
92
+ addSegment(segmentStart, endPos, audioStartSeconds, aEnd, true);
93
+ }
94
+ // Audible
95
+ if (segmentEnd > resultStart && segmentStart < resultEnd) {
96
+ const startPos = Math.max(segmentStart, resultStart);
97
+ const endPos = Math.min(segmentEnd, resultEnd);
98
+ const aStart = audioStartSeconds + (startPos - segmentStart) * rate;
99
+ const aEnd = audioStartSeconds + (endPos - segmentStart) * rate;
100
+ addSegment(startPos, endPos, aStart, aEnd, false);
101
+ }
102
+ // After audible
103
+ if (segmentEnd > resultEnd) {
104
+ const startPos = Math.max(segmentStart, resultEnd);
105
+ const aStart = audioStartSeconds + (startPos - segmentStart) * rate;
106
+ addSegment(startPos, segmentEnd, aStart, audioEndSeconds, true);
107
+ }
108
+ }
109
+ };
110
+ const visibleLocalStart = (clip ? resultStart : range.unitMin) - rawStart;
111
+ const visibleLocalEnd = (clip ? resultEnd : range.unitMax) - rawStart;
112
+ // With positive offset, audio from file start appears BEFORE first.position
113
+ // With negative offset, audio from file end appears AFTER last.position
114
+ const extraNeededBefore = waveformOffset > 0 ? waveformOffset / firstRate : 0;
115
+ const extraNeededAfter = waveformOffset < 0 ? -waveformOffset / lastRate : 0;
116
+ const extrapolateStartLocal = Math.min(visibleLocalStart, first.position - extraNeededBefore);
117
+ const extrapolateEndLocal = Math.max(visibleLocalEnd, last.position + extraNeededAfter);
118
+ // Extrapolate before the first warp marker
119
+ if (extrapolateStartLocal < first.position) {
120
+ const audioStart = first.seconds +
121
+ (extrapolateStartLocal - first.position) * firstRate;
122
+ handleSegment(rawStart + extrapolateStartLocal, rawStart + first.position, audioStart, first.seconds);
123
+ }
124
+ // Interior warp segments - only iterate visible range
125
+ const startIndex = Math.max(0, warpMarkers.floorLastIndex(visibleLocalStart));
126
+ for (let i = startIndex; i < markers.length - 1; i++) {
127
+ const w0 = markers[i];
128
+ if (w0.position > visibleLocalEnd) {
129
+ break;
130
+ }
131
+ const w1 = markers[i + 1];
132
+ handleSegment(rawStart + w0.position, rawStart + w1.position, w0.seconds, w1.seconds);
133
+ }
134
+ // Extrapolate after the last warp marker
135
+ if (extrapolateEndLocal > last.position) {
136
+ const audioEnd = last.seconds + (extrapolateEndLocal - last.position) * lastRate;
137
+ handleSegment(rawStart + last.position, rawStart + extrapolateEndLocal, last.seconds, audioEnd);
138
+ }
139
+ }
140
+ else {
141
+ // Non-stretch mode - audio plays at 100% original speed
142
+ // Audio time = elapsed timeline seconds since rawStart + waveformOffset
143
+ // Use rawStart (not resultStart) because resultStart is clipped to viewport
144
+ const regionStartSeconds = tempoMap.ppqnToSeconds(rawStart);
145
+ // Use absolute time conversion so it works for positions before AND after rawStart
146
+ const audioTimeAt = (ppqn) => tempoMap.ppqnToSeconds(ppqn) - regionStartSeconds + waveformOffset;
147
+ // Fixed step size for consistent rendering across zoom levels
148
+ const addSegmentDirect = (ppqnStart, ppqnEnd, audioStart, audioEnd, outside) => {
149
+ if (ppqnStart >= ppqnEnd) {
150
+ return;
151
+ }
152
+ if (ppqnEnd < range.unitMin - range.unitPadding ||
153
+ ppqnStart > range.unitMax) {
154
+ return;
155
+ }
156
+ const clippedStart = Math.max(ppqnStart, range.unitMin - range.unitPadding);
157
+ const clippedEnd = Math.min(ppqnEnd, range.unitMax);
158
+ if (clippedStart >= clippedEnd) {
159
+ return;
160
+ }
161
+ // Interpolate audio times for clipped range
162
+ const t0 = (clippedStart - ppqnStart) / (ppqnEnd - ppqnStart);
163
+ const t1 = (clippedEnd - ppqnStart) / (ppqnEnd - ppqnStart);
164
+ let aStart = audioStart + t0 * (audioEnd - audioStart);
165
+ let aEnd = audioStart + t1 * (audioEnd - audioStart);
166
+ let x0 = range.unitToX(clippedStart) * devicePixelRatio;
167
+ let x1 = range.unitToX(clippedEnd) * devicePixelRatio;
168
+ if (aStart < 0) {
169
+ const ratio = -aStart / (aEnd - aStart);
170
+ x0 += ratio * (x1 - x0);
171
+ aStart = 0;
172
+ }
173
+ if (aEnd > durationInSeconds) {
174
+ const ratio = (aEnd - durationInSeconds) / (aEnd - aStart);
175
+ x1 -= ratio * (x1 - x0);
176
+ aEnd = durationInSeconds;
177
+ }
178
+ if (aStart >= aEnd) {
179
+ return;
180
+ }
181
+ const u0 = (aStart / durationInSeconds) * numFrames;
182
+ const u1 = (aEnd / durationInSeconds) * numFrames;
183
+ if (u0 < u1 && x1 - x0 >= 1) {
184
+ segments.push({ x0, x1, u0, u1, outside });
185
+ }
186
+ };
187
+ // Similar to stretch mode: handle clipping at region boundaries
188
+ const handleTempoSegment = (segStart, segEnd, audioStart, audioEnd) => {
189
+ if (segStart >= segEnd) {
190
+ return;
191
+ }
192
+ if (clip) {
193
+ if (segEnd <= resultStart || segStart >= resultEnd) {
194
+ return;
195
+ }
196
+ const clippedStart = Math.max(segStart, resultStart);
197
+ const clippedEnd = Math.min(segEnd, resultEnd);
198
+ const t0 = (clippedStart - segStart) / (segEnd - segStart);
199
+ const t1 = (clippedEnd - segStart) / (segEnd - segStart);
200
+ const aStart = audioStart + t0 * (audioEnd - audioStart);
201
+ const aEnd = audioStart + t1 * (audioEnd - audioStart);
202
+ addSegmentDirect(clippedStart, clippedEnd, aStart, aEnd, false);
203
+ }
204
+ else {
205
+ const rate = (audioEnd - audioStart) / (segEnd - segStart);
206
+ // Before audible region
207
+ if (segStart < resultStart) {
208
+ const endPos = Math.min(segEnd, resultStart);
209
+ const aEnd = audioStart + (endPos - segStart) * rate;
210
+ addSegmentDirect(segStart, endPos, audioStart, aEnd, true);
211
+ }
212
+ // Audible region
213
+ if (segEnd > resultStart && segStart < resultEnd) {
214
+ const startPos = Math.max(segStart, resultStart);
215
+ const endPos = Math.min(segEnd, resultEnd);
216
+ const aStart = audioStart + (startPos - segStart) * rate;
217
+ const aEnd = audioStart + (endPos - segStart) * rate;
218
+ addSegmentDirect(startPos, endPos, aStart, aEnd, false);
219
+ }
220
+ // After audible region
221
+ if (segEnd > resultEnd) {
222
+ const startPos = Math.max(segStart, resultEnd);
223
+ const aStart = audioStart + (startPos - segStart) * rate;
224
+ addSegmentDirect(startPos, segEnd, aStart, audioEnd, true);
225
+ }
226
+ }
227
+ };
228
+ // Calculate iteration bounds
229
+ // Where does audioTime = 0? Solve: ppqnToSeconds(ppqn) - regionStartSeconds + waveformOffset = 0
230
+ const audioStartPPQN = tempoMap.secondsToPPQN(regionStartSeconds - waveformOffset);
231
+ // Where does audioTime = durationInSeconds?
232
+ const audioEndPPQN = tempoMap.secondsToPPQN(regionStartSeconds - waveformOffset + durationInSeconds);
233
+ // Determine visible iteration range (include padding on the left for smooth scrolling)
234
+ const iterStart = clip
235
+ ? Math.max(resultStart, range.unitMin - range.unitPadding)
236
+ : Math.max(Math.min(audioStartPPQN, resultStart), range.unitMin - range.unitPadding);
237
+ const iterEnd = clip
238
+ ? Math.min(resultEnd, range.unitMax + TempoChangeGrid)
239
+ : Math.min(Math.max(audioEndPPQN, resultEnd), range.unitMax + TempoChangeGrid);
240
+ // Dynamic step size: ensure each step is at least 1 device pixel wide
241
+ const minStepSize = range.unitsPerPixel * devicePixelRatio;
242
+ const stepSize = Math.max(TempoChangeGrid, Math.ceil(minStepSize / TempoChangeGrid) * TempoChangeGrid);
243
+ // Align to grid for consistent rendering across zoom levels
244
+ let currentPPQN = Math.floor(iterStart / stepSize) * stepSize;
245
+ // Compute initial audio time once, then increment (avoid O(n) ppqnToSeconds calls per step)
246
+ let currentAudioTime = audioTimeAt(currentPPQN);
247
+ while (currentPPQN < iterEnd) {
248
+ const nextPPQN = currentPPQN + stepSize;
249
+ // Incremental: get tempo at the current position and compute step duration
250
+ const stepSeconds = PPQN.pulsesToSeconds(stepSize, tempoMap.getTempoAt(currentPPQN));
251
+ const nextAudioTime = currentAudioTime + stepSeconds;
252
+ // Skip if entirely outside audio file range
253
+ if (nextAudioTime > 0 && currentAudioTime < durationInSeconds) {
254
+ handleTempoSegment(currentPPQN, nextPPQN, currentAudioTime, nextAudioTime);
255
+ }
256
+ currentPPQN = nextPPQN;
257
+ currentAudioTime = nextAudioTime;
258
+ }
259
+ }
260
+ context.fillStyle = contentColor;
261
+ for (const { x0, x1, u0, u1, outside } of segments) {
262
+ context.globalAlpha = outside && !clip ? 0.25 : 1.0;
263
+ for (let channel = 0; channel < numberOfChannels; channel++) {
264
+ PeaksPainter.renderBlocks(context, peaks, channel, {
265
+ u0,
266
+ u1,
267
+ v0: -scale,
268
+ v1: +scale,
269
+ x0,
270
+ x1,
271
+ y0: 3 + top + channel * peaksHeight,
272
+ y1: 3 + top + (channel + 1) * peaksHeight
273
+ });
274
+ }
275
+ }
276
+ };
277
+ })(AudioRenderer || (AudioRenderer = {}));
@@ -0,0 +1,5 @@
1
+ export type RegionBound = {
2
+ top: number;
3
+ bottom: number;
4
+ };
5
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/env.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,WAAW,GAAG;IACtB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;CACjB,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { FadingEnvelope } from "@opendaw/lib-dsp";
2
+ import { TimelineRange } from "../../index";
3
+ import { RegionBound } from "./env";
4
+ export declare namespace AudioFadingRenderer {
5
+ const render: (context: CanvasRenderingContext2D, range: TimelineRange, fading: FadingEnvelope.Config, { top, bottom }: RegionBound, startPPQN: number, endPPQN: number, color: string) => void;
6
+ }
7
+ //# sourceMappingURL=fading.d.ts.map