@opendaw/studio-core 0.0.93 → 0.0.95
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/EffectFactories.d.ts.map +1 -1
- package/dist/EffectFactories.js +1 -0
- package/dist/capture/CaptureAudio.d.ts +2 -0
- package/dist/capture/CaptureAudio.d.ts.map +1 -1
- package/dist/capture/CaptureAudio.js +44 -1
- package/dist/capture/RecordMidi.d.ts.map +1 -1
- package/dist/capture/RecordMidi.js +5 -3
- package/dist/dawproject/DawProjectExporter.d.ts.map +1 -1
- package/dist/dawproject/DawProjectExporter.js +76 -3
- package/dist/dawproject/DawProjectImporter.d.ts.map +1 -1
- package/dist/dawproject/DawProjectImporter.js +71 -3
- package/dist/processors.js +7 -7
- package/dist/processors.js.map +3 -3
- package/dist/project/migration/MigrateTimelineBox.js +2 -1
- package/dist/samples/GlobalSampleLoaderManager.js +2 -2
- package/package.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EffectFactories.d.ts","sourceRoot":"","sources":["../src/EffectFactories.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAG7C,yBAAiB,eAAe,CAAC;IACtB,MAAM,QAAQ,EAAE,aAYtB,CAAA;IAEM,MAAM,KAAK,EAAE,aAYnB,CAAA;IAEM,MAAM,QAAQ,EAAE,aAYtB,CAAA;IAEM,MAAM,SAAS,EAAE,aAsBvB,CAAA;IAEM,MAAM,UAAU,EAAE,aAaxB,CAAA;IAEM,MAAM,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"EffectFactories.d.ts","sourceRoot":"","sources":["../src/EffectFactories.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAA;AAG7C,yBAAiB,eAAe,CAAC;IACtB,MAAM,QAAQ,EAAE,aAYtB,CAAA;IAEM,MAAM,KAAK,EAAE,aAYnB,CAAA;IAEM,MAAM,QAAQ,EAAE,aAYtB,CAAA;IAEM,MAAM,SAAS,EAAE,aAsBvB,CAAA;IAEM,MAAM,UAAU,EAAE,aAaxB,CAAA;IAEM,MAAM,KAAK,EAAE,aAcnB,CAAA;IAEM,MAAM,cAAc,EAAE,aAa5B,CAAA;IAEM,MAAM,SAAS,EAAE,aAavB,CAAA;IAEM,MAAM,UAAU,EAAE,aAaxB,CAAA;IAEM,MAAM,MAAM,EAAE,aAcpB,CAAA;IAEM,MAAM,OAAO,EAAE,aAarB,CAAA;IAEM,MAAM,IAAI,EAAE,aAalB,CAAA;IAEM,MAAM,KAAK,EAAE,aAcnB,CAAA;IAEM,MAAM,MAAM,EAAE,aAapB,CAAA;IAEM,MAAM,OAAO,EAAE,aAqCrB,CAAA;IAEM,MAAM,SAAS;;;;;KAAyC,CAAA;IACxD,MAAM,UAAU;;;;;;;;;;;KAEtB,CAAA;IACM,MAAM,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA4B,CAAA;IACjF,MAAM,SAAS,EAAE,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA6B,CAAA;IACnF,MAAM,WAAW;;;;;;;;;;;;;;;KAAgC,CAAA;IACxD,KAAY,cAAc,GAAG,MAAM,OAAO,SAAS,CAAA;IACnD,KAAY,eAAe,GAAG,MAAM,OAAO,UAAU,CAAA;CACxD"}
|
package/dist/EffectFactories.js
CHANGED
|
@@ -5,6 +5,8 @@ import { CaptureDevices } from "./CaptureDevices";
|
|
|
5
5
|
export declare class CaptureAudio extends Capture<CaptureAudioBox> {
|
|
6
6
|
#private;
|
|
7
7
|
constructor(manager: CaptureDevices, audioUnitBox: AudioUnitBox, captureAudioBox: CaptureAudioBox);
|
|
8
|
+
get isMonitoring(): boolean;
|
|
9
|
+
set isMonitoring(value: boolean);
|
|
8
10
|
get gainDb(): number;
|
|
9
11
|
get stream(): MutableObservableOption<MediaStream>;
|
|
10
12
|
get streamDeviceId(): Option<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,uBAAuB,
|
|
1
|
+
{"version":3,"file":"CaptureAudio.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,uBAAuB,EAEvB,MAAM,EAEN,UAAU,EACb,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAAC,YAAY,EAAE,eAAe,EAAC,MAAM,uBAAuB,CAAA;AACnE,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAI/C,qBAAa,YAAa,SAAQ,OAAO,CAAC,eAAe,CAAC;;gBAW1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe;IAiCjG,IAAI,YAAY,IAAI,OAAO,CAA4B;IACvD,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAS9B;IACD,IAAI,MAAM,IAAI,MAAM,CAAsB;IAC1C,IAAI,MAAM,IAAI,uBAAuB,CAAC,WAAW,CAAC,CAAsB;IACxE,IAAI,cAAc,IAAI,MAAM,CAAC,MAAM,CAAC,CAEnC;IACD,IAAI,KAAK,IAAI,MAAM,CAAsE;IACzF,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAA+D;IAChG,IAAI,gBAAgB,IAAI,MAAM,CAAC,gBAAgB,CAAC,CAE/C;IAEK,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBvC,cAAc,IAAI,UAAU;CAqF/B"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Errors, isDefined, isUndefined, MutableObservableOption, Option, RuntimeNotifier, Terminable } from "@opendaw/lib-std";
|
|
2
|
+
import { dbToGain } from "@opendaw/lib-dsp";
|
|
2
3
|
import { Promises } from "@opendaw/lib-runtime";
|
|
3
4
|
import { Capture } from "./Capture";
|
|
4
5
|
import { RecordAudio } from "./RecordAudio";
|
|
@@ -6,8 +7,10 @@ import { AudioDevices } from "../AudioDevices";
|
|
|
6
7
|
export class CaptureAudio extends Capture {
|
|
7
8
|
#stream;
|
|
8
9
|
#streamGenerator;
|
|
10
|
+
#isMonitoring = false;
|
|
9
11
|
#requestChannels = Option.None;
|
|
10
12
|
#gainDb = 0.0;
|
|
13
|
+
#monitor = null;
|
|
11
14
|
constructor(manager, audioUnitBox, captureAudioBox) {
|
|
12
15
|
super(manager, audioUnitBox, captureAudioBox);
|
|
13
16
|
this.#stream = new MutableObservableOption();
|
|
@@ -15,7 +18,12 @@ export class CaptureAudio extends Capture {
|
|
|
15
18
|
this.ownAll(captureAudioBox.requestChannels.catchupAndSubscribe(owner => {
|
|
16
19
|
const channels = owner.getValue();
|
|
17
20
|
this.#requestChannels = channels === 1 || channels === 2 ? Option.wrap(channels) : Option.None;
|
|
18
|
-
}), captureAudioBox.gainDb.catchupAndSubscribe(owner =>
|
|
21
|
+
}), captureAudioBox.gainDb.catchupAndSubscribe(owner => {
|
|
22
|
+
this.#gainDb = owner.getValue();
|
|
23
|
+
if (isDefined(this.#monitor)) {
|
|
24
|
+
this.#monitor.gainNode.gain.value = dbToGain(this.#gainDb);
|
|
25
|
+
}
|
|
26
|
+
}), captureAudioBox.deviceId.catchupAndSubscribe(async () => {
|
|
19
27
|
if (this.armed.getValue()) {
|
|
20
28
|
await this.#streamGenerator();
|
|
21
29
|
}
|
|
@@ -29,6 +37,20 @@ export class CaptureAudio extends Capture {
|
|
|
29
37
|
}
|
|
30
38
|
}));
|
|
31
39
|
}
|
|
40
|
+
get isMonitoring() { return this.#isMonitoring; }
|
|
41
|
+
set isMonitoring(value) {
|
|
42
|
+
if (this.#isMonitoring === value) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
this.#isMonitoring = value;
|
|
46
|
+
if (this.#isMonitoring) {
|
|
47
|
+
this.armed.setValue(true);
|
|
48
|
+
this.#stream.ifSome(stream => this.#connectMonitoring(stream));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.#disconnectMonitoring();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
32
54
|
get gainDb() { return this.#gainDb; }
|
|
33
55
|
get stream() { return this.#stream; }
|
|
34
56
|
get streamDeviceId() {
|
|
@@ -106,6 +128,9 @@ export class CaptureAudio extends Capture {
|
|
|
106
128
|
console.debug(`new stream. device requested: ${deviceId ?? "default"}, got: ${gotDeviceId ?? "unknown"}. channelCount requested: ${channelCount}, got: ${settings?.channelCount}`);
|
|
107
129
|
if (isUndefined(deviceId) || deviceId === gotDeviceId) {
|
|
108
130
|
this.#stream.wrap(stream);
|
|
131
|
+
if (this.#isMonitoring) {
|
|
132
|
+
this.#connectMonitoring(stream);
|
|
133
|
+
}
|
|
109
134
|
}
|
|
110
135
|
else {
|
|
111
136
|
stream.getAudioTracks().forEach(track => track.stop());
|
|
@@ -114,6 +139,24 @@ export class CaptureAudio extends Capture {
|
|
|
114
139
|
});
|
|
115
140
|
}
|
|
116
141
|
#stopStream() {
|
|
142
|
+
this.#disconnectMonitoring();
|
|
117
143
|
this.#stream.clear(stream => stream.getAudioTracks().forEach(track => track.stop()));
|
|
118
144
|
}
|
|
145
|
+
#connectMonitoring(stream) {
|
|
146
|
+
this.#disconnectMonitoring();
|
|
147
|
+
const { audioContext } = this.manager.project.env;
|
|
148
|
+
const sourceNode = audioContext.createMediaStreamSource(stream);
|
|
149
|
+
const gainNode = audioContext.createGain();
|
|
150
|
+
gainNode.gain.value = dbToGain(this.#gainDb);
|
|
151
|
+
sourceNode.connect(gainNode);
|
|
152
|
+
gainNode.connect(audioContext.destination);
|
|
153
|
+
this.#monitor = { sourceNode, gainNode };
|
|
154
|
+
}
|
|
155
|
+
#disconnectMonitoring() {
|
|
156
|
+
if (isDefined(this.#monitor)) {
|
|
157
|
+
const { sourceNode, gainNode } = this.#monitor;
|
|
158
|
+
sourceNode.disconnect();
|
|
159
|
+
gainNode.disconnect();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
119
162
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,QAAQ,EAAuC,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGrI,OAAO,EAAa,UAAU,EAA2B,MAAM,0BAA0B,CAAA;AACzF,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,yBAAiB,UAAU,CAAC;IACxB,KAAK,iBAAiB,GAAG;QACrB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC/B,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,OAAO,CAAA;KACnB,CAAA;IAgBD,MAAM,CAAC,MAAM,KAAK,GAAI,gCAA8B,iBAAiB,KAAG,
|
|
1
|
+
{"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,QAAQ,EAAuC,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGrI,OAAO,EAAa,UAAU,EAA2B,MAAM,0BAA0B,CAAA;AACzF,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,yBAAiB,UAAU,CAAC;IACxB,KAAK,iBAAiB,GAAG;QACrB,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC/B,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,OAAO,CAAA;KACnB,CAAA;IAgBD,MAAM,CAAC,MAAM,KAAK,GAAI,gCAA8B,iBAAiB,KAAG,UAkJvE,CAAA;;CACJ"}
|
|
@@ -91,12 +91,14 @@ export var RecordMidi;
|
|
|
91
91
|
const loopEnabled = loopArea.enabled.getValue();
|
|
92
92
|
const loopFrom = loopArea.from.getValue();
|
|
93
93
|
const loopTo = loopArea.to.getValue();
|
|
94
|
-
const loopDurationPPQN = loopTo - loopFrom;
|
|
95
94
|
const allowTakes = project.engine.preferences.settings.recording.allowTakes;
|
|
96
95
|
if (loopEnabled && allowTakes && currentTake.nonEmpty() && currentPosition < lastPosition) {
|
|
97
|
-
positionOffset += loopDurationPPQN;
|
|
98
96
|
editing.modify(() => {
|
|
99
|
-
currentTake.ifSome(take =>
|
|
97
|
+
currentTake.ifSome(take => {
|
|
98
|
+
const actualDurationPPQN = take.regionBox.duration.getValue();
|
|
99
|
+
finalizeTake(take, actualDurationPPQN);
|
|
100
|
+
positionOffset += actualDurationPPQN;
|
|
101
|
+
});
|
|
100
102
|
startNewTake(loopFrom);
|
|
101
103
|
}, false);
|
|
102
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DawProjectExporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectExporter.ts"],"names":[],"mappings":"AAKA,OAAO,
|
|
1
|
+
{"version":3,"file":"DawProjectExporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectExporter.ts"],"names":[],"mappings":"AAKA,OAAO,EAcH,mBAAmB,EAMnB,aAAa,EAahB,MAAM,yBAAyB,CAAA;AAgBhC,OAAO,EAAwD,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAA;AAKpI,yBAAiB,kBAAkB,CAAC;IAChC,UAAiB,cAAc;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,mBAAmB,CAAA;KAAC;IAE5F,MAAM,KAAK,GAAI,UAAU,eAAe,EAAE,eAAe,mBAAmB,EAAE,gBAAgB,cAAc,kBAqTlH,CAAA;CACJ"}
|
|
@@ -3,10 +3,10 @@ import { Xml } from "@opendaw/lib-xml";
|
|
|
3
3
|
import { dbToGain, PPQN } from "@opendaw/lib-dsp";
|
|
4
4
|
import { AddressIdEncoder, BooleanField } from "@opendaw/lib-box";
|
|
5
5
|
import { Html } from "@opendaw/lib-dom";
|
|
6
|
-
import { ApplicationSchema, ArrangementSchema, AudioAlgorithm, AudioSchema, BuiltinDeviceSchema, ChannelRole, ChannelSchema, ClipSchema, ClipsSchema, DeviceRole, FileReferenceSchema, LanesSchema, NoteSchema, NotesSchema, ParameterEncoder, ProjectSchema, RealParameterSchema, TimeSignatureParameterSchema, TimeUnit, TrackSchema, TransportSchema, Unit, WarpSchema, WarpsSchema } from "@opendaw/lib-dawproject";
|
|
6
|
+
import { ApplicationSchema, ArrangementSchema, AudioAlgorithm, AudioSchema, AutomationTargetSchema, BuiltinDeviceSchema, ChannelRole, ChannelSchema, ClipSchema, ClipsSchema, DeviceRole, FileReferenceSchema, LanesSchema, NoteSchema, NotesSchema, ParameterEncoder, PointsSchema, ProjectSchema, RealParameterSchema, RealPointSchema, TempoAutomationConverter, TimeSignatureParameterSchema, TimeSignaturePointSchema, TimeUnit, TrackSchema, TransportSchema, Unit, WarpSchema, WarpsSchema } from "@opendaw/lib-dawproject";
|
|
7
7
|
import { AudioUnitType } from "@opendaw/studio-enums";
|
|
8
|
-
import { AudioFileBox, AudioUnitBox, NoteEventBox, NoteEventCollectionBox, TrackBox } from "@opendaw/studio-boxes";
|
|
9
|
-
import { ColorCodes, DeviceBoxUtils } from "@opendaw/studio-adapters";
|
|
8
|
+
import { AudioFileBox, AudioUnitBox, NoteEventBox, NoteEventCollectionBox, SignatureEventBox, TrackBox, ValueEventBox, ValueEventCollectionBox } from "@opendaw/studio-boxes";
|
|
9
|
+
import { ColorCodes, DeviceBoxUtils, InterpolationFieldAdapter } from "@opendaw/studio-adapters";
|
|
10
10
|
import { AudioUnitExportLayout } from "./AudioUnitExportLayout";
|
|
11
11
|
import { DeviceIO } from "./DeviceIO";
|
|
12
12
|
import { WavFile } from "../WavFile";
|
|
@@ -205,6 +205,77 @@ export var DawProjectExporter;
|
|
|
205
205
|
content: []
|
|
206
206
|
}, ClipSchema)]
|
|
207
207
|
}, ClipsSchema);
|
|
208
|
+
const writeTempoAutomation = () => {
|
|
209
|
+
const { tempoTrack } = timelineBox;
|
|
210
|
+
if (!tempoTrack.enabled.getValue()) {
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
const targetVertex = tempoTrack.events.targetVertex;
|
|
214
|
+
if (targetVertex.isEmpty()) {
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
const collectionBox = asInstanceOf(targetVertex.unwrap().box, ValueEventCollectionBox);
|
|
218
|
+
const events = collectionBox.events.pointerHub.incoming()
|
|
219
|
+
.map(({ box }) => asInstanceOf(box, ValueEventBox))
|
|
220
|
+
.sort((eventA, eventB) => eventA.position.getValue() - eventB.position.getValue());
|
|
221
|
+
if (events.length === 0) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
const minBpm = tempoTrack.minBpm.getValue();
|
|
225
|
+
const maxBpm = tempoTrack.maxBpm.getValue();
|
|
226
|
+
const tempoParameterId = ids.getOrCreate(timelineBox.bpm.address);
|
|
227
|
+
return Xml.element({
|
|
228
|
+
unit: Unit.BPM,
|
|
229
|
+
target: Xml.element({
|
|
230
|
+
parameter: tempoParameterId
|
|
231
|
+
}, AutomationTargetSchema),
|
|
232
|
+
points: events.map(event => {
|
|
233
|
+
const interpolation = InterpolationFieldAdapter.read(event.interpolation);
|
|
234
|
+
return Xml.element({
|
|
235
|
+
time: event.position.getValue() / PPQN.Quarter,
|
|
236
|
+
value: TempoAutomationConverter.normalizedToBpm(event.value.getValue(), minBpm, maxBpm),
|
|
237
|
+
interpolation: TempoAutomationConverter.toDawProjectInterpolation(interpolation)
|
|
238
|
+
}, RealPointSchema);
|
|
239
|
+
})
|
|
240
|
+
}, PointsSchema);
|
|
241
|
+
};
|
|
242
|
+
const writeSignatureAutomation = () => {
|
|
243
|
+
const { signatureTrack, signature } = timelineBox;
|
|
244
|
+
if (!signatureTrack.enabled.getValue()) {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
const events = signatureTrack.events.pointerHub.incoming()
|
|
248
|
+
.map(({ box }) => asInstanceOf(box, SignatureEventBox))
|
|
249
|
+
.sort((eventA, eventB) => eventA.index.getValue() - eventB.index.getValue());
|
|
250
|
+
if (events.length === 0) {
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
// Calculate absolute positions for each event
|
|
254
|
+
const points = [];
|
|
255
|
+
let accumulatedPpqn = 0;
|
|
256
|
+
let currentNominator = signature.nominator.getValue();
|
|
257
|
+
let currentDenominator = signature.denominator.getValue();
|
|
258
|
+
// Add the initial signature at time 0
|
|
259
|
+
points.push(Xml.element({
|
|
260
|
+
time: 0,
|
|
261
|
+
numerator: currentNominator,
|
|
262
|
+
denominator: currentDenominator
|
|
263
|
+
}, TimeSignaturePointSchema));
|
|
264
|
+
for (const event of events) {
|
|
265
|
+
const barDuration = PPQN.fromSignature(currentNominator, currentDenominator);
|
|
266
|
+
accumulatedPpqn += barDuration * event.relativePosition.getValue();
|
|
267
|
+
currentNominator = event.nominator.getValue();
|
|
268
|
+
currentDenominator = event.denominator.getValue();
|
|
269
|
+
points.push(Xml.element({
|
|
270
|
+
time: accumulatedPpqn / PPQN.Quarter,
|
|
271
|
+
numerator: currentNominator,
|
|
272
|
+
denominator: currentDenominator
|
|
273
|
+
}, TimeSignaturePointSchema));
|
|
274
|
+
}
|
|
275
|
+
return Xml.element({
|
|
276
|
+
points
|
|
277
|
+
}, PointsSchema);
|
|
278
|
+
};
|
|
208
279
|
const writeLanes = () => {
|
|
209
280
|
return audioUnits
|
|
210
281
|
.flatMap(audioUnitBox => audioUnitBox.tracks.pointerHub.incoming()
|
|
@@ -230,6 +301,8 @@ export var DawProjectExporter;
|
|
|
230
301
|
transport: writeTransport(),
|
|
231
302
|
structure: writeStructure(),
|
|
232
303
|
arrangement: Xml.element({
|
|
304
|
+
tempoAutomation: writeTempoAutomation(),
|
|
305
|
+
timeSignatureAutomation: writeSignatureAutomation(),
|
|
233
306
|
lanes: Xml.element({
|
|
234
307
|
lanes: writeLanes(),
|
|
235
308
|
timeUnit: TimeUnit.BEATS
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DawProjectImporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,
|
|
1
|
+
{"version":3,"file":"DawProjectImporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAiBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,EAUhB,MAAM,yBAAyB,CAAA;AA2BhC,OAAO,EAOH,eAAe,EAElB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAIvC,yBAAiB,gBAAgB,CAAC;IAW9B,KAAY,MAAM,GAAG;QACjB,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACpC,QAAQ,EAAE,eAAe,CAAA;KAC5B,CAAA;IAOM,MAAM,IAAI,GAAU,QAAQ,aAAa,EAAE,WAAW,UAAU,CAAC,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAycxG,CAAA;CAaJ"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ArrayMultimap, asDefined, asInstanceOf, assert, Color, ifDefined, isDefined, isInstanceOf, isUndefined, NumberComparator, Option, panic, UUID, ValueMapping } from "@opendaw/lib-std";
|
|
2
2
|
import { BoxGraph } from "@opendaw/lib-box";
|
|
3
3
|
import { gainToDb, PPQN } from "@opendaw/lib-dsp";
|
|
4
|
-
import { ChannelRole, ClipsSchema, DeviceRole, EqualizerSchema, LanesSchema, NotesSchema, PointsSchema, SendType, TrackSchema, WarpsSchema } from "@opendaw/lib-dawproject";
|
|
4
|
+
import { ChannelRole, ClipsSchema, DeviceRole, EqualizerSchema, LanesSchema, NotesSchema, PointsSchema, RealPointSchema, SendType, TempoAutomationConverter, TimeSignaturePointSchema, TrackSchema, WarpsSchema } from "@opendaw/lib-dawproject";
|
|
5
5
|
import { AudioSendRouting, AudioUnitType, IconSymbol } from "@opendaw/studio-enums";
|
|
6
|
-
import { AudioBusBox, AudioFileBox, AudioPitchStretchBox, AudioRegionBox, AudioUnitBox, AuxSendBox, BoxIO, CaptureAudioBox, CaptureMidiBox, GrooveShuffleBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, RootBox, TimelineBox, TrackBox, UnknownAudioEffectDeviceBox, UnknownMidiEffectDeviceBox, UserInterfaceBox, ValueEventCollectionBox } from "@opendaw/studio-boxes";
|
|
7
|
-
import { AudioUnitOrdering, ColorCodes, InstrumentFactories, TrackType } from "@opendaw/studio-adapters";
|
|
6
|
+
import { AudioBusBox, AudioFileBox, AudioPitchStretchBox, AudioRegionBox, AudioUnitBox, AuxSendBox, BoxIO, CaptureAudioBox, CaptureMidiBox, GrooveShuffleBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, RootBox, SignatureEventBox, TimelineBox, TrackBox, UnknownAudioEffectDeviceBox, UnknownMidiEffectDeviceBox, UserInterfaceBox, ValueEventBox, ValueEventCollectionBox } from "@opendaw/studio-boxes";
|
|
7
|
+
import { AudioUnitOrdering, ColorCodes, InstrumentFactories, InterpolationFieldAdapter, TrackType } from "@opendaw/studio-adapters";
|
|
8
8
|
import { BuiltinDevices } from "./BuiltinDevices";
|
|
9
9
|
import { AudioContentHelpers } from "../project/audio/AudioContentHelpers";
|
|
10
10
|
export var DawProjectImport;
|
|
@@ -344,6 +344,74 @@ export var DawProjectImport;
|
|
|
344
344
|
box.playMode.refer(pitchStretch);
|
|
345
345
|
});
|
|
346
346
|
};
|
|
347
|
+
const readTempoAutomation = (tempoAutomation) => {
|
|
348
|
+
const points = tempoAutomation.points;
|
|
349
|
+
if (!isDefined(points) || points.length === 0) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const minBpm = timelineBox.tempoTrack.minBpm.getValue();
|
|
353
|
+
const maxBpm = timelineBox.tempoTrack.maxBpm.getValue();
|
|
354
|
+
const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
|
|
355
|
+
timelineBox.tempoTrack.events.refer(collectionBox.owners);
|
|
356
|
+
timelineBox.tempoTrack.enabled.setValue(true);
|
|
357
|
+
points
|
|
358
|
+
.filter((point) => isInstanceOf(point, RealPointSchema))
|
|
359
|
+
.forEach(point => {
|
|
360
|
+
const eventBox = ValueEventBox.create(boxGraph, UUID.generate(), box => {
|
|
361
|
+
box.position.setValue(point.time * PPQN.Quarter);
|
|
362
|
+
box.index.setValue(0);
|
|
363
|
+
box.value.setValue(TempoAutomationConverter.bpmToNormalized(point.value, minBpm, maxBpm));
|
|
364
|
+
box.events.refer(collectionBox.events);
|
|
365
|
+
});
|
|
366
|
+
const interpolation = TempoAutomationConverter.fromDawProjectInterpolation(point.interpolation);
|
|
367
|
+
InterpolationFieldAdapter.write(eventBox.interpolation, interpolation);
|
|
368
|
+
});
|
|
369
|
+
};
|
|
370
|
+
ifDefined(arrangement.tempoAutomation, readTempoAutomation);
|
|
371
|
+
const readSignatureAutomation = (signatureAutomation) => {
|
|
372
|
+
const points = signatureAutomation.points;
|
|
373
|
+
if (!isDefined(points) || points.length === 0) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const signaturePoints = points
|
|
377
|
+
.filter((point) => isInstanceOf(point, TimeSignaturePointSchema))
|
|
378
|
+
.sort((pointA, pointB) => pointA.time - pointB.time);
|
|
379
|
+
if (signaturePoints.length === 0) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
// First point at or near time 0 sets the base signature
|
|
383
|
+
const firstPoint = signaturePoints[0];
|
|
384
|
+
const firstPointIsAtStart = Number(firstPoint.time) < 0.001;
|
|
385
|
+
if (firstPointIsAtStart) {
|
|
386
|
+
timelineBox.signature.nominator.setValue(firstPoint.numerator);
|
|
387
|
+
timelineBox.signature.denominator.setValue(firstPoint.denominator);
|
|
388
|
+
}
|
|
389
|
+
// Remaining points become SignatureEventBox instances
|
|
390
|
+
const eventsToCreate = firstPointIsAtStart ? signaturePoints.slice(1) : signaturePoints;
|
|
391
|
+
if (eventsToCreate.length === 0) {
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
timelineBox.signatureTrack.enabled.setValue(true);
|
|
395
|
+
let prevPpqn = 0;
|
|
396
|
+
let prevNominator = timelineBox.signature.nominator.getValue();
|
|
397
|
+
let prevDenominator = timelineBox.signature.denominator.getValue();
|
|
398
|
+
eventsToCreate.forEach((point, index) => {
|
|
399
|
+
const currentPpqn = point.time * PPQN.Quarter;
|
|
400
|
+
const barDuration = PPQN.fromSignature(prevNominator, prevDenominator);
|
|
401
|
+
const relativePosition = Math.max(1, Math.round((currentPpqn - prevPpqn) / barDuration));
|
|
402
|
+
SignatureEventBox.create(boxGraph, UUID.generate(), box => {
|
|
403
|
+
box.index.setValue(index);
|
|
404
|
+
box.relativePosition.setValue(relativePosition);
|
|
405
|
+
box.nominator.setValue(point.numerator);
|
|
406
|
+
box.denominator.setValue(point.denominator);
|
|
407
|
+
box.events.refer(timelineBox.signatureTrack.events);
|
|
408
|
+
});
|
|
409
|
+
prevPpqn = prevPpqn + relativePosition * barDuration;
|
|
410
|
+
prevNominator = point.numerator;
|
|
411
|
+
prevDenominator = point.denominator;
|
|
412
|
+
});
|
|
413
|
+
};
|
|
414
|
+
ifDefined(arrangement.timeSignatureAutomation, readSignatureAutomation);
|
|
347
415
|
return Promise.all(arrangement?.lanes?.lanes?.filter(timeline => isInstanceOf(timeline, LanesSchema))
|
|
348
416
|
.map(readLane) ?? []);
|
|
349
417
|
};
|