@opendaw/studio-core 0.0.121 → 0.0.123

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 (46) 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/EffectBox.d.ts +2 -2
  5. package/dist/EffectBox.d.ts.map +1 -1
  6. package/dist/EffectFactories.d.ts +3 -0
  7. package/dist/EffectFactories.d.ts.map +1 -1
  8. package/dist/EffectFactories.js +15 -1
  9. package/dist/RecordingWorklet.d.ts +2 -0
  10. package/dist/RecordingWorklet.d.ts.map +1 -1
  11. package/dist/RecordingWorklet.js +8 -25
  12. package/dist/capture/CaptureAudio.d.ts.map +1 -1
  13. package/dist/capture/CaptureAudio.js +2 -1
  14. package/dist/capture/RecordMidi.d.ts.map +1 -1
  15. package/dist/capture/RecordMidi.js +24 -2
  16. package/dist/offline-engine.js +1 -1
  17. package/dist/offline-engine.js.map +1 -1
  18. package/dist/processors.js +25 -25
  19. package/dist/processors.js.map +4 -4
  20. package/dist/project/ProjectEnv.d.ts +4 -0
  21. package/dist/project/ProjectEnv.d.ts.map +1 -1
  22. package/dist/project/audio/AudioContentFactory.d.ts +2 -1
  23. package/dist/project/audio/AudioContentFactory.d.ts.map +1 -1
  24. package/dist/project/audio/AudioContentFactory.js +8 -7
  25. package/dist/samples/SampleService.d.ts +5 -3
  26. package/dist/samples/SampleService.d.ts.map +1 -1
  27. package/dist/samples/SampleService.js +16 -7
  28. package/dist/soundfont/SoundfontService.d.ts +2 -2
  29. package/dist/soundfont/SoundfontService.d.ts.map +1 -1
  30. package/dist/soundfont/SoundfontService.js +3 -3
  31. package/dist/ui/renderer/audio.d.ts +13 -1
  32. package/dist/ui/renderer/audio.d.ts.map +1 -1
  33. package/dist/ui/renderer/audio.js +28 -20
  34. package/dist/ui/renderer/fading.d.ts.map +1 -1
  35. package/dist/ui/renderer/fading.js +23 -20
  36. package/dist/ui/renderer/index.d.ts +1 -0
  37. package/dist/ui/renderer/index.d.ts.map +1 -1
  38. package/dist/ui/renderer/index.js +1 -0
  39. package/dist/ui/renderer/notes.d.ts.map +1 -1
  40. package/dist/ui/renderer/notes.js +7 -4
  41. package/dist/ui/renderer/riffle.d.ts +3 -0
  42. package/dist/ui/renderer/riffle.d.ts.map +1 -0
  43. package/dist/ui/renderer/riffle.js +106 -0
  44. package/dist/workers-main.js +1 -1
  45. package/dist/workers-main.js.map +1 -1
  46. package/package.json +15 -15
@@ -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"}
@@ -15,6 +15,7 @@ export declare namespace AudioContentFactory {
15
15
  warpMarkers?: ReadonlyArray<WarpMarkerTemplate>;
16
16
  waveformOffset?: number;
17
17
  gainInDb?: number;
18
+ disableQuantize?: boolean;
18
19
  };
19
20
  type Clip = Props & {
20
21
  index: int;
@@ -33,7 +34,7 @@ export declare namespace AudioContentFactory {
33
34
  * Calculates the duration of an audio region based on sample properties.
34
35
  * Returns duration in PPQN for stretched regions, or in seconds for non-stretched.
35
36
  */
36
- const calculateDuration: (sample: Sample) => ppqn;
37
+ const calculateDuration: (sample: Sample, disableQuantize?: boolean) => ppqn;
37
38
  const createTimeStretchedRegion: (props: TimeStretchedProps & Region) => AudioRegionBox;
38
39
  const createPitchStretchedRegion: (props: PitchStretchedProps & Region) => AudioRegionBox;
39
40
  const createNotStretchedRegion: (props: NotStretchedProps & Region) => AudioRegionBox;
@@ -1 +1 @@
1
- {"version":3,"file":"AudioContentFactory.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAiB,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAa,MAAM,EAAY,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,GAAG,EAAuC,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EACH,YAAY,EACZ,YAAY,EAEZ,cAAc,EAEd,QAAQ,EAEX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AAEvD,yBAAiB,mBAAmB,CAAC;IACjC,KAAY,KAAK,GAAG;QAChB,QAAQ,EAAE,QAAQ,CAAA;QAClB,WAAW,EAAE,QAAQ,CAAA;QACrB,YAAY,EAAE,YAAY,CAAA;QAC1B,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;QACxB,WAAW,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;QAC/C,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;IAED,KAAY,IAAI,GAAG,KAAK,GAAG;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,CAAA;IACzC,KAAY,MAAM,GAAG,KAAK,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAE9D,KAAY,kBAAkB,GAAG;QAC7B,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;QACrC,YAAY,CAAC,EAAE,MAAM,CAAA;KACxB,GAAG,KAAK,CAAA;IAET,KAAY,mBAAmB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAEpF,KAAY,iBAAiB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAElF;;;OAGG;IACI,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,IAQlD,CAAA;IAIM,MAAM,yBAAyB,GAAI,OAAO,kBAAkB,GAAG,MAAM,KAAG,cAM9E,CAAA;IAEM,MAAM,0BAA0B,GAAI,OAAO,mBAAmB,GAAG,MAAM,KAAG,cAEhF,CAAA;IAEM,MAAM,wBAAwB,GAAI,OAAO,iBAAiB,GAAG,MAAM,KAAG,cAgB5E,CAAA;IAIM,MAAM,uBAAuB,GAAI,OAAO,kBAAkB,GAAG,IAAI,KAAG,YAM1E,CAAA;IAEM,MAAM,wBAAwB,GAAI,OAAO,mBAAmB,GAAG,IAAI,KAAG,YAG5E,CAAA;IAEM,MAAM,sBAAsB,GAAI,OAAO,iBAAiB,GAAG,IAAI,KAAG,YAcxE,CAAA;CA6DJ"}
1
+ {"version":3,"file":"AudioContentFactory.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentFactory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,IAAI,EAAiB,MAAM,kBAAkB,CAAA;AACrD,OAAO,EAAa,MAAM,EAAY,MAAM,0BAA0B,CAAA;AACtE,OAAO,EAAC,GAAG,EAAwC,MAAM,kBAAkB,CAAA;AAC3E,OAAO,EACH,YAAY,EACZ,YAAY,EAEZ,cAAc,EAEd,QAAQ,EAEX,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AAEzC,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AAEvD,yBAAiB,mBAAmB,CAAC;IACjC,KAAY,KAAK,GAAG;QAChB,QAAQ,EAAE,QAAQ,CAAA;QAClB,WAAW,EAAE,QAAQ,CAAA;QACrB,YAAY,EAAE,YAAY,CAAA;QAC1B,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,CAAC,EAAE,IAAI,GAAG,MAAM,CAAA;QACxB,WAAW,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;QAC/C,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,eAAe,CAAC,EAAE,OAAO,CAAA;KAC5B,CAAA;IAED,KAAY,IAAI,GAAG,KAAK,GAAG;QAAE,KAAK,EAAE,GAAG,CAAA;KAAE,CAAA;IACzC,KAAY,MAAM,GAAG,KAAK,GAAG;QAAE,QAAQ,EAAE,IAAI,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAE9D,KAAY,kBAAkB,GAAG;QAC7B,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;QACrC,YAAY,CAAC,EAAE,MAAM,CAAA;KACxB,GAAG,KAAK,CAAA;IAET,KAAY,mBAAmB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAEpF,KAAY,iBAAiB,GAAG,EAA0C,GAAG,KAAK,CAAA;IAElF;;;OAGG;IACI,MAAM,iBAAiB,GAAI,QAAQ,MAAM,EAAE,kBAAiB,OAAe,KAAG,IAOpF,CAAA;IAIM,MAAM,yBAAyB,GAAI,OAAO,kBAAkB,GAAG,MAAM,KAAG,cAM9E,CAAA;IAEM,MAAM,0BAA0B,GAAI,OAAO,mBAAmB,GAAG,MAAM,KAAG,cAEhF,CAAA;IAEM,MAAM,wBAAwB,GAAI,OAAO,iBAAiB,GAAG,MAAM,KAAG,cAgB5E,CAAA;IAIM,MAAM,uBAAuB,GAAI,OAAO,kBAAkB,GAAG,IAAI,KAAG,YAM1E,CAAA;IAEM,MAAM,wBAAwB,GAAI,OAAO,mBAAmB,GAAG,IAAI,KAAG,YAG5E,CAAA;IAEM,MAAM,sBAAsB,GAAI,OAAO,iBAAiB,GAAG,IAAI,KAAG,YAcxE,CAAA;CA+DJ"}
@@ -1,6 +1,6 @@
1
1
  import { PPQN, TimeBase } from "@opendaw/lib-dsp";
2
2
  import { ColorCodes, TrackType } from "@opendaw/studio-adapters";
3
- import { isDefined, panic, quantizeCeil, UUID } from "@opendaw/lib-std";
3
+ import { isDefined, panic, quantizeRound, UUID } from "@opendaw/lib-std";
4
4
  import { AudioClipBox, AudioPitchStretchBox, AudioRegionBox, AudioTimeStretchBox, ValueEventCollectionBox } from "@opendaw/studio-boxes";
5
5
  import { TransientPlayMode } from "@opendaw/studio-enums";
6
6
  import { AudioContentHelpers } from "./AudioContentHelpers";
@@ -10,14 +10,13 @@ export var AudioContentFactory;
10
10
  * Calculates the duration of an audio region based on sample properties.
11
11
  * Returns duration in PPQN for stretched regions, or in seconds for non-stretched.
12
12
  */
13
- AudioContentFactory.calculateDuration = (sample) => {
13
+ AudioContentFactory.calculateDuration = (sample, disableQuantize = false) => {
14
14
  const { duration: durationInSeconds, bpm } = sample;
15
15
  if (bpm === 0) {
16
- // Non-stretched: duration is in seconds
17
16
  return durationInSeconds;
18
17
  }
19
- // Stretched: duration is in PPQN
20
- return quantizeCeil(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
18
+ const pulses = PPQN.secondsToPulses(durationInSeconds, bpm);
19
+ return disableQuantize ? pulses : quantizeRound(pulses, PPQN.SemiQuaver);
21
20
  };
22
21
  // --- Region Creation --- //
23
22
  AudioContentFactory.createTimeStretchedRegion = (props) => {
@@ -81,7 +80,8 @@ export var AudioContentFactory;
81
80
  return panic("Cannot create audio-region on non-audio track");
82
81
  }
83
82
  const { name, duration: durationInSeconds, bpm } = sample;
84
- const durationInPPQN = props.duration ?? quantizeCeil(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
83
+ const pulses = PPQN.secondsToPulses(durationInSeconds, bpm);
84
+ const durationInPPQN = props.duration ?? (!props.disableQuantize ? quantizeRound(pulses, PPQN.SemiQuaver) : pulses);
85
85
  if (isDefined(props.warpMarkers)) {
86
86
  AudioContentHelpers.addWarpMarkers(boxGraph, playMode, props.warpMarkers);
87
87
  }
@@ -110,7 +110,8 @@ export var AudioContentFactory;
110
110
  return panic("Cannot create audio-region on non-audio track");
111
111
  }
112
112
  const { name, duration: durationInSeconds, bpm } = sample;
113
- const durationInPPQN = props.duration ?? quantizeCeil(PPQN.secondsToPulses(durationInSeconds, bpm), PPQN.SemiQuaver);
113
+ const pulses = PPQN.secondsToPulses(durationInSeconds, bpm);
114
+ const durationInPPQN = props.duration ?? (!props.disableQuantize ? quantizeRound(pulses, PPQN.SemiQuaver) : pulses);
114
115
  if (isDefined(props.warpMarkers)) {
115
116
  AudioContentHelpers.addWarpMarkers(boxGraph, playMode, props.warpMarkers);
116
117
  }
@@ -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
+ };