@opendaw/studio-core 0.0.45 → 0.0.47
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/EffectBox.d.ts +2 -2
- package/dist/EffectBox.d.ts.map +1 -1
- package/dist/EffectFactories.d.ts +3 -0
- package/dist/EffectFactories.d.ts.map +1 -1
- package/dist/EffectFactories.js +14 -2
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +8 -1
- package/dist/InstrumentBox.d.ts +2 -2
- package/dist/InstrumentBox.d.ts.map +1 -1
- package/dist/InstrumentFactories.d.ts +2 -0
- package/dist/InstrumentFactories.d.ts.map +1 -1
- package/dist/InstrumentFactories.js +13 -2
- package/dist/capture/CaptureDevices.d.ts +1 -1
- package/dist/capture/CaptureDevices.d.ts.map +1 -1
- package/dist/capture/CaptureDevices.js +21 -10
- package/dist/capture/CaptureMidi.js +1 -1
- package/dist/processors.js +12 -12
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts +9 -3
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +47 -6
- package/dist/project/ProjectApi.js +1 -1
- package/dist/ui/TimeGrid.d.ts +19 -0
- package/dist/ui/TimeGrid.d.ts.map +1 -0
- package/dist/ui/TimeGrid.js +74 -0
- 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/workers-main.js +2 -2
- package/dist/workers-main.js.map +1 -1
- package/dist/ysync/YService.d.ts.map +1 -1
- package/dist/ysync/YService.js +19 -8
- package/dist/ysync/YSync.d.ts +4 -4
- package/dist/ysync/YSync.d.ts.map +1 -1
- package/dist/ysync/YSync.js +29 -26
- package/package.json +15 -15
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Func, Procedure, Terminable, TerminableOwner, Terminator } from "@opendaw/lib-std";
|
|
1
|
+
import { Func, Procedure, Terminable, TerminableOwner, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { BoxEditing, BoxGraph } from "@opendaw/lib-box";
|
|
3
|
-
import { AudioBusBox, AudioUnitBox, BoxIO, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
3
|
+
import { AudioBusBox, AudioUnitBox, BoxIO, MIDIOutputDeviceBox, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { BoxAdapters, BoxAdaptersContext, ClipSequencing, ParameterFieldAdapters, ProcessorOptions, ProjectSkeleton, RootBoxAdapter, SampleLoaderManager, SoundfontLoaderManager, TimelineBoxAdapter, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
|
5
5
|
import { LiveStreamBroadcaster, LiveStreamReceiver } from "@opendaw/lib-fusion";
|
|
6
6
|
import { ProjectEnv } from "./ProjectEnv";
|
|
@@ -10,6 +10,7 @@ import { CaptureDevices } from "../capture";
|
|
|
10
10
|
import { EngineFacade } from "../EngineFacade";
|
|
11
11
|
import { EngineWorklet } from "../EngineWorklet";
|
|
12
12
|
import { MIDILearning } from "../midi";
|
|
13
|
+
import { ppqn } from "@opendaw/lib-dsp";
|
|
13
14
|
export type RestartWorklet = {
|
|
14
15
|
unload: Func<unknown, Promise<unknown>>;
|
|
15
16
|
load: Procedure<EngineWorklet>;
|
|
@@ -21,7 +22,7 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
21
22
|
#private;
|
|
22
23
|
static new(env: ProjectEnv, options?: ProjectCreateOptions): Project;
|
|
23
24
|
static load(env: ProjectEnv, arrayBuffer: ArrayBuffer): Project;
|
|
24
|
-
static skeleton(env: ProjectEnv, skeleton: ProjectSkeleton): Project;
|
|
25
|
+
static skeleton(env: ProjectEnv, skeleton: ProjectSkeleton, followFirstUser?: boolean): Project;
|
|
25
26
|
readonly boxGraph: BoxGraph<BoxIO.TypeMap>;
|
|
26
27
|
readonly rootBox: RootBox;
|
|
27
28
|
readonly userInterfaceBoxes: ReadonlyArray<UserInterfaceBox>;
|
|
@@ -56,10 +57,15 @@ export declare class Project implements BoxAdaptersContext, Terminable, Terminab
|
|
|
56
57
|
get isAudioContext(): boolean;
|
|
57
58
|
get isMainThread(): boolean;
|
|
58
59
|
get liveStreamBroadcaster(): LiveStreamBroadcaster;
|
|
60
|
+
get signatureDuration(): ppqn;
|
|
59
61
|
get skeleton(): ProjectSkeleton;
|
|
62
|
+
collectSampleUUIDs(): ReadonlyArray<UUID.Bytes>;
|
|
60
63
|
toArrayBuffer(): ArrayBufferLike;
|
|
61
64
|
copy(env?: Partial<ProjectEnv>): Project;
|
|
62
65
|
invalid(): boolean;
|
|
66
|
+
connectMIDIOutput(box: MIDIOutputDeviceBox, device: MIDIOutput): void;
|
|
67
|
+
disconnectMIDIOutput(uuid: UUID.Bytes): void;
|
|
68
|
+
receivedMIDIFromEngine(target: UUID.Bytes, data: Uint8Array, relativeTimeInMs: number): void;
|
|
63
69
|
terminate(): void;
|
|
64
70
|
}
|
|
65
71
|
//# sourceMappingURL=Project.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Project.d.ts","sourceRoot":"","sources":["../../src/project/Project.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,IAAI,
|
|
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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Arrays, ByteArrayOutput, Option, panic, safeExecute, Terminator, UUID } from "@opendaw/lib-std";
|
|
1
|
+
import { Arrays, ByteArrayOutput, isDefined, Option, panic, safeExecute, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { BoxEditing, BoxGraph } from "@opendaw/lib-box";
|
|
3
3
|
import { AudioBusBox, AudioUnitBox, BoxIO, CompressorDeviceBox, GrooveShuffleBox, RootBox, TimelineBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { BoxAdapters, IconSymbol, ParameterFieldAdapters, ProjectDecoder, RootBoxAdapter, TimelineBoxAdapter, UnionBoxTypes, UserEditingManager, VertexSelection } from "@opendaw/studio-adapters";
|
|
@@ -12,6 +12,7 @@ import { EngineFacade } from "../EngineFacade";
|
|
|
12
12
|
import { MIDILearning } from "../midi";
|
|
13
13
|
import { ProjectValidation } from "./ProjectValidation";
|
|
14
14
|
import { Preferences } from "../Preferences";
|
|
15
|
+
import { PPQN } from "@opendaw/lib-dsp";
|
|
15
16
|
// Main Entry Point for a Project
|
|
16
17
|
export class Project {
|
|
17
18
|
static new(env, options) {
|
|
@@ -51,27 +52,36 @@ export class Project {
|
|
|
51
52
|
rootBox.timeline.refer(timelineBox.root);
|
|
52
53
|
primaryAudioBus.output.refer(primaryAudioOutputUnit.input);
|
|
53
54
|
const userInterfaceBoxes = [];
|
|
54
|
-
|
|
55
|
+
const createDefaultUser = options?.noDefaultUser !== true;
|
|
56
|
+
if (createDefaultUser) {
|
|
55
57
|
const userInterfaceBox = UserInterfaceBox.create(boxGraph, UUID.generate());
|
|
56
58
|
userInterfaceBox.root.refer(rootBox.users);
|
|
57
59
|
userInterfaceBoxes.push(userInterfaceBox);
|
|
58
60
|
}
|
|
59
61
|
boxGraph.endTransaction();
|
|
60
|
-
|
|
62
|
+
const project = new Project(env, boxGraph, {
|
|
61
63
|
rootBox,
|
|
62
64
|
primaryAudioBus,
|
|
63
65
|
primaryAudioOutputUnit,
|
|
64
66
|
userInterfaceBoxes,
|
|
65
67
|
timelineBox
|
|
66
68
|
});
|
|
69
|
+
if (createDefaultUser) {
|
|
70
|
+
project.follow(userInterfaceBoxes[0]);
|
|
71
|
+
}
|
|
72
|
+
return project;
|
|
67
73
|
}
|
|
68
74
|
static load(env, arrayBuffer) {
|
|
69
75
|
return this.skeleton(env, ProjectDecoder.decode(arrayBuffer));
|
|
70
76
|
}
|
|
71
|
-
static skeleton(env, skeleton) {
|
|
77
|
+
static skeleton(env, skeleton, followFirstUser = true) {
|
|
72
78
|
ProjectMigration.migrate(skeleton);
|
|
73
79
|
ProjectValidation.validate(skeleton);
|
|
74
|
-
|
|
80
|
+
const project = new Project(env, skeleton.boxGraph, skeleton.mandatoryBoxes);
|
|
81
|
+
if (followFirstUser) {
|
|
82
|
+
project.follow(project.userInterfaceBoxes[0]);
|
|
83
|
+
}
|
|
84
|
+
return project;
|
|
75
85
|
}
|
|
76
86
|
#terminator = new Terminator();
|
|
77
87
|
#env;
|
|
@@ -92,6 +102,7 @@ export class Project {
|
|
|
92
102
|
midiLearning;
|
|
93
103
|
mixer;
|
|
94
104
|
engine = new EngineFacade();
|
|
105
|
+
#midiOutputs = UUID.newSet(({ box: { address: { uuid } } }) => uuid);
|
|
95
106
|
constructor(env, boxGraph, { rootBox, userInterfaceBoxes, primaryAudioBus, primaryAudioOutputUnit, timelineBox }) {
|
|
96
107
|
this.#env = env;
|
|
97
108
|
this.boxGraph = boxGraph;
|
|
@@ -111,7 +122,7 @@ export class Project {
|
|
|
111
122
|
this.captureDevices = this.#terminator.own(new CaptureDevices(this));
|
|
112
123
|
this.mixer = new Mixer(this.rootBoxAdapter.audioUnits);
|
|
113
124
|
// TODO We are probably doing that from the outside
|
|
114
|
-
if (this.userInterfaceBoxes.length
|
|
125
|
+
if (this.userInterfaceBoxes.length === 1) {
|
|
115
126
|
this.follow(this.userInterfaceBoxes[0]);
|
|
116
127
|
}
|
|
117
128
|
console.debug(`Project was created on ${this.rootBoxAdapter.created.toString()}`);
|
|
@@ -159,6 +170,10 @@ export class Project {
|
|
|
159
170
|
get isAudioContext() { return false; }
|
|
160
171
|
get isMainThread() { return true; }
|
|
161
172
|
get liveStreamBroadcaster() { return panic("Only available in audio context"); }
|
|
173
|
+
get signatureDuration() {
|
|
174
|
+
const { nominator, denominator } = this.timelineBox.signature;
|
|
175
|
+
return PPQN.fromSignature(nominator.getValue(), denominator.getValue());
|
|
176
|
+
}
|
|
162
177
|
get skeleton() {
|
|
163
178
|
return {
|
|
164
179
|
boxGraph: this.boxGraph,
|
|
@@ -171,6 +186,11 @@ export class Project {
|
|
|
171
186
|
}
|
|
172
187
|
};
|
|
173
188
|
}
|
|
189
|
+
collectSampleUUIDs() {
|
|
190
|
+
return this.boxGraph.boxes()
|
|
191
|
+
.filter(box => box.accept({ visitAudioFileBox: (_box) => true }))
|
|
192
|
+
.map(box => box.address.uuid);
|
|
193
|
+
}
|
|
174
194
|
toArrayBuffer() {
|
|
175
195
|
const output = ByteArrayOutput.create();
|
|
176
196
|
output.writeInt(ProjectDecoder.MAGIC_HEADER_OPEN);
|
|
@@ -198,6 +218,27 @@ export class Project {
|
|
|
198
218
|
}
|
|
199
219
|
}) ?? false);
|
|
200
220
|
}
|
|
221
|
+
connectMIDIOutput(box, device) {
|
|
222
|
+
console.debug("connectMIDIOutput", UUID.toString(box.address.uuid), device.name, device.manufacturer);
|
|
223
|
+
this.disconnectMIDIOutput(box.address.uuid);
|
|
224
|
+
this.#midiOutputs.add({
|
|
225
|
+
box, device, subscription: box.host.subscribe(pointer => {
|
|
226
|
+
if (pointer.isEmpty()) {
|
|
227
|
+
this.disconnectMIDIOutput(box.address.uuid);
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
disconnectMIDIOutput(uuid) {
|
|
233
|
+
const entry = this.#midiOutputs.removeByKeyIfExist(uuid);
|
|
234
|
+
if (isDefined(entry)) {
|
|
235
|
+
console.debug("disconnectMIDIOutput", UUID.toString(uuid));
|
|
236
|
+
entry.subscription.terminate();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
receivedMIDIFromEngine(target, data, relativeTimeInMs) {
|
|
240
|
+
this.#midiOutputs.opt(target).ifSome(({ box, device }) => device.send(data, performance.now() + relativeTimeInMs + box.delay.getValue()));
|
|
241
|
+
}
|
|
201
242
|
terminate() {
|
|
202
243
|
console.debug("Project terminated");
|
|
203
244
|
this.#terminator.terminate();
|
|
@@ -139,7 +139,7 @@ export class ProjectApi {
|
|
|
139
139
|
box.hue.setValue(hue ?? ColorCodes.forTrackType(type));
|
|
140
140
|
box.mute.setValue(false);
|
|
141
141
|
box.duration.setValue(duration);
|
|
142
|
-
box.loopDuration.setValue(
|
|
142
|
+
box.loopDuration.setValue(this.#project.signatureDuration);
|
|
143
143
|
box.events.refer(events.owners);
|
|
144
144
|
box.regions.refer(trackBox.regions);
|
|
145
145
|
}));
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { int } from "@opendaw/lib-std";
|
|
2
|
+
import { TimelineRange } from "./TimelineRange";
|
|
3
|
+
export declare namespace TimeGrid {
|
|
4
|
+
type Signature = [int, int];
|
|
5
|
+
type Options = {
|
|
6
|
+
minLength?: number;
|
|
7
|
+
};
|
|
8
|
+
type Fragment = {
|
|
9
|
+
bars: int;
|
|
10
|
+
beats: int;
|
|
11
|
+
ticks: int;
|
|
12
|
+
isBar: boolean;
|
|
13
|
+
isBeat: boolean;
|
|
14
|
+
pulse: number;
|
|
15
|
+
};
|
|
16
|
+
type Designer = (fragment: Fragment) => void;
|
|
17
|
+
const fragment: ([nominator, denominator]: Signature, range: TimelineRange, designer: Designer, options?: Options) => void;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=TimeGrid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimeGrid.d.ts","sourceRoot":"","sources":["../../src/ui/TimeGrid.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,GAAG,EAAgB,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAE7C,yBAAiB,QAAQ,CAAC;IACtB,KAAY,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IAClC,KAAY,OAAO,GAAG;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C,KAAY,QAAQ,GAAG;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5G,KAAY,QAAQ,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAA;IAE5C,MAAM,QAAQ,GAAI,0BAA0B,SAAS,EACnC,OAAO,aAAa,EAAE,UAAU,QAAQ,EAAE,UAAU,OAAO,KAAG,IA4DtF,CAAA;CACJ"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { PPQN } from "@opendaw/lib-dsp";
|
|
2
|
+
import { quantizeFloor } from "@opendaw/lib-std";
|
|
3
|
+
export var TimeGrid;
|
|
4
|
+
(function (TimeGrid) {
|
|
5
|
+
TimeGrid.fragment = ([nominator, denominator], range, designer, options) => {
|
|
6
|
+
const unitsPerPixel = range.unitsPerPixel;
|
|
7
|
+
if (unitsPerPixel <= 0) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const barPulses = PPQN.fromSignature(nominator, denominator);
|
|
11
|
+
const beatPulses = PPQN.fromSignature(1, denominator);
|
|
12
|
+
const minLength = options?.minLength ?? 48;
|
|
13
|
+
let interval = barPulses;
|
|
14
|
+
let pixel = interval / unitsPerPixel;
|
|
15
|
+
if (pixel > minLength) {
|
|
16
|
+
// scaling down the interval until we hit the minimum length
|
|
17
|
+
while (pixel > minLength) {
|
|
18
|
+
if (interval > barPulses) {
|
|
19
|
+
// Above bar level: divide by 2
|
|
20
|
+
interval /= 2;
|
|
21
|
+
}
|
|
22
|
+
else if (interval > beatPulses) {
|
|
23
|
+
// Between beat and bar level: divide by nominator
|
|
24
|
+
interval /= nominator;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
// Below beat level: divide by 2
|
|
28
|
+
interval /= 2;
|
|
29
|
+
}
|
|
30
|
+
pixel = interval / unitsPerPixel;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (pixel < minLength) {
|
|
34
|
+
// scaling up the interval until we hit the minimum length
|
|
35
|
+
while (pixel < minLength) {
|
|
36
|
+
if (interval < beatPulses) {
|
|
37
|
+
// Below beat level: multiply by 2
|
|
38
|
+
const nextInterval = interval * 2;
|
|
39
|
+
// If doubling exceeds beat level, jump to beat level instead
|
|
40
|
+
if (nextInterval > beatPulses) {
|
|
41
|
+
interval = beatPulses;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
interval = nextInterval;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (interval < barPulses) {
|
|
48
|
+
// Between beat and bar level: multiply by nominator
|
|
49
|
+
const nextInterval = interval * nominator;
|
|
50
|
+
// If multiplying exceeds bar level, jump to bar level instead
|
|
51
|
+
if (nextInterval > barPulses) {
|
|
52
|
+
interval = barPulses;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
interval = nextInterval;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// At or above bar level: multiply by 2
|
|
60
|
+
interval *= 2;
|
|
61
|
+
}
|
|
62
|
+
pixel = interval / unitsPerPixel;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const p0 = quantizeFloor(range.unitMin, interval);
|
|
66
|
+
const p1 = range.unitMax;
|
|
67
|
+
for (let pulse = p0; pulse < p1; pulse += interval) {
|
|
68
|
+
const { bars, beats, semiquavers, ticks } = PPQN.toParts(pulse, nominator, denominator);
|
|
69
|
+
const isBeat = ticks === 0 && semiquavers === 0;
|
|
70
|
+
const isBar = isBeat && beats === 0;
|
|
71
|
+
designer({ bars, beats, ticks, isBar, isBeat, pulse });
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
})(TimeGrid || (TimeGrid = {}));
|
package/dist/ui/index.d.ts
CHANGED
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,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA"}
|
package/dist/ui/index.js
CHANGED