@opendaw/studio-core 0.0.122 → 0.0.124

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 (34) hide show
  1. package/dist/AssetService.d.ts +4 -3
  2. package/dist/AssetService.d.ts.map +1 -1
  3. package/dist/AssetService.js +3 -5
  4. package/dist/RecordingWorklet.d.ts +2 -0
  5. package/dist/RecordingWorklet.d.ts.map +1 -1
  6. package/dist/RecordingWorklet.js +8 -25
  7. package/dist/capture/CaptureAudio.d.ts.map +1 -1
  8. package/dist/capture/CaptureAudio.js +2 -1
  9. package/dist/capture/RecordMidi.d.ts.map +1 -1
  10. package/dist/capture/RecordMidi.js +24 -2
  11. package/dist/processors.js +8 -8
  12. package/dist/processors.js.map +3 -3
  13. package/dist/project/ProjectEnv.d.ts +4 -0
  14. package/dist/project/ProjectEnv.d.ts.map +1 -1
  15. package/dist/samples/SampleService.d.ts +5 -3
  16. package/dist/samples/SampleService.d.ts.map +1 -1
  17. package/dist/samples/SampleService.js +16 -7
  18. package/dist/soundfont/SoundfontService.d.ts +2 -2
  19. package/dist/soundfont/SoundfontService.d.ts.map +1 -1
  20. package/dist/soundfont/SoundfontService.js +3 -3
  21. package/dist/ui/renderer/audio.d.ts +13 -1
  22. package/dist/ui/renderer/audio.d.ts.map +1 -1
  23. package/dist/ui/renderer/audio.js +28 -20
  24. package/dist/ui/renderer/fading.d.ts.map +1 -1
  25. package/dist/ui/renderer/fading.js +23 -20
  26. package/dist/ui/renderer/index.d.ts +1 -0
  27. package/dist/ui/renderer/index.d.ts.map +1 -1
  28. package/dist/ui/renderer/index.js +1 -0
  29. package/dist/ui/renderer/notes.d.ts.map +1 -1
  30. package/dist/ui/renderer/notes.js +7 -4
  31. package/dist/ui/renderer/riffle.d.ts +3 -0
  32. package/dist/ui/renderer/riffle.d.ts.map +1 -0
  33. package/dist/ui/renderer/riffle.js +106 -0
  34. package/package.json +6 -6
@@ -2,11 +2,15 @@ import { SampleLoaderManager, SoundfontLoaderManager } from "@opendaw/studio-ada
2
2
  import { Editing, Func } from "@opendaw/lib-std";
3
3
  import { BoxGraph } from "@opendaw/lib-box";
4
4
  import { AudioWorklets } from "../AudioWorklets";
5
+ import { SampleService } from "../samples";
6
+ import { SoundfontService } from "../soundfont";
5
7
  export interface ProjectEnv {
6
8
  audioContext: AudioContext;
7
9
  audioWorklets: AudioWorklets;
8
10
  sampleManager: SampleLoaderManager;
9
11
  soundfontManager: SoundfontLoaderManager;
12
+ sampleService: SampleService;
13
+ soundfontService: SoundfontService;
10
14
  createEditing?: Func<BoxGraph, Editing>;
11
15
  }
12
16
  //# sourceMappingURL=ProjectEnv.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../../src/project/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAE,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AACpF,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;AAE9C,MAAM,WAAW,UAAU;IACvB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,mBAAmB,CAAA;IAClC,gBAAgB,EAAE,sBAAsB,CAAA;IACxC,aAAa,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;CAC1C"}
1
+ {"version":3,"file":"ProjectEnv.d.ts","sourceRoot":"","sources":["../../src/project/ProjectEnv.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,mBAAmB,EAAE,sBAAsB,EAAC,MAAM,0BAA0B,CAAA;AACpF,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAC,aAAa,EAAC,MAAM,YAAY,CAAA;AACxC,OAAO,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAA;AAE7C,MAAM,WAAW,UAAU;IACvB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,mBAAmB,CAAA;IAClC,gBAAgB,EAAE,sBAAsB,CAAA;IACxC,aAAa,EAAE,aAAa,CAAA;IAC5B,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,aAAa,CAAC,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;CAC1C"}
@@ -1,5 +1,6 @@
1
- import { Class, Procedure } from "@opendaw/lib-std";
1
+ import { Class } from "@opendaw/lib-std";
2
2
  import { Box } from "@opendaw/lib-box";
3
+ import { AudioData } from "@opendaw/lib-dsp";
3
4
  import { Sample } from "@opendaw/studio-adapters";
4
5
  import { AssetService } from "../AssetService";
5
6
  export declare class SampleService extends AssetService<Sample> {
@@ -9,8 +10,9 @@ export declare class SampleService extends AssetService<Sample> {
9
10
  protected readonly nameSingular: string;
10
11
  protected readonly boxType: Class<Box>;
11
12
  protected readonly filePickerOptions: FilePickerOptions;
12
- constructor(audioContext: AudioContext, onUpdate: Procedure<Sample>);
13
- importFile({ uuid, name, arrayBuffer, progressHandler }: AssetService.ImportArgs): Promise<Sample>;
13
+ constructor(audioContext: AudioContext);
14
+ importRecording(audioData: AudioData, name?: string): Promise<Sample>;
15
+ importFile({ uuid, name, arrayBuffer, progressHandler, origin }: AssetService.ImportArgs): Promise<Sample>;
14
16
  protected collectAllFiles(): Promise<ReadonlyArray<Sample>>;
15
17
  }
16
18
  //# sourceMappingURL=SampleService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAe,SAAS,EAA2B,MAAM,kBAAkB,CAAA;AAChG,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAKpC,OAAO,EAAC,MAAM,EAAiB,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAO5C,qBAAa,aAAc,SAAQ,YAAY,CAAC,MAAM,CAAC;;IAMvC,QAAQ,CAAC,YAAY,EAAE,YAAY;IAL/C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAW;IAClD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAe;IACrD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAiC;gBAEnE,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC;IAItE,UAAU,CAAC,EAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,eAAgC,EAAC,EACzD,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;cAyB5C,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;CAkBpE"}
1
+ {"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAA2B,MAAM,kBAAkB,CAAA;AACxE,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AACpC,OAAO,EAAC,SAAS,EAAc,MAAM,kBAAkB,CAAA;AAIvD,OAAO,EAAC,MAAM,EAAiB,MAAM,0BAA0B,CAAA;AAC/D,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAO5C,qBAAa,aAAc,SAAQ,YAAY,CAAC,MAAM,CAAC;;IAMvC,QAAQ,CAAC,YAAY,EAAE,YAAY;IAL/C,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAW;IAClD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAe;IACrD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAiC;gBAEnE,YAAY,EAAE,YAAY;IAEzC,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,GAAE,MAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;IAUlF,UAAU,CAAC,EAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,eAAgC,EAAE,MAAiB,EAAC,EAC5E,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC;cAyB5C,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;CAkBpE"}
@@ -1,4 +1,4 @@
1
- import { Arrays, isUndefined, Progress, tryCatch, UUID } from "@opendaw/lib-std";
1
+ import { Arrays, Progress, tryCatch, UUID } from "@opendaw/lib-std";
2
2
  import { AudioData, estimateBpm } from "@opendaw/lib-dsp";
3
3
  import { Promises } from "@opendaw/lib-runtime";
4
4
  import { SamplePeaks } from "@opendaw/lib-fusion";
@@ -15,11 +15,20 @@ export class SampleService extends AssetService {
15
15
  nameSingular = "Sample";
16
16
  boxType = AudioFileBox;
17
17
  filePickerOptions = FilePickerAcceptTypes.WavFiles;
18
- constructor(audioContext, onUpdate) {
19
- super(onUpdate);
18
+ constructor(audioContext) {
19
+ super();
20
20
  this.audioContext = audioContext;
21
21
  }
22
- async importFile({ uuid, name, arrayBuffer, progressHandler = Progress.Empty }) {
22
+ async importRecording(audioData, name = "Recording") {
23
+ const arrayBuffer = WavFile.encodeFloats({
24
+ frames: audioData.frames.slice(),
25
+ numberOfFrames: audioData.numberOfFrames,
26
+ numberOfChannels: audioData.numberOfChannels,
27
+ sampleRate: audioData.sampleRate
28
+ });
29
+ return this.importFile({ name, arrayBuffer, origin: "recording" });
30
+ }
31
+ async importFile({ uuid, name, arrayBuffer, progressHandler = Progress.Empty, origin = "import" }) {
23
32
  console.debug(`importSample '${name}' (${arrayBuffer.byteLength >> 10}kb)`);
24
33
  uuid ??= await UUID.sha256(arrayBuffer);
25
34
  const audioData = await this.#decodeAudio(arrayBuffer);
@@ -28,14 +37,14 @@ export class SampleService extends AssetService {
28
37
  const peaks = await Workers.Peak.generateAsync(progressHandler, shifts, audioData.frames, audioData.numberOfFrames, audioData.numberOfChannels);
29
38
  const meta = {
30
39
  bpm: estimateBpm(duration),
31
- name: isUndefined(name) ? "Unnnamed" : name,
40
+ name: name ?? "Unnnamed",
32
41
  duration,
33
42
  sample_rate: audioData.sampleRate,
34
- origin: "import"
43
+ origin
35
44
  };
36
45
  await SampleStorage.get().save({ uuid, audio: audioData, peaks, meta });
37
46
  const sample = { uuid: UUID.toString(uuid), ...meta };
38
- this.onUpdate(sample);
47
+ this.notifier.notify(sample);
39
48
  return sample;
40
49
  }
41
50
  async collectAllFiles() {
@@ -1,4 +1,4 @@
1
- import { Class, Option, Procedure } from "@opendaw/lib-std";
1
+ import { Class, Option } from "@opendaw/lib-std";
2
2
  import { Box } from "@opendaw/lib-box";
3
3
  import { Soundfont } from "@opendaw/studio-adapters";
4
4
  import { AssetService } from "../AssetService";
@@ -8,7 +8,7 @@ export declare class SoundfontService extends AssetService<Soundfont> {
8
8
  protected readonly nameSingular: string;
9
9
  protected readonly boxType: Class<Box>;
10
10
  protected readonly filePickerOptions: FilePickerOptions;
11
- constructor(onUpdate: Procedure<Soundfont>);
11
+ constructor();
12
12
  get local(): Option<ReadonlyArray<Soundfont>>;
13
13
  get remote(): Option<ReadonlyArray<Soundfont>>;
14
14
  importFile({ uuid, arrayBuffer }: AssetService.ImportArgs): Promise<Soundfont>;
@@ -1 +1 @@
1
- {"version":3,"file":"SoundfontService.d.ts","sourceRoot":"","sources":["../../src/soundfont/SoundfontService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,EAAS,SAAS,EAAwB,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAGpC,OAAO,EAAC,SAAS,EAAoB,MAAM,0BAA0B,CAAA;AAIrE,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAG5C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,SAAS,CAAC;;IACzD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAc;IACrD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAmB;IACzD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAuC;gBAKlF,QAAQ,EAAE,SAAS,CAAC,SAAS,CAAC;IAY1C,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAqB;IAClE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAsB;IAE9D,UAAU,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;cA4ClE,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAKvE"}
1
+ {"version":3,"file":"SoundfontService.d.ts","sourceRoot":"","sources":["../../src/soundfont/SoundfontService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAE,MAAM,EAA+B,MAAM,kBAAkB,CAAA;AACpF,OAAO,EAAC,GAAG,EAAC,MAAM,kBAAkB,CAAA;AAGpC,OAAO,EAAC,SAAS,EAAoB,MAAM,0BAA0B,CAAA;AAIrE,OAAO,EAAC,YAAY,EAAC,MAAM,iBAAiB,CAAA;AAG5C,qBAAa,gBAAiB,SAAQ,YAAY,CAAC,SAAS,CAAC;;IACzD,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAe;IACpD,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAc;IACrD,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,CAAmB;IACzD,SAAS,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAAuC;;IAgB9F,IAAI,KAAK,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAqB;IAClE,IAAI,MAAM,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAsB;IAE9D,UAAU,CAAC,EAAC,IAAI,EAAE,WAAW,EAAC,EAAE,YAAY,CAAC,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC;cA4ClE,eAAe,IAAI,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;CAKvE"}
@@ -13,8 +13,8 @@ export class SoundfontService extends AssetService {
13
13
  filePickerOptions = FilePickerAcceptTypes.SoundfontFiles;
14
14
  #local = Option.None;
15
15
  #remote = Option.None;
16
- constructor(onUpdate) {
17
- super(onUpdate);
16
+ constructor() {
17
+ super();
18
18
  Promise.all([
19
19
  SoundfontStorage.get().list(),
20
20
  OpenSoundfontAPI.get().all()
@@ -64,7 +64,7 @@ export class SoundfontService extends AssetService {
64
64
  if (!list.some(other => other.uuid === soundfont.uuid)) {
65
65
  list.push(soundfont);
66
66
  }
67
- this.onUpdate(soundfont);
67
+ this.notifier.notify(soundfont);
68
68
  updater.terminate();
69
69
  return soundfont;
70
70
  }
@@ -1,9 +1,21 @@
1
1
  import { RegionBound } from "./env";
2
2
  import { Option } from "@opendaw/lib-std";
3
3
  import { LoopableRegion, TempoMap } from "@opendaw/lib-dsp";
4
+ import { Peaks } from "@opendaw/lib-fusion";
4
5
  import { AudioFileBoxAdapter, AudioPlayMode } from "@opendaw/studio-adapters";
5
6
  import { TimelineRange } from "../timeline/TimelineRange";
6
7
  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
+ type Segment = {
9
+ x0: number;
10
+ x1: number;
11
+ u0: number;
12
+ u1: number;
13
+ outside: boolean;
14
+ };
15
+ interface Strategy {
16
+ render(context: CanvasRenderingContext2D, segments: ReadonlyArray<Segment>, peaks: Peaks, bound: RegionBound, gain: number): void;
17
+ }
18
+ const DefaultStrategy: Strategy;
19
+ const render: (context: CanvasRenderingContext2D, range: TimelineRange, file: AudioFileBoxAdapter, tempoMap: TempoMap, playMode: Option<AudioPlayMode>, waveformOffset: number, gain: number, bound: RegionBound, contentColor: string, { rawStart, resultStart, resultEnd }: LoopableRegion.LoopCycle, clip?: boolean, strategy?: Strategy) => void;
8
20
  }
9
21
  //# sourceMappingURL=audio.d.ts.map
@@ -1 +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"}
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;AAC1F,OAAO,EAAC,KAAK,EAAe,MAAM,qBAAqB,CAAA;AACvD,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,0BAA0B,CAAA;AAC3E,OAAO,EAAC,aAAa,EAAC,MAAM,2BAA2B,CAAA;AAEvD,yBAAiB,aAAa,CAAC;IAC3B,KAAY,OAAO,GAAG;QAClB,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,MAAM,CAAA;QACV,EAAE,EAAE,MAAM,CAAA;QACV,OAAO,EAAE,OAAO,CAAA;KACnB,CAAA;IAED,UAAiB,QAAQ;QACrB,MAAM,CAAC,OAAO,EAAE,wBAAwB,EACjC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;KAC7B;IAEM,MAAM,eAAe,EAAE,QAyB7B,CAAA;IAEM,MAAM,MAAM,GAAI,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,OAAO,WAAW,EAClB,cAAc,MAAM,EACpB,sCAAoC,cAAc,CAAC,SAAS,EAC5D,OAAM,OAAc,EACpB,WAAU,QAA0B,SAyU1D,CAAA;CACJ"}
@@ -2,17 +2,39 @@ import { dbToGain, PPQN, TempoChangeGrid } from "@opendaw/lib-dsp";
2
2
  import { PeaksPainter } from "@opendaw/lib-fusion";
3
3
  export var AudioRenderer;
4
4
  (function (AudioRenderer) {
5
- AudioRenderer.render = (context, range, file, tempoMap, playMode, waveformOffset, gain, { top, bottom }, contentColor, { rawStart, resultStart, resultEnd }, clip = true) => {
5
+ AudioRenderer.DefaultStrategy = {
6
+ render(context, segments, peaks, { top, bottom }, gain) {
7
+ const dpr = devicePixelRatio;
8
+ const actualTop = top * dpr;
9
+ const actualBottom = bottom * dpr;
10
+ const height = actualBottom - actualTop;
11
+ const numberOfChannels = peaks.numChannels;
12
+ const peaksHeight = Math.floor((height - 4) / numberOfChannels);
13
+ const scale = dbToGain(-gain);
14
+ for (const { x0, x1, u0, u1, outside } of segments) {
15
+ context.globalAlpha = outside ? 0.25 : 1.0;
16
+ for (let channel = 0; channel < numberOfChannels; channel++) {
17
+ PeaksPainter.renderPixelStrips(context, peaks, channel, {
18
+ u0,
19
+ u1,
20
+ v0: -scale,
21
+ v1: +scale,
22
+ x0,
23
+ x1,
24
+ y0: 3 + actualTop + channel * peaksHeight,
25
+ y1: 3 + actualTop + (channel + 1) * peaksHeight
26
+ });
27
+ }
28
+ }
29
+ }
30
+ };
31
+ AudioRenderer.render = (context, range, file, tempoMap, playMode, waveformOffset, gain, bound, contentColor, { rawStart, resultStart, resultEnd }, clip = true, strategy = AudioRenderer.DefaultStrategy) => {
6
32
  if (file.peaks.isEmpty()) {
7
33
  return;
8
34
  }
9
35
  const peaks = file.peaks.unwrap();
10
36
  const durationInSeconds = file.endInSeconds - file.startInSeconds;
11
37
  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
38
  const segments = [];
17
39
  if (playMode.nonEmpty()) {
18
40
  const { warpMarkers } = playMode.unwrap();
@@ -258,20 +280,6 @@ export var AudioRenderer;
258
280
  }
259
281
  }
260
282
  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
- }
283
+ strategy.render(context, segments, peaks, bound, gain);
276
284
  };
277
285
  })(AudioRenderer || (AudioRenderer = {}));
@@ -1 +1 @@
1
- {"version":3,"file":"fading.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/fading.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AAEjC,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,QAAQ,cAAc,CAAC,MAAM,EAC7B,iBAAe,WAAW,EAC1B,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,OAAO,MAAM,KAAG,IAkDtC,CAAA;CACJ"}
1
+ {"version":3,"file":"fading.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/fading.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,aAAa,EAAC,MAAM,aAAa,CAAA;AACzC,OAAO,EAAC,WAAW,EAAC,MAAM,OAAO,CAAA;AAEjC,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,QAAQ,cAAc,CAAC,MAAM,EAC7B,iBAAe,WAAW,EAC1B,WAAW,MAAM,EACjB,SAAS,MAAM,EACf,OAAO,MAAM,KAAG,IAqDtC,CAAA;CACJ"}
@@ -2,6 +2,9 @@ import { Curve, TAU } from "@opendaw/lib-std";
2
2
  export var AudioFadingRenderer;
3
3
  (function (AudioFadingRenderer) {
4
4
  AudioFadingRenderer.render = (context, range, fading, { top, bottom }, startPPQN, endPPQN, color) => {
5
+ const dpr = devicePixelRatio;
6
+ const actualTop = top * dpr;
7
+ const actualBottom = bottom * dpr;
5
8
  const { inSlope: fadeInSlope, outSlope: fadeOutSlope } = fading;
6
9
  const duration = endPPQN - startPPQN;
7
10
  const totalFading = fading.in + fading.out;
@@ -10,46 +13,46 @@ export var AudioFadingRenderer;
10
13
  const fadeOut = fading.out * scale;
11
14
  context.strokeStyle = color;
12
15
  context.fillStyle = "rgba(0,0,0,0.25)";
13
- context.lineWidth = devicePixelRatio;
16
+ context.lineWidth = dpr;
14
17
  if (fadeIn > 0) {
15
18
  const fadeInEndPPQN = startPPQN + fadeIn;
16
- const x0 = range.unitToX(startPPQN) * devicePixelRatio;
17
- const x1 = range.unitToX(fadeInEndPPQN) * devicePixelRatio;
19
+ const x0 = range.unitToX(startPPQN) * dpr;
20
+ const x1 = range.unitToX(fadeInEndPPQN) * dpr;
18
21
  const xn = x1 - x0;
19
22
  const path = new Path2D();
20
- path.moveTo(x0, bottom);
23
+ path.moveTo(x0, actualBottom);
21
24
  let x = x0;
22
- Curve.run(fadeInSlope, xn, bottom, top, y => path.lineTo(++x, y));
23
- path.lineTo(x1, top);
25
+ Curve.run(fadeInSlope, xn, actualBottom, actualTop, y => path.lineTo(++x, y));
26
+ path.lineTo(x1, actualTop);
24
27
  context.stroke(path);
25
- path.lineTo(x0, top);
26
- path.lineTo(x0, bottom);
28
+ path.lineTo(x0, actualTop);
29
+ path.lineTo(x0, actualBottom);
27
30
  context.fill(path);
28
31
  }
29
32
  if (fadeOut > 0) {
30
- const x0 = range.unitToX(endPPQN - fadeOut) * devicePixelRatio;
31
- const x1 = range.unitToX(endPPQN) * devicePixelRatio;
33
+ const x0 = range.unitToX(endPPQN - fadeOut) * dpr;
34
+ const x1 = range.unitToX(endPPQN) * dpr;
32
35
  const xn = x1 - x0;
33
36
  const path = new Path2D();
34
- path.moveTo(x0, top);
37
+ path.moveTo(x0, actualTop);
35
38
  let x = x0;
36
- Curve.run(fadeOutSlope, xn, top, bottom, y => path.lineTo(++x, y));
37
- path.lineTo(x1, bottom);
39
+ Curve.run(fadeOutSlope, xn, actualTop, actualBottom, y => path.lineTo(++x, y));
40
+ path.lineTo(x1, actualBottom);
38
41
  context.strokeStyle = color;
39
42
  context.stroke(path);
40
- path.lineTo(x1, top);
41
- path.lineTo(x0, top);
43
+ path.lineTo(x1, actualTop);
44
+ path.lineTo(x0, actualTop);
42
45
  context.fill(path);
43
46
  }
44
- const handleRadius = 1.5 * devicePixelRatio;
45
- const x0 = Math.max(range.unitToX(startPPQN + fadeIn), range.unitToX(startPPQN)) * devicePixelRatio;
46
- const x1 = Math.min(range.unitToX(endPPQN - fadeOut), range.unitToX(endPPQN)) * devicePixelRatio;
47
+ const handleRadius = 1.5 * dpr;
48
+ const x0 = Math.max(range.unitToX(startPPQN + fadeIn), range.unitToX(startPPQN)) * dpr;
49
+ const x1 = Math.min(range.unitToX(endPPQN - fadeOut), range.unitToX(endPPQN)) * dpr;
47
50
  context.fillStyle = color;
48
51
  context.beginPath();
49
- context.arc(x0, top, handleRadius, 0, TAU);
52
+ context.arc(x0, actualTop, handleRadius, 0, TAU);
50
53
  context.fill();
51
54
  context.beginPath();
52
- context.arc(x1, top, handleRadius, 0, TAU);
55
+ context.arc(x1, actualTop, handleRadius, 0, TAU);
53
56
  context.fill();
54
57
  };
55
58
  })(AudioFadingRenderer || (AudioFadingRenderer = {}));
@@ -2,5 +2,6 @@ export * from "./audio";
2
2
  export * from "./env";
3
3
  export * from "./fading";
4
4
  export * from "./notes";
5
+ export * from "./riffle";
5
6
  export * from "./value";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAA;AACvB,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA"}
@@ -2,4 +2,5 @@ export * from "./audio";
2
2
  export * from "./env";
3
3
  export * from "./fading";
4
4
  export * from "./notes";
5
+ export * from "./riffle";
5
6
  export * from "./value";
@@ -1 +1 @@
1
- {"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,6BAA6B,EAAC,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,WAAW,EAAE,aAAa,EAAC,MAAM,aAAa,CAAA;AAEtD,yBAAiB,aAAa,CAAC;IACpB,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,YAAY,6BAA6B,EACzC,iBAAe,WAAW,EAC1B,cAAc,MAAM,EACpB,mDAAiD,cAAc,CAAC,SAAS,SAgB/F,CAAA;CACJ"}
1
+ {"version":3,"file":"notes.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/notes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,6BAA6B,EAAC,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAC,WAAW,EAAE,aAAa,EAAC,MAAM,aAAa,CAAA;AAEtD,yBAAiB,aAAa,CAAC;IACpB,MAAM,MAAM,GAAI,SAAS,wBAAwB,EACjC,OAAO,aAAa,EACpB,YAAY,6BAA6B,EACzC,iBAAe,WAAW,EAC1B,cAAc,MAAM,EACpB,mDAAiD,cAAc,CAAC,SAAS,SAmB/F,CAAA;CACJ"}
@@ -1,7 +1,10 @@
1
1
  export var NotesRenderer;
2
2
  (function (NotesRenderer) {
3
3
  NotesRenderer.render = (context, range, collection, { top, bottom }, contentColor, { rawStart, regionStart, resultStart, resultEnd }) => {
4
- const height = bottom - top;
4
+ const dpr = devicePixelRatio;
5
+ const actualTop = top * dpr;
6
+ const actualBottom = bottom * dpr;
7
+ const height = actualBottom - actualTop;
5
8
  context.fillStyle = contentColor;
6
9
  const padding = 8;
7
10
  const noteHeight = 5;
@@ -13,9 +16,9 @@ export var NotesRenderer;
13
16
  continue;
14
17
  }
15
18
  const complete = Math.min(rawStart + note.complete, resultEnd);
16
- const x0 = Math.floor(range.unitToX(position) * devicePixelRatio);
17
- const x1 = Math.floor(range.unitToX(complete) * devicePixelRatio);
18
- const y = top + padding + Math.floor(note.normalizedPitch() * (height - (padding * 2 + noteHeight)));
19
+ const x0 = Math.floor(range.unitToX(position) * dpr);
20
+ const x1 = Math.floor(range.unitToX(complete) * dpr);
21
+ const y = actualTop + padding + Math.floor(note.normalizedPitch() * (height - (padding * 2 + noteHeight)));
19
22
  context.fillRect(x0, y, Math.max(1, x1 - x0), noteHeight);
20
23
  }
21
24
  };
@@ -0,0 +1,3 @@
1
+ import { AudioRenderer } from "./audio";
2
+ export declare const RiffleStrategy: AudioRenderer.Strategy;
3
+ //# sourceMappingURL=riffle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"riffle.d.ts","sourceRoot":"","sources":["../../../src/ui/renderer/riffle.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,aAAa,EAAC,MAAM,SAAS,CAAA;AAErC,eAAO,MAAM,cAAc,EAAE,aAAa,CAAC,QAuF1C,CAAA"}
@@ -0,0 +1,106 @@
1
+ import { dbToGain } from "@opendaw/lib-dsp";
2
+ import { Peaks } from "@opendaw/lib-fusion";
3
+ export const RiffleStrategy = {
4
+ render(context, segments, peaks, { top, bottom }, gain) {
5
+ if (segments.length === 0) {
6
+ return;
7
+ }
8
+ const dpr = devicePixelRatio;
9
+ const actualTop = top * dpr;
10
+ const actualBottom = bottom * dpr;
11
+ const height = actualBottom - actualTop;
12
+ const numberOfChannels = peaks.numChannels;
13
+ const peaksHeight = Math.floor(height / numberOfChannels);
14
+ const gainScale = dbToGain(-gain);
15
+ const blockWidth = 3 * dpr;
16
+ // noinspection PointlessArithmeticExpressionJS
17
+ const gap = dpr * 1;
18
+ const pixelsPerBlock = blockWidth + gap;
19
+ let globalX0 = Infinity;
20
+ let globalX1 = -Infinity;
21
+ for (const { x0, x1 } of segments) {
22
+ globalX0 = Math.min(globalX0, Math.floor(x0));
23
+ globalX1 = Math.max(globalX1, Math.floor(x1));
24
+ }
25
+ if (globalX0 >= globalX1) {
26
+ return;
27
+ }
28
+ const seg0 = segments[0];
29
+ const pxPerUnit = (seg0.x1 - seg0.x0) / (seg0.u1 - seg0.u0);
30
+ const anchorX = seg0.x0 - seg0.u0 * pxPerUnit;
31
+ const gridPhase = ((globalX0 - anchorX) % pixelsPerBlock + pixelsPerBlock) % pixelsPerBlock;
32
+ const firstBlockX = globalX0 - gridPhase;
33
+ for (let channel = 0; channel < numberOfChannels; channel++) {
34
+ const data = peaks.data[channel];
35
+ const channelY0 = actualTop + channel * peaksHeight;
36
+ const channelY1 = actualTop + (channel + 1) * peaksHeight;
37
+ const centerY = (channelY0 + channelY1) / 2;
38
+ const yScale = (channelY1 - channelY0 - 1.0) / (gainScale * 2);
39
+ for (let bx = firstBlockX; bx < globalX1; bx += pixelsPerBlock) {
40
+ const bxEnd = bx + pixelsPerBlock;
41
+ let blockMin = 0.0;
42
+ let blockMax = 0.0;
43
+ let blockAlpha = 0.0;
44
+ let hasData = false;
45
+ for (const seg of segments) {
46
+ const segX0 = Math.floor(seg.x0);
47
+ const segX1 = Math.floor(seg.x1);
48
+ if (segX0 >= bxEnd || segX1 <= bx) {
49
+ continue;
50
+ }
51
+ const pixelSpan = seg.x1 - seg.x0;
52
+ if (pixelSpan <= 0) {
53
+ continue;
54
+ }
55
+ const uPerPx = (seg.u1 - seg.u0) / pixelSpan;
56
+ const stage = peaks.nearest(uPerPx);
57
+ if (stage === null) {
58
+ continue;
59
+ }
60
+ const uPerPeak = stage.unitsEachPeak();
61
+ const peaksPerPx = uPerPx / uPerPeak;
62
+ const overflow = seg.x0 - segX0;
63
+ const fromAtX0 = (seg.u0 - overflow * uPerPx) / uPerPx * peaksPerPx;
64
+ const overlapStart = Math.max(bx, segX0);
65
+ const overlapEnd = Math.min(bxEnd, segX1);
66
+ const fromPeak = fromAtX0 + (overlapStart - segX0) * peaksPerPx;
67
+ const toPeak = fromAtX0 + (overlapEnd - segX0) * peaksPerPx;
68
+ const idxFrom = Math.max(0, Math.floor(fromPeak));
69
+ const idxTo = Math.floor(toPeak);
70
+ for (let idx = idxFrom; idx < idxTo; idx++) {
71
+ const bits = data[stage.dataOffset + idx];
72
+ blockMin = Math.min(Peaks.unpack(bits, 0), blockMin);
73
+ blockMax = Math.max(Peaks.unpack(bits, 1), blockMax);
74
+ }
75
+ if (idxFrom < idxTo) {
76
+ hasData = true;
77
+ }
78
+ blockAlpha = Math.max(blockAlpha, seg.outside ? 0.25 : 1.0);
79
+ }
80
+ if (!hasData) {
81
+ continue;
82
+ }
83
+ context.globalAlpha = blockAlpha;
84
+ const x = Math.max(bx, globalX0);
85
+ const w = Math.min(blockWidth, Math.min(bxEnd, globalX1) - x);
86
+ if (w <= 0) {
87
+ continue;
88
+ }
89
+ const yMin = channelY0 + Math.floor((blockMin + gainScale) * yScale);
90
+ const yMax = channelY0 + Math.floor((blockMax + gainScale) * yScale);
91
+ const ry0 = Math.max(channelY0, Math.min(yMin, yMax));
92
+ const ry1 = Math.min(channelY1, Math.max(yMin, yMax));
93
+ const finalY1 = ry0 === ry1 ? ry0 + 1 : ry1;
94
+ const maxDist = Math.max(centerY - ry0, finalY1 - centerY);
95
+ const symY0 = centerY - maxDist;
96
+ const symY1 = centerY + maxDist;
97
+ const h = symY1 - symY0;
98
+ const r = Math.min(dpr, w / 2, h / 2);
99
+ context.beginPath();
100
+ context.roundRect(x, symY0, w, h, r);
101
+ context.fill();
102
+ }
103
+ }
104
+ context.globalAlpha = 1.0;
105
+ }
106
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opendaw/studio-core",
3
- "version": "0.0.122",
3
+ "version": "0.0.124",
4
4
  "license": "LGPL-3.0-or-later",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -37,11 +37,11 @@
37
37
  "@opendaw/lib-dawproject": "^0.0.63",
38
38
  "@opendaw/lib-dom": "^0.0.77",
39
39
  "@opendaw/lib-dsp": "^0.0.77",
40
- "@opendaw/lib-fusion": "^0.0.84",
40
+ "@opendaw/lib-fusion": "^0.0.85",
41
41
  "@opendaw/lib-runtime": "^0.0.73",
42
42
  "@opendaw/lib-std": "^0.0.72",
43
43
  "@opendaw/nam-wasm": "^1.0.3",
44
- "@opendaw/studio-adapters": "^0.0.98",
44
+ "@opendaw/studio-adapters": "^0.0.99",
45
45
  "@opendaw/studio-boxes": "^0.0.83",
46
46
  "@opendaw/studio-enums": "^0.0.68",
47
47
  "dropbox": "^10.34.0",
@@ -57,10 +57,10 @@
57
57
  "@ffmpeg/ffmpeg": "^0.12.15",
58
58
  "@ffmpeg/util": "^0.12.2",
59
59
  "@opendaw/eslint-config": "^0.0.27",
60
- "@opendaw/studio-core-processors": "^0.0.101",
61
- "@opendaw/studio-core-workers": "^0.0.93",
60
+ "@opendaw/studio-core-processors": "^0.0.103",
61
+ "@opendaw/studio-core-workers": "^0.0.94",
62
62
  "@opendaw/studio-forge-boxes": "^0.0.83",
63
63
  "@opendaw/typescript-config": "^0.0.29"
64
64
  },
65
- "gitHead": "318e323aeb53ffe41c138d021da4d40fe2452374"
65
+ "gitHead": "bcacc3de31ba8c899be229f7ca0b9186a21cd290"
66
66
  }