@opendaw/studio-core 0.0.111 → 0.0.113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AssetService.d.ts.map +1 -1
- package/dist/AssetService.js +15 -4
- package/dist/AudioUnitFreeze.d.ts +15 -0
- package/dist/AudioUnitFreeze.d.ts.map +1 -0
- package/dist/AudioUnitFreeze.js +129 -0
- package/dist/Engine.d.ts +1 -0
- package/dist/Engine.d.ts.map +1 -1
- package/dist/EngineFacade.d.ts +1 -0
- package/dist/EngineFacade.d.ts.map +1 -1
- package/dist/EngineFacade.js +3 -0
- package/dist/EngineWorklet.d.ts +1 -0
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +4 -0
- package/dist/FilePickerAcceptTypes.d.ts +1 -0
- package/dist/FilePickerAcceptTypes.d.ts.map +1 -1
- package/dist/FilePickerAcceptTypes.js +4 -0
- package/dist/OfflineEngineRenderer.d.ts.map +1 -1
- package/dist/OfflineEngineRenderer.js +1 -0
- package/dist/StudioPreferences.d.ts +1 -0
- package/dist/StudioPreferences.d.ts.map +1 -1
- package/dist/StudioSettings.d.ts +1 -0
- package/dist/StudioSettings.d.ts.map +1 -1
- package/dist/StudioSettings.js +4 -2
- package/dist/capture/CaptureDevices.d.ts.map +1 -1
- package/dist/capture/CaptureDevices.js +6 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/offline-engine.js.map +1 -1
- package/dist/processors.js +8 -8
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts +2 -0
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +3 -0
- package/dist/project/ProjectApi.d.ts +3 -3
- package/dist/project/ProjectApi.d.ts.map +1 -1
- package/dist/project/ProjectApi.js +3 -0
- package/dist/project/audio/AudioContentHelpers.d.ts +2 -2
- package/dist/project/audio/AudioContentHelpers.d.ts.map +1 -1
- package/dist/project/audio/AudioContentHelpers.js +1 -1
- package/dist/project/audio/AudioContentModifier.d.ts.map +1 -1
- package/dist/project/audio/AudioContentModifier.js +8 -7
- package/dist/samples/SampleService.d.ts +1 -0
- package/dist/samples/SampleService.d.ts.map +1 -1
- package/dist/samples/SampleService.js +24 -19
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/renderer/audio.d.ts +9 -0
- package/dist/ui/renderer/audio.d.ts.map +1 -0
- package/dist/ui/renderer/audio.js +277 -0
- package/dist/ui/renderer/env.d.ts +5 -0
- package/dist/ui/renderer/env.d.ts.map +1 -0
- package/dist/ui/renderer/env.js +1 -0
- package/dist/ui/renderer/fading.d.ts +7 -0
- package/dist/ui/renderer/fading.d.ts.map +1 -0
- package/dist/ui/renderer/fading.js +55 -0
- package/dist/ui/renderer/index.d.ts +6 -0
- package/dist/ui/renderer/index.d.ts.map +1 -0
- package/dist/ui/renderer/index.js +5 -0
- package/dist/ui/renderer/notes.d.ts +7 -0
- package/dist/ui/renderer/notes.d.ts.map +1 -0
- package/dist/ui/renderer/notes.js +23 -0
- package/dist/ui/renderer/value.d.ts +7 -0
- package/dist/ui/renderer/value.d.ts.map +1 -0
- package/dist/ui/renderer/value.js +101 -0
- package/dist/ui/timeline/RegionClipResolver.d.ts.map +1 -1
- package/dist/ui/timeline/RegionClipResolver.js +19 -23
- package/package.json +15 -15
|
@@ -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":"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;
|
|
1
|
+
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"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"}
|
package/dist/project/Project.js
CHANGED
|
@@ -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()) {
|
|
@@ -2,8 +2,8 @@ import { Attempt, float, int, Observer, Option, Subscription } from "@opendaw/li
|
|
|
2
2
|
import { ppqn } from "@opendaw/lib-dsp";
|
|
3
3
|
import { Field, PointerField } from "@opendaw/lib-box";
|
|
4
4
|
import { Pointers } from "@opendaw/studio-enums";
|
|
5
|
-
import { AudioClipBox, AudioRegionBox, AudioUnitBox, NoteClipBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, TrackBox, ValueClipBox
|
|
6
|
-
import { AnyRegionBoxAdapter, AudioUnitBoxAdapter, EffectPointerType, IndexedAdapterCollectionListener, InstrumentBox, InstrumentFactory, InstrumentOptions, InstrumentProduct } from "@opendaw/studio-adapters";
|
|
5
|
+
import { AudioClipBox, AudioRegionBox, AudioUnitBox, NoteClipBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, TrackBox, ValueClipBox } from "@opendaw/studio-boxes";
|
|
6
|
+
import { AnyRegionBox, AnyRegionBoxAdapter, AudioUnitBoxAdapter, EffectPointerType, IndexedAdapterCollectionListener, InstrumentBox, InstrumentFactory, InstrumentOptions, InstrumentProduct } from "@opendaw/studio-adapters";
|
|
7
7
|
import { Project } from "./Project";
|
|
8
8
|
import { EffectFactory } from "../EffectFactory";
|
|
9
9
|
import { EffectBox } from "../EffectBox";
|
|
@@ -65,7 +65,7 @@ export declare class ProjectApi {
|
|
|
65
65
|
quantiseNotes(collection: NoteEventCollectionBox, { positionQuantisation, durationQuantisation }: QuantiseNotesOptions): void;
|
|
66
66
|
createValueClip(trackBox: TrackBox, clipIndex: int, { name, hue }?: ClipRegionOptions): ValueClipBox;
|
|
67
67
|
createNoteRegion({ trackBox, position, duration, loopOffset, loopDuration, eventOffset, eventCollection, mute, name, hue }: NoteRegionParams): NoteRegionBox;
|
|
68
|
-
createTrackRegion(trackBox: TrackBox, position: ppqn, duration: ppqn, { name, hue }?: ClipRegionOptions): Option<
|
|
68
|
+
createTrackRegion(trackBox: TrackBox, position: ppqn, duration: ppqn, { name, hue }?: ClipRegionOptions): Option<AnyRegionBox>;
|
|
69
69
|
createNoteEvent({ owner, position, duration, velocity, pitch, chance, cent }: NoteEventParams): NoteEventBox;
|
|
70
70
|
deleteAudioUnit(audioUnitBox: AudioUnitBox): void;
|
|
71
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../../src/project/ProjectApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,OAAO,EAGP,KAAK,EACL,GAAG,EAIH,QAAQ,EACR,MAAM,EAIN,YAAY,EAEf,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAC,IAAI,EAAO,MAAM,kBAAkB,CAAA;AAC3C,OAAO,EAAW,KAAK,EAAc,YAAY,EAAC,MAAM,kBAAkB,CAAA;AAC1E,OAAO,EAAgB,QAAQ,EAAC,MAAM,uBAAuB,CAAA;AAC7D,OAAO,EACH,YAAY,EACZ,cAAc,EACd,YAAY,EAGZ,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,QAAQ,EACR,YAAY,
|
|
1
|
+
{"version":3,"file":"ProjectApi.d.ts","sourceRoot":"","sources":["../../src/project/ProjectApi.ts"],"names":[],"mappings":"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"}
|
|
@@ -196,6 +196,9 @@ export class ProjectApi {
|
|
|
196
196
|
});
|
|
197
197
|
}
|
|
198
198
|
createTrackRegion(trackBox, position, duration, { name, hue } = {}) {
|
|
199
|
+
if (duration <= 0.0) {
|
|
200
|
+
return Option.None;
|
|
201
|
+
}
|
|
199
202
|
const { boxGraph } = this.#project;
|
|
200
203
|
const type = trackBox.type.getValue();
|
|
201
204
|
switch (type) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { BoxGraph } from "@opendaw/lib-box";
|
|
2
2
|
import { AudioPitchStretchBox, AudioTimeStretchBox } from "@opendaw/studio-boxes";
|
|
3
|
-
import { ppqn } from "@opendaw/lib-dsp";
|
|
3
|
+
import { ppqn, seconds } from "@opendaw/lib-dsp";
|
|
4
4
|
import { WarpMarkerTemplate } from "./WarpMarkerTemplate";
|
|
5
5
|
export declare namespace AudioContentHelpers {
|
|
6
|
-
const addDefaultWarpMarkers: (boxGraph: BoxGraph, playMode: AudioPitchStretchBox | AudioTimeStretchBox, durationInPPQN: ppqn, durationInSeconds:
|
|
6
|
+
const addDefaultWarpMarkers: (boxGraph: BoxGraph, playMode: AudioPitchStretchBox | AudioTimeStretchBox, durationInPPQN: ppqn, durationInSeconds: seconds) => void;
|
|
7
7
|
const addWarpMarkers: (boxGraph: BoxGraph, playMode: AudioPitchStretchBox | AudioTimeStretchBox, templates: ReadonlyArray<WarpMarkerTemplate>) => void;
|
|
8
8
|
}
|
|
9
9
|
//# sourceMappingURL=AudioContentHelpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioContentHelpers.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,oBAAoB,EAAE,mBAAmB,EAAgB,MAAM,uBAAuB,CAAA;AAC9F,OAAO,EAAC,IAAI,EAAC,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"AudioContentHelpers.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAC,oBAAoB,EAAE,mBAAmB,EAAgB,MAAM,uBAAuB,CAAA;AAC9F,OAAO,EAAC,IAAI,EAAE,OAAO,EAAC,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAC,kBAAkB,EAAC,MAAM,sBAAsB,CAAA;AAEvD,yBAAiB,mBAAmB,CAAC;IAC1B,MAAM,qBAAqB,GAAI,UAAU,QAAQ,EAClB,UAAU,oBAAoB,GAAG,mBAAmB,EACpD,gBAAgB,IAAI,EACpB,mBAAmB,OAAO,SAW/D,CAAA;IAEM,MAAM,cAAc,GAAI,UAAU,QAAQ,EAClB,UAAU,oBAAoB,GAAG,mBAAmB,EACpD,WAAW,aAAa,CAAC,kBAAkB,CAAC,SAM1E,CAAA;CACJ"}
|
|
@@ -6,7 +6,7 @@ export var AudioContentHelpers;
|
|
|
6
6
|
WarpMarkerBox.create(boxGraph, UUID.generate(), box => {
|
|
7
7
|
box.owner.refer(playMode.warpMarkers);
|
|
8
8
|
box.position.setValue(0);
|
|
9
|
-
box.seconds.setValue(0);
|
|
9
|
+
box.seconds.setValue(0.0);
|
|
10
10
|
});
|
|
11
11
|
WarpMarkerBox.create(boxGraph, UUID.generate(), box => {
|
|
12
12
|
box.owner.refer(playMode.warpMarkers);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioContentModifier.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentModifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,IAAI,EAAiD,MAAM,kBAAkB,CAAA;AAShG,OAAO,EAAC,sBAAsB,EAAwB,MAAM,0BAA0B,CAAA;AAKtF,yBAAiB,oBAAoB,CAAC;IAC3B,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"AudioContentModifier.d.ts","sourceRoot":"","sources":["../../../src/project/audio/AudioContentModifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,IAAI,EAAiD,MAAM,kBAAkB,CAAA;AAShG,OAAO,EAAC,sBAAsB,EAAwB,MAAM,0BAA0B,CAAA;AAKtF,yBAAiB,oBAAoB,CAAC;IAC3B,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CAelG,CAAA;IAEM,MAAM,cAAc,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CA6BlG,CAAA;IAEM,MAAM,aAAa,GAAU,UAAU,aAAa,CAAC,sBAAsB,CAAC,KAAG,OAAO,CAAC,IAAI,CA+CjG,CAAA;CA0BJ"}
|
|
@@ -13,6 +13,8 @@ export var AudioContentModifier;
|
|
|
13
13
|
return EmptyExec;
|
|
14
14
|
}
|
|
15
15
|
return () => audioAdapters.forEach((adapter) => {
|
|
16
|
+
const audibleDuration = adapter.optWarpMarkers
|
|
17
|
+
.mapOr(warpMarkers => warpMarkers.last()?.seconds ?? 0, 0);
|
|
16
18
|
adapter.box.playMode.defer();
|
|
17
19
|
adapter.asPlayModeTimeStretch.ifSome(({ box }) => {
|
|
18
20
|
if (box.pointerHub.filter(Pointers.AudioPlayMode).length === 0) {
|
|
@@ -24,7 +26,7 @@ export var AudioContentModifier;
|
|
|
24
26
|
box.delete();
|
|
25
27
|
}
|
|
26
28
|
});
|
|
27
|
-
switchTimeBaseToSeconds(adapter);
|
|
29
|
+
switchTimeBaseToSeconds(adapter, audibleDuration);
|
|
28
30
|
});
|
|
29
31
|
};
|
|
30
32
|
AudioContentModifier.toPitchStretch = async (adapters) => {
|
|
@@ -55,7 +57,7 @@ export var AudioContentModifier;
|
|
|
55
57
|
}
|
|
56
58
|
}
|
|
57
59
|
else {
|
|
58
|
-
AudioContentHelpers.addDefaultWarpMarkers(boxGraph, pitchStretch, adapter.duration, adapter.
|
|
60
|
+
AudioContentHelpers.addDefaultWarpMarkers(boxGraph, pitchStretch, adapter.duration, adapter.box.duration.getValue());
|
|
59
61
|
}
|
|
60
62
|
switchTimeBaseToMusical(adapter);
|
|
61
63
|
});
|
|
@@ -99,7 +101,7 @@ export var AudioContentModifier;
|
|
|
99
101
|
}
|
|
100
102
|
}
|
|
101
103
|
else {
|
|
102
|
-
AudioContentHelpers.addDefaultWarpMarkers(boxGraph, timeStretch, adapter.duration, adapter.
|
|
104
|
+
AudioContentHelpers.addDefaultWarpMarkers(boxGraph, timeStretch, adapter.duration, adapter.box.duration.getValue());
|
|
103
105
|
}
|
|
104
106
|
if (isDefined(transients) && adapter.file.transients.length() === 0) {
|
|
105
107
|
const markersField = adapter.file.box.transientMarkers;
|
|
@@ -111,17 +113,16 @@ export var AudioContentModifier;
|
|
|
111
113
|
switchTimeBaseToMusical(adapter);
|
|
112
114
|
});
|
|
113
115
|
};
|
|
114
|
-
const switchTimeBaseToSeconds = ({ box,
|
|
116
|
+
const switchTimeBaseToSeconds = ({ box, timeBase }, audibleDuration) => {
|
|
115
117
|
if (timeBase === TimeBase.Seconds) {
|
|
116
118
|
return;
|
|
117
119
|
}
|
|
118
|
-
// Reset to 100% playback speed (original file speed)
|
|
119
120
|
box.timeBase.setValue(TimeBase.Seconds);
|
|
120
|
-
box.duration.setValue(
|
|
121
|
+
box.duration.setValue(audibleDuration);
|
|
121
122
|
box.accept({
|
|
122
123
|
visitAudioRegionBox: (box) => {
|
|
123
124
|
box.loopOffset.setValue(0);
|
|
124
|
-
box.loopDuration.setValue(
|
|
125
|
+
box.loopDuration.setValue(audibleDuration);
|
|
125
126
|
}
|
|
126
127
|
});
|
|
127
128
|
};
|
|
@@ -3,6 +3,7 @@ import { Box } from "@opendaw/lib-box";
|
|
|
3
3
|
import { Sample } from "@opendaw/studio-adapters";
|
|
4
4
|
import { AssetService } from "../AssetService";
|
|
5
5
|
export declare class SampleService extends AssetService<Sample> {
|
|
6
|
+
#private;
|
|
6
7
|
readonly audioContext: AudioContext;
|
|
7
8
|
protected readonly namePlural: string;
|
|
8
9
|
protected readonly nameSingular: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SampleService.d.ts","sourceRoot":"","sources":["../../src/samples/SampleService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,EAAe,SAAS,
|
|
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,10 +1,11 @@
|
|
|
1
|
-
import { Arrays, isUndefined, Progress, UUID } from "@opendaw/lib-std";
|
|
1
|
+
import { Arrays, isUndefined, 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";
|
|
5
5
|
import { AudioFileBox } from "@opendaw/studio-boxes";
|
|
6
6
|
import { AssetService } from "../AssetService";
|
|
7
7
|
import { FilePickerAcceptTypes } from "../FilePickerAcceptTypes";
|
|
8
|
+
import { WavFile } from "../WavFile";
|
|
8
9
|
import { Workers } from "../Workers";
|
|
9
10
|
import { SampleStorage } from "./SampleStorage";
|
|
10
11
|
import { OpenSampleAPI } from "./OpenSampleAPI";
|
|
@@ -20,28 +21,16 @@ export class SampleService extends AssetService {
|
|
|
20
21
|
}
|
|
21
22
|
async importFile({ uuid, name, arrayBuffer, progressHandler = Progress.Empty }) {
|
|
22
23
|
console.debug(`importSample '${name}' (${arrayBuffer.byteLength >> 10}kb)`);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
console.time("decodeAudioData");
|
|
27
|
-
const audioResult = await Promises.tryCatch(this.audioContext.decodeAudioData(arrayBuffer));
|
|
28
|
-
console.timeEnd("decodeAudioData");
|
|
29
|
-
if (audioResult.status === "rejected") {
|
|
30
|
-
return Promise.reject(name);
|
|
31
|
-
}
|
|
32
|
-
const { value: audioBuffer } = audioResult;
|
|
33
|
-
console.debug(`Imported ${audioBuffer.duration.toFixed(1)} seconds`);
|
|
34
|
-
const audioData = AudioData.create(audioBuffer.sampleRate, audioBuffer.length, audioBuffer.numberOfChannels);
|
|
35
|
-
for (let i = 0; i < audioBuffer.numberOfChannels; i++) {
|
|
36
|
-
audioData.frames[i].set(audioBuffer.getChannelData(i));
|
|
37
|
-
}
|
|
24
|
+
uuid ??= await UUID.sha256(arrayBuffer);
|
|
25
|
+
const audioData = await this.#decodeAudio(arrayBuffer);
|
|
26
|
+
const duration = audioData.numberOfFrames / audioData.sampleRate;
|
|
38
27
|
const shifts = SamplePeaks.findBestFit(audioData.numberOfFrames);
|
|
39
28
|
const peaks = await Workers.Peak.generateAsync(progressHandler, shifts, audioData.frames, audioData.numberOfFrames, audioData.numberOfChannels);
|
|
40
29
|
const meta = {
|
|
41
|
-
bpm: estimateBpm(
|
|
30
|
+
bpm: estimateBpm(duration),
|
|
42
31
|
name: isUndefined(name) ? "Unnnamed" : name,
|
|
43
|
-
duration
|
|
44
|
-
sample_rate:
|
|
32
|
+
duration,
|
|
33
|
+
sample_rate: audioData.sampleRate,
|
|
45
34
|
origin: "import"
|
|
46
35
|
};
|
|
47
36
|
await SampleStorage.get().save({ uuid, audio: audioData, peaks, meta });
|
|
@@ -54,4 +43,20 @@ export class SampleService extends AssetService {
|
|
|
54
43
|
const local = await SampleStorage.get().list();
|
|
55
44
|
return Arrays.merge(stock, local, (sample, { uuid }) => sample.uuid === uuid);
|
|
56
45
|
}
|
|
46
|
+
async #decodeAudio(arrayBuffer) {
|
|
47
|
+
const wavResult = tryCatch(() => WavFile.decodeFloats(arrayBuffer));
|
|
48
|
+
if (wavResult.status === "success") {
|
|
49
|
+
return wavResult.value;
|
|
50
|
+
}
|
|
51
|
+
console.debug("decoding with web-api-api (fallback)");
|
|
52
|
+
const { status, value: audioBuffer } = await Promises.tryCatch(this.audioContext.decodeAudioData(arrayBuffer));
|
|
53
|
+
if (status === "rejected") {
|
|
54
|
+
return Promise.reject();
|
|
55
|
+
}
|
|
56
|
+
const audioData = AudioData.create(audioBuffer.sampleRate, audioBuffer.length, audioBuffer.numberOfChannels);
|
|
57
|
+
for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
|
|
58
|
+
audioData.frames[channel].set(audioBuffer.getChannelData(channel));
|
|
59
|
+
}
|
|
60
|
+
return audioData;
|
|
61
|
+
}
|
|
57
62
|
}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from "./clipboard/types/NotesClipboardHandler";
|
|
|
7
7
|
export * from "./clipboard/types/RegionsClipboardHandler";
|
|
8
8
|
export * from "./clipboard/types/ValuesClipboardHandler";
|
|
9
9
|
export * from "./menu/MenuItems";
|
|
10
|
+
export * from "./renderer";
|
|
10
11
|
export * from "./timeline/RegionClipResolver";
|
|
11
12
|
export * from "./timeline/RegionKeepExistingResolver";
|
|
12
13
|
export * from "./timeline/RegionModifyStrategies";
|
package/dist/ui/index.d.ts.map
CHANGED
|
@@ -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,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
|
@@ -7,6 +7,7 @@ export * from "./clipboard/types/NotesClipboardHandler";
|
|
|
7
7
|
export * from "./clipboard/types/RegionsClipboardHandler";
|
|
8
8
|
export * from "./clipboard/types/ValuesClipboardHandler";
|
|
9
9
|
export * from "./menu/MenuItems";
|
|
10
|
+
export * from "./renderer";
|
|
10
11
|
export * from "./timeline/RegionClipResolver";
|
|
11
12
|
export * from "./timeline/RegionKeepExistingResolver";
|
|
12
13
|
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 @@
|
|
|
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
|