@volter/dawproject 0.5.67 → 0.5.69
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/package.json +1 -1
- package/src/index.ts +75 -2
- package/src/piece.ts +135 -30
- package/src/render.ts +3 -2
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -73,6 +73,22 @@ export interface ChannelProps {
|
|
|
73
73
|
readonly children?: ReactNode;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* A modulator on a `<Channel>`, as Bitwig's LFO: a wave added to one of the channel's own
|
|
78
|
+
* parameters, `target` `volume` or `send:<bus>` (±`depth` dB) or `pan` (±`depth`, the sum
|
|
79
|
+
* clamped to −1…1). One cycle lasts `period` (a note value or a number of beats, so it follows
|
|
80
|
+
* the tempo), counted from the piece's first beat and offset by `phase` (0–1 of a cycle). It adds
|
|
81
|
+
* to the parameter's written value, or to its automation lane where it has one. DAWproject has no
|
|
82
|
+
* modulators: its export writes the moving parameter as automation points.
|
|
83
|
+
*/
|
|
84
|
+
export interface LfoProps {
|
|
85
|
+
readonly target: string;
|
|
86
|
+
readonly shape?: 'sine' | 'triangle' | 'square' | 'saw';
|
|
87
|
+
readonly period: Length;
|
|
88
|
+
readonly depth: number;
|
|
89
|
+
readonly phase?: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
/** DAWproject `Send`: this channel feeds the `effect` channel of the track named `to`, at `level` dB. */
|
|
77
93
|
export interface SendProps {
|
|
78
94
|
readonly to: string;
|
|
@@ -108,9 +124,13 @@ export interface DeviceProps {
|
|
|
108
124
|
readonly params?: Readonly<Record<string, DeviceParam>>;
|
|
109
125
|
}
|
|
110
126
|
|
|
111
|
-
/**
|
|
127
|
+
/**
|
|
128
|
+
* DAWproject `Clip`: a region of a track's timeline, from bar `at` for `bars` bars. In a
|
|
129
|
+
* `<ClipSlot>` a clip has no `at`: it is a loop of its own, and its notes' positions count from
|
|
130
|
+
* its start as bar 1.
|
|
131
|
+
*/
|
|
112
132
|
export interface ClipProps {
|
|
113
|
-
readonly at
|
|
133
|
+
readonly at?: Position;
|
|
114
134
|
readonly bars: number;
|
|
115
135
|
readonly name?: string;
|
|
116
136
|
readonly children?: ReactNode;
|
|
@@ -131,6 +151,33 @@ export interface NoteProps {
|
|
|
131
151
|
readonly artic?: 'staccato' | 'staccatissimo' | 'tenuto' | 'accent' | 'marcato' | 'legato' | 'pizzicato' | 'tremolo';
|
|
132
152
|
}
|
|
133
153
|
|
|
154
|
+
/**
|
|
155
|
+
* DAWproject `Audio`: a recorded file a `<Clip>` plays, instead of notes. `file` is a WAV at a
|
|
156
|
+
* project path; it plays from the clip's start (or from `offset` seconds into the file) for the
|
|
157
|
+
* clip's length, at `gain` dB. A track whose clips hold audio is an audio track: its strip's input
|
|
158
|
+
* is the files, not an instrument.
|
|
159
|
+
*/
|
|
160
|
+
export interface AudioProps {
|
|
161
|
+
readonly file: string;
|
|
162
|
+
readonly offset?: number;
|
|
163
|
+
readonly gain?: number;
|
|
164
|
+
/**
|
|
165
|
+
* The take's name, when a clip holds several recordings of one part (one per pass of a loop):
|
|
166
|
+
* the newest (last) plays unless `<Comp>`s pick others.
|
|
167
|
+
*/
|
|
168
|
+
readonly take?: string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* A comp choice in a clip of several takes: from `at` (a position of the piece, inside the clip)
|
|
173
|
+
* the take named `take` plays, until the next `<Comp>`. Before the first, the newest take plays.
|
|
174
|
+
* Where the take changes, the two cross in 5 ms.
|
|
175
|
+
*/
|
|
176
|
+
export interface CompProps {
|
|
177
|
+
readonly take: string;
|
|
178
|
+
readonly at: Position;
|
|
179
|
+
}
|
|
180
|
+
|
|
134
181
|
/**
|
|
135
182
|
* DAWproject `Points`: an automation lane. In a `<Clip>`, `target` is a MIDI controller
|
|
136
183
|
* (`cc1` modulation, `cc11` expression, `cc64` sustain, …) or `pitchbend`, with values 0–1
|
|
@@ -148,6 +195,22 @@ export interface PointProps {
|
|
|
148
195
|
readonly hold?: boolean;
|
|
149
196
|
}
|
|
150
197
|
|
|
198
|
+
/**
|
|
199
|
+
* DAWproject `Scene`: a row of the clip launcher, a child of `<Project>`. Launching it plays each
|
|
200
|
+
* of its `<ClipSlot>`s on that slot's track, looping, from the next bar, and stops the tracks it
|
|
201
|
+
* has no slot for: one scene is one state of the music (a game's explore, combat, calm).
|
|
202
|
+
*/
|
|
203
|
+
export interface SceneProps {
|
|
204
|
+
readonly name: string;
|
|
205
|
+
readonly children?: ReactNode;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** DAWproject `ClipSlot`: the launcher cell of the track named `track` in a scene, holding one `<Clip>`. */
|
|
209
|
+
export interface ClipSlotProps {
|
|
210
|
+
readonly track: string;
|
|
211
|
+
readonly children?: ReactNode;
|
|
212
|
+
}
|
|
213
|
+
|
|
151
214
|
/** DAWproject `Marker`: a named point on the arrangement's timeline. */
|
|
152
215
|
export interface MarkerProps {
|
|
153
216
|
readonly at: Position;
|
|
@@ -168,7 +231,12 @@ export const Clip = element<ClipProps>('dawproject.Clip');
|
|
|
168
231
|
export const Note = element<NoteProps>('dawproject.Note');
|
|
169
232
|
export const Marker = element<MarkerProps>('dawproject.Marker');
|
|
170
233
|
export const Points = element<PointsProps>('dawproject.Points');
|
|
234
|
+
export const Audio = element<AudioProps>('dawproject.Audio');
|
|
171
235
|
export const Point = element<PointProps>('dawproject.Point');
|
|
236
|
+
export const Lfo = element<LfoProps>('dawproject.Lfo');
|
|
237
|
+
export const Comp = element<CompProps>('dawproject.Comp');
|
|
238
|
+
export const Scene = element<SceneProps>('dawproject.Scene');
|
|
239
|
+
export const ClipSlot = element<ClipSlotProps>('dawproject.ClipSlot');
|
|
172
240
|
|
|
173
241
|
/** Every element this package names, keyed by its short name. */
|
|
174
242
|
export const ELEMENT_TYPES = {
|
|
@@ -183,6 +251,11 @@ export const ELEMENT_TYPES = {
|
|
|
183
251
|
Marker: 'dawproject.Marker',
|
|
184
252
|
Points: 'dawproject.Points',
|
|
185
253
|
Point: 'dawproject.Point',
|
|
254
|
+
Audio: 'dawproject.Audio',
|
|
255
|
+
Lfo: 'dawproject.Lfo',
|
|
256
|
+
Comp: 'dawproject.Comp',
|
|
257
|
+
Scene: 'dawproject.Scene',
|
|
258
|
+
ClipSlot: 'dawproject.ClipSlot',
|
|
186
259
|
} as const;
|
|
187
260
|
|
|
188
261
|
export type ElementName = keyof typeof ELEMENT_TYPES;
|
package/src/piece.ts
CHANGED
|
@@ -70,6 +70,29 @@ export interface PieceClip {
|
|
|
70
70
|
readonly duration: number;
|
|
71
71
|
readonly notes: readonly PieceNote[];
|
|
72
72
|
readonly lanes: readonly PiecePoints[];
|
|
73
|
+
/** The recorded file this clip plays by default (`<Audio>`, the newest take), or `null` for a note clip. */
|
|
74
|
+
readonly audio: PieceAudio | null;
|
|
75
|
+
/** Every `<Audio>` in the clip, oldest first: its takes when there are several. */
|
|
76
|
+
readonly takes: readonly PieceAudio[];
|
|
77
|
+
/** Which take plays from where (`<Comp>`), in time order. */
|
|
78
|
+
readonly comps: readonly PieceComp[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A comp choice: from `time` (beats of the piece) the take named `take` plays. */
|
|
82
|
+
export interface PieceComp {
|
|
83
|
+
readonly oid: string | null;
|
|
84
|
+
readonly take: string;
|
|
85
|
+
readonly time: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** A clip's recorded file: a WAV at a project path, from `offset` seconds into it, at `gain` dB. */
|
|
89
|
+
export interface PieceAudio {
|
|
90
|
+
readonly oid: string | null;
|
|
91
|
+
readonly file: string;
|
|
92
|
+
readonly offset: number;
|
|
93
|
+
readonly gain: number;
|
|
94
|
+
/** Its take name (`take`), or its place among the clip's takes from 1 when unnamed. */
|
|
95
|
+
readonly take: string;
|
|
73
96
|
}
|
|
74
97
|
|
|
75
98
|
export interface PieceDevice {
|
|
@@ -88,6 +111,18 @@ export interface PieceSend {
|
|
|
88
111
|
readonly pre: boolean;
|
|
89
112
|
}
|
|
90
113
|
|
|
114
|
+
/** A channel's LFO (`<Lfo>`): a wave added to `target`, one cycle per `period` beats. */
|
|
115
|
+
export interface PieceLfo {
|
|
116
|
+
readonly oid: string | null;
|
|
117
|
+
readonly target: string;
|
|
118
|
+
readonly shape: 'sine' | 'triangle' | 'square' | 'saw';
|
|
119
|
+
readonly period: number;
|
|
120
|
+
readonly depth: number;
|
|
121
|
+
readonly phase: number;
|
|
122
|
+
/** The period as written (`"h"`, `2`), for an editor field. */
|
|
123
|
+
readonly writtenPeriod: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
91
126
|
export interface PieceChannel {
|
|
92
127
|
readonly oid: string | null;
|
|
93
128
|
/** `submix`: a group track's channel, summing the tracks it contains (DAWproject's role). */
|
|
@@ -98,6 +133,7 @@ export interface PieceChannel {
|
|
|
98
133
|
readonly solo: boolean;
|
|
99
134
|
readonly devices: readonly PieceDevice[];
|
|
100
135
|
readonly sends: readonly PieceSend[];
|
|
136
|
+
readonly lfos: readonly PieceLfo[];
|
|
101
137
|
}
|
|
102
138
|
|
|
103
139
|
export interface PieceTrack {
|
|
@@ -116,6 +152,23 @@ export interface PieceTrack {
|
|
|
116
152
|
readonly parent: string | null;
|
|
117
153
|
}
|
|
118
154
|
|
|
155
|
+
/** A launcher cell: the clip the track named `track` loops when the slot is launched. */
|
|
156
|
+
export interface PieceSlot {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
readonly oid: string | null;
|
|
159
|
+
readonly track: string;
|
|
160
|
+
/** Its clip, whose `time` is 0 and whose notes count from its start; `null` for an empty slot. */
|
|
161
|
+
readonly clip: PieceClip | null;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** A row of the clip launcher (`<Scene>`). */
|
|
165
|
+
export interface PieceScene {
|
|
166
|
+
readonly id: string;
|
|
167
|
+
readonly oid: string | null;
|
|
168
|
+
readonly name: string;
|
|
169
|
+
readonly slots: readonly PieceSlot[];
|
|
170
|
+
}
|
|
171
|
+
|
|
119
172
|
export interface PieceMarker {
|
|
120
173
|
readonly id: string;
|
|
121
174
|
readonly oid: string | null;
|
|
@@ -127,7 +180,9 @@ export interface Piece {
|
|
|
127
180
|
readonly transport: PieceTransport;
|
|
128
181
|
readonly tracks: readonly PieceTrack[];
|
|
129
182
|
readonly markers: readonly PieceMarker[];
|
|
130
|
-
/** The
|
|
183
|
+
/** The clip launcher's rows, in source order. */
|
|
184
|
+
readonly scenes: readonly PieceScene[];
|
|
185
|
+
/** The last beat any arrangement clip reaches. */
|
|
131
186
|
readonly length: number;
|
|
132
187
|
/** How many nodes each oid rendered; above 1 means the element repeats. */
|
|
133
188
|
readonly oidCounts: ReadonlyMap<string, number>;
|
|
@@ -190,7 +245,51 @@ export function readPiece(root: DawNode): Piece {
|
|
|
190
245
|
const withTempo: PieceTransport = tempoNode ? { ...transport, tempoPoints: readLane(tempoNode, 'transport:tempo', '<Transport>') } : transport;
|
|
191
246
|
const tracks: PieceTrack[] = [];
|
|
192
247
|
const markers: PieceMarker[] = [];
|
|
248
|
+
const scenes: PieceScene[] = [];
|
|
193
249
|
let length = 0;
|
|
250
|
+
/**
|
|
251
|
+
* A clip: on a track, a region from its `at`; in a launcher slot (`arranged` false), a loop of its
|
|
252
|
+
* own whose time is 0, so its notes' `at` counts from its start as bar 1.
|
|
253
|
+
*/
|
|
254
|
+
const readClip = (child: DawNode, clipId: string, trackName: string, arranged: boolean): PieceClip => {
|
|
255
|
+
const clipName = str(child.props['name']);
|
|
256
|
+
const where = `<Clip${clipName ? ` "${clipName}"` : ''}> on ${trackName}`;
|
|
257
|
+
const time = arranged ? position(child.props['at'], where) : 0;
|
|
258
|
+
const duration = num(child.props['bars'], 0) * beatsPerBar;
|
|
259
|
+
const notes: PieceNote[] = child.children
|
|
260
|
+
.filter((note) => note.type === 'Note')
|
|
261
|
+
.map((note, noteIndex) => {
|
|
262
|
+
const writtenPitch = String(note.props['pitch'] ?? '');
|
|
263
|
+
const writtenDur = note.props['dur'];
|
|
264
|
+
const start = position(note.props['at'], `A <Note> in ${where}`);
|
|
265
|
+
return {
|
|
266
|
+
id: `${clipId}:note:${noteIndex}`,
|
|
267
|
+
oid: note.oid,
|
|
268
|
+
start,
|
|
269
|
+
time: start - time,
|
|
270
|
+
duration: beatsOf(typeof writtenDur === 'number' ? writtenDur : String(writtenDur ?? '')),
|
|
271
|
+
pitch: midiOf(writtenPitch),
|
|
272
|
+
vel: num(note.props['vel'], 0.7),
|
|
273
|
+
artic: str(note.props['artic']),
|
|
274
|
+
written: { at: String(note.props['at'] ?? ''), pitch: writtenPitch, dur: String(writtenDur ?? '') },
|
|
275
|
+
};
|
|
276
|
+
});
|
|
277
|
+
const lanes = child.children.filter((lane) => lane.type === 'Points').map((lane, laneIndex) => readLane(lane, `${clipId}:lane:${laneIndex}`, where));
|
|
278
|
+
const takes: PieceAudio[] = child.children
|
|
279
|
+
.filter((part) => part.type === 'Audio')
|
|
280
|
+
.map((part, takeIndex) => ({
|
|
281
|
+
oid: part.oid,
|
|
282
|
+
file: str(part.props['file']) ?? '',
|
|
283
|
+
offset: num(part.props['offset'], 0),
|
|
284
|
+
gain: num(part.props['gain'], 0),
|
|
285
|
+
take: str(part.props['take']) ?? String(takeIndex + 1),
|
|
286
|
+
}));
|
|
287
|
+
const comps: PieceComp[] = child.children
|
|
288
|
+
.filter((part) => part.type === 'Comp')
|
|
289
|
+
.map((part) => ({ oid: part.oid, take: str(part.props['take']) ?? '', time: position(part.props['at'], `A <Comp> in ${where}`) }))
|
|
290
|
+
.sort((a, b) => a.time - b.time);
|
|
291
|
+
return { id: clipId, oid: child.oid, name: clipName, time, duration, notes, lanes, audio: takes.at(-1) ?? null, takes, comps };
|
|
292
|
+
};
|
|
194
293
|
/**
|
|
195
294
|
* A track, and (after it) every track it contains: a group's children sum into its strip, the
|
|
196
295
|
* group's channel `role="submix"`. `parent` is the group track's id.
|
|
@@ -209,6 +308,27 @@ export function readPiece(root: DawNode): Piece {
|
|
|
209
308
|
sends: child.children
|
|
210
309
|
.filter((send) => send.type === 'Send')
|
|
211
310
|
.map((send) => ({ oid: send.oid, to: str(send.props['to']) ?? '', level: num(send.props['level'], 0), pre: bool(send.props['pre']) })),
|
|
311
|
+
lfos: child.children
|
|
312
|
+
.filter((lfo) => lfo.type === 'Lfo')
|
|
313
|
+
.map((lfo) => {
|
|
314
|
+
const shape = str(lfo.props['shape']);
|
|
315
|
+
const period = lfo.props['period'];
|
|
316
|
+
return {
|
|
317
|
+
oid: lfo.oid,
|
|
318
|
+
target: str(lfo.props['target']) ?? '',
|
|
319
|
+
shape: shape === 'triangle' || shape === 'square' || shape === 'saw' ? shape : 'sine',
|
|
320
|
+
period: (() => {
|
|
321
|
+
try {
|
|
322
|
+
return beatsOf(typeof period === 'number' ? period : String(period ?? ''));
|
|
323
|
+
} catch (error) {
|
|
324
|
+
throw new Error(`The <Lfo> on ${trackName}'s channel has no period it can cycle over: ${error instanceof Error ? error.message : String(error)}`);
|
|
325
|
+
}
|
|
326
|
+
})(),
|
|
327
|
+
depth: num(lfo.props['depth'], 0),
|
|
328
|
+
phase: num(lfo.props['phase'], 0),
|
|
329
|
+
writtenPeriod: String(period ?? ''),
|
|
330
|
+
};
|
|
331
|
+
}),
|
|
212
332
|
volume: num(child.props['volume'], 0),
|
|
213
333
|
pan: num(child.props['pan'], 0),
|
|
214
334
|
mute: bool(child.props['mute']),
|
|
@@ -224,34 +344,9 @@ export function readPiece(root: DawNode): Piece {
|
|
|
224
344
|
})),
|
|
225
345
|
};
|
|
226
346
|
} else if (child.type === 'Clip') {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const time = position(child.props['at'], where);
|
|
231
|
-
const duration = num(child.props['bars'], 0) * beatsPerBar;
|
|
232
|
-
const notes: PieceNote[] = child.children
|
|
233
|
-
.filter((note) => note.type === 'Note')
|
|
234
|
-
.map((note, noteIndex) => {
|
|
235
|
-
const writtenPitch = String(note.props['pitch'] ?? '');
|
|
236
|
-
const writtenDur = note.props['dur'];
|
|
237
|
-
const start = position(note.props['at'], `A <Note> in ${where}`);
|
|
238
|
-
return {
|
|
239
|
-
id: `${clipId}:note:${noteIndex}`,
|
|
240
|
-
oid: note.oid,
|
|
241
|
-
start,
|
|
242
|
-
time: start - time,
|
|
243
|
-
duration: beatsOf(typeof writtenDur === 'number' ? writtenDur : String(writtenDur ?? '')),
|
|
244
|
-
pitch: midiOf(writtenPitch),
|
|
245
|
-
vel: num(note.props['vel'], 0.7),
|
|
246
|
-
artic: str(note.props['artic']),
|
|
247
|
-
written: { at: String(note.props['at'] ?? ''), pitch: writtenPitch, dur: String(writtenDur ?? '') },
|
|
248
|
-
};
|
|
249
|
-
});
|
|
250
|
-
const lanes = child.children
|
|
251
|
-
.filter((lane) => lane.type === 'Points')
|
|
252
|
-
.map((lane, laneIndex) => readLane(lane, `${clipId}:lane:${laneIndex}`, where));
|
|
253
|
-
length = Math.max(length, time + duration);
|
|
254
|
-
clips.push({ id: clipId, oid: child.oid, name: clipName, time, duration, notes, lanes });
|
|
347
|
+
const clip = readClip(child, `${trackId}:clip:${childIndex}`, trackName, true);
|
|
348
|
+
length = Math.max(length, clip.time + clip.duration);
|
|
349
|
+
clips.push(clip);
|
|
255
350
|
} else if (child.type === 'Points') {
|
|
256
351
|
trackLanes.push(readLane(child, `${trackId}:lane:${childIndex}`, `<Track "${trackName}">`));
|
|
257
352
|
}
|
|
@@ -266,9 +361,19 @@ export function readPiece(root: DawNode): Piece {
|
|
|
266
361
|
markers.push({ id: `marker:${index}`, oid: node.oid, time: position(node.props['at'], 'A <Marker>'), name: str(node.props['name']) ?? '' });
|
|
267
362
|
} else if (node.type === 'Track') {
|
|
268
363
|
readTrack(node, `track:${index}`, null);
|
|
364
|
+
} else if (node.type === 'Scene') {
|
|
365
|
+
const sceneId = `scene:${index}`;
|
|
366
|
+
const slots = node.children.flatMap((slot, slotIndex): PieceSlot[] => {
|
|
367
|
+
if (slot.type !== 'ClipSlot') return [];
|
|
368
|
+
const track = str(slot.props['track']) ?? '';
|
|
369
|
+
const clipNode = slot.children.find((child) => child.type === 'Clip');
|
|
370
|
+
const id = `${sceneId}:slot:${slotIndex}`;
|
|
371
|
+
return [{ id, oid: slot.oid, track, clip: clipNode ? readClip(clipNode, `${id}:clip`, track, false) : null }];
|
|
372
|
+
});
|
|
373
|
+
scenes.push({ id: sceneId, oid: node.oid, name: str(node.props['name']) ?? `Scene ${scenes.length + 1}`, slots });
|
|
269
374
|
}
|
|
270
375
|
});
|
|
271
|
-
return { transport: withTempo, tracks, markers, length, oidCounts };
|
|
376
|
+
return { transport: withTempo, tracks, markers, scenes, length, oidCounts };
|
|
272
377
|
}
|
|
273
378
|
|
|
274
379
|
/** Seconds per beat at the piece's tempo (a constant tempo; tempo automation is not read yet). */
|
package/src/render.ts
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import type { ComponentType, ReactNode } from 'react';
|
|
17
17
|
import { createElement } from 'react';
|
|
18
18
|
import Reconciler from 'react-reconciler';
|
|
19
|
+
import { ELEMENT_TYPES } from './index';
|
|
19
20
|
import { ConcurrentRoot, DefaultEventPriority } from 'react-reconciler/constants.js';
|
|
20
21
|
|
|
21
22
|
export const OID_PROP = 'data-oid';
|
|
@@ -59,7 +60,7 @@ function ownProps(props: Record<string, unknown>): { props: Record<string, unkno
|
|
|
59
60
|
function shortType(type: string): string {
|
|
60
61
|
if (!type.startsWith(TYPE_PREFIX)) {
|
|
61
62
|
throw new Error(
|
|
62
|
-
`<${type}> is not a DAWproject element. A piece renders only @volter/dawproject's elements (
|
|
63
|
+
`<${type}> is not a DAWproject element. A piece renders only @volter/dawproject's elements (${Object.keys(ELEMENT_TYPES).join(', ')}) and components made of them.`,
|
|
63
64
|
);
|
|
64
65
|
}
|
|
65
66
|
return type.slice(TYPE_PREFIX.length);
|
|
@@ -163,7 +164,7 @@ const reconciler = Reconciler({
|
|
|
163
164
|
resolveEventType: () => null,
|
|
164
165
|
resolveEventTimeStamp: () => -1.1,
|
|
165
166
|
rendererPackageName: '@volter/dawproject',
|
|
166
|
-
rendererVersion: '0.5.
|
|
167
|
+
rendererVersion: '0.5.69',
|
|
167
168
|
} as never);
|
|
168
169
|
|
|
169
170
|
function snapshot(instance: Instance): DawNode {
|