@opendaw/studio-core 0.0.19 → 0.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/AudioInputDevices.d.ts +8 -0
  2. package/dist/AudioInputDevices.d.ts.map +1 -0
  3. package/dist/AudioInputDevices.js +30 -0
  4. package/dist/AudioUnitOrdering.d.ts +3 -0
  5. package/dist/AudioUnitOrdering.d.ts.map +1 -0
  6. package/dist/AudioUnitOrdering.js +7 -0
  7. package/dist/EffectBox.d.ts +2 -2
  8. package/dist/EffectBox.d.ts.map +1 -1
  9. package/dist/Engine.d.ts +31 -10
  10. package/dist/Engine.d.ts.map +1 -1
  11. package/dist/EngineFacade.d.ts +22 -11
  12. package/dist/EngineFacade.d.ts.map +1 -1
  13. package/dist/EngineFacade.js +39 -22
  14. package/dist/EngineWorklet.d.ts +22 -13
  15. package/dist/EngineWorklet.d.ts.map +1 -1
  16. package/dist/EngineWorklet.js +47 -56
  17. package/dist/MeterWorklet.d.ts.map +1 -1
  18. package/dist/MeterWorklet.js +2 -2
  19. package/dist/Project.d.ts +4 -2
  20. package/dist/Project.d.ts.map +1 -1
  21. package/dist/Project.js +6 -3
  22. package/dist/ProjectApi.d.ts +0 -1
  23. package/dist/ProjectApi.d.ts.map +1 -1
  24. package/dist/ProjectApi.js +16 -11
  25. package/dist/ProjectEnv.d.ts +1 -0
  26. package/dist/ProjectEnv.d.ts.map +1 -1
  27. package/dist/ProjectMigration.d.ts.map +1 -1
  28. package/dist/ProjectMigration.js +20 -3
  29. package/dist/RecordingWorklet.d.ts +15 -3
  30. package/dist/RecordingWorklet.d.ts.map +1 -1
  31. package/dist/RecordingWorklet.js +111 -16
  32. package/dist/WorkerAgents.d.ts +2 -2
  33. package/dist/WorkerAgents.d.ts.map +1 -1
  34. package/dist/Worklets.d.ts +1 -1
  35. package/dist/Worklets.d.ts.map +1 -1
  36. package/dist/Worklets.js +2 -2
  37. package/dist/capture/Capture.d.ts +22 -0
  38. package/dist/capture/Capture.d.ts.map +1 -0
  39. package/dist/capture/Capture.js +32 -0
  40. package/dist/capture/CaptureAudio.d.ts +17 -0
  41. package/dist/capture/CaptureAudio.d.ts.map +1 -0
  42. package/dist/capture/CaptureAudio.js +106 -0
  43. package/dist/capture/CaptureManager.d.ts +12 -0
  44. package/dist/capture/CaptureManager.d.ts.map +1 -0
  45. package/dist/capture/CaptureManager.js +38 -0
  46. package/dist/capture/CaptureMidi.d.ts +13 -0
  47. package/dist/capture/CaptureMidi.d.ts.map +1 -0
  48. package/dist/capture/CaptureMidi.js +50 -0
  49. package/dist/capture/RecordAudio.d.ts +21 -0
  50. package/dist/capture/RecordAudio.d.ts.map +1 -0
  51. package/dist/capture/RecordAudio.js +66 -0
  52. package/dist/capture/RecordMidi.d.ts +15 -0
  53. package/dist/capture/RecordMidi.d.ts.map +1 -0
  54. package/dist/capture/RecordMidi.js +85 -0
  55. package/dist/capture/RecordTrack.d.ts +7 -0
  56. package/dist/capture/RecordTrack.d.ts.map +1 -0
  57. package/dist/capture/RecordTrack.js +23 -0
  58. package/dist/capture/Recording.d.ts +9 -0
  59. package/dist/capture/Recording.d.ts.map +1 -0
  60. package/dist/capture/Recording.js +65 -0
  61. package/dist/capture/RecordingContext.d.ts +14 -0
  62. package/dist/capture/RecordingContext.d.ts.map +1 -0
  63. package/dist/capture/RecordingContext.js +1 -0
  64. package/dist/dawproject/AudioUnitExportLayout.d.ts +10 -0
  65. package/dist/dawproject/AudioUnitExportLayout.d.ts.map +1 -0
  66. package/dist/dawproject/AudioUnitExportLayout.js +64 -0
  67. package/dist/dawproject/BuiltinDevices.d.ts +9 -0
  68. package/dist/dawproject/BuiltinDevices.d.ts.map +1 -0
  69. package/dist/dawproject/BuiltinDevices.js +70 -0
  70. package/dist/dawproject/{DawProjectIO.d.ts → DawProject.d.ts} +6 -4
  71. package/dist/dawproject/DawProject.d.ts.map +1 -0
  72. package/dist/dawproject/{DawProjectIO.js → DawProject.js} +23 -5
  73. package/dist/dawproject/DawProjectExporter.d.ts +7 -6
  74. package/dist/dawproject/DawProjectExporter.d.ts.map +1 -1
  75. package/dist/dawproject/DawProjectExporter.js +245 -22
  76. package/dist/dawproject/DawProjectExporter.test.js +39 -6
  77. package/dist/dawproject/DawProjectImport.d.ts +12 -0
  78. package/dist/dawproject/DawProjectImport.d.ts.map +1 -0
  79. package/dist/dawproject/DawProjectImport.js +389 -0
  80. package/dist/dawproject/DawProjectImport.test.js +6 -7
  81. package/dist/dawproject/DeviceIO.d.ts +8 -0
  82. package/dist/dawproject/DeviceIO.d.ts.map +1 -0
  83. package/dist/dawproject/DeviceIO.js +63 -0
  84. package/dist/index.d.ts +11 -3
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +11 -3
  87. package/dist/processors.js +3 -3
  88. package/dist/processors.js.map +4 -4
  89. package/dist/samples/MainThreadSampleLoader.d.ts +1 -0
  90. package/dist/samples/MainThreadSampleLoader.d.ts.map +1 -1
  91. package/dist/samples/MainThreadSampleLoader.js +10 -6
  92. package/dist/samples/MainThreadSampleManager.d.ts +5 -5
  93. package/dist/samples/MainThreadSampleManager.d.ts.map +1 -1
  94. package/dist/samples/MainThreadSampleManager.js +1 -0
  95. package/dist/samples/SampleProvider.d.ts +2 -2
  96. package/dist/samples/SampleProvider.d.ts.map +1 -1
  97. package/dist/samples/SampleStorage.d.ts.map +1 -1
  98. package/dist/samples/SampleStorage.js +2 -3
  99. package/dist/workers.js +2 -2
  100. package/dist/workers.js.map +4 -4
  101. package/package.json +15 -15
  102. package/dist/dawproject/DawProjectIO.d.ts.map +0 -1
  103. package/dist/dawproject/DawProjectImporter.d.ts +0 -12
  104. package/dist/dawproject/DawProjectImporter.d.ts.map +0 -1
  105. package/dist/dawproject/DawProjectImporter.js +0 -273
  106. package/dist/samples/SamplePeaks.d.ts +0 -6
  107. package/dist/samples/SamplePeaks.d.ts.map +0 -1
  108. package/dist/samples/SamplePeaks.js +0 -9
@@ -1,10 +1,11 @@
1
1
  import JSZip from "jszip";
2
2
  import { Xml } from "@opendaw/lib-xml";
3
3
  import { asDefined, panic, UUID } from "@opendaw/lib-std";
4
- import { MetaDataSchema, ProjectSchema } from "@opendaw/lib-dawproject";
5
- export var DawProjectIO;
6
- (function (DawProjectIO) {
7
- DawProjectIO.decode = async (buffer) => {
4
+ import { FileReferenceSchema, MetaDataSchema, ProjectSchema } from "@opendaw/lib-dawproject";
5
+ import { DawProjectExporter } from "./DawProjectExporter";
6
+ export var DawProject;
7
+ (function (DawProject) {
8
+ DawProject.decode = async (buffer) => {
8
9
  const zip = await JSZip.loadAsync(buffer);
9
10
  const metaData = Xml.parse(asDefined(await zip.file("metadata.xml")
10
11
  ?.async("string"), "No metadata.xml found"), MetaDataSchema);
@@ -28,4 +29,21 @@ export var DawProjectIO;
28
29
  }
29
30
  };
30
31
  };
31
- })(DawProjectIO || (DawProjectIO = {}));
32
+ DawProject.encode = (project, metaData) => {
33
+ const zip = new JSZip();
34
+ const projectSchema = DawProjectExporter.write(project, {
35
+ write: (path, buffer) => {
36
+ zip.file(path, buffer);
37
+ return Xml.element({ path, external: false }, FileReferenceSchema);
38
+ }
39
+ });
40
+ const metaDataXml = Xml.pretty(Xml.toElement("MetaData", metaData));
41
+ const projectXml = Xml.pretty(Xml.toElement("Project", projectSchema));
42
+ console.debug("encode");
43
+ console.debug(metaDataXml);
44
+ console.debug(projectXml);
45
+ zip.file("metadata.xml", metaDataXml);
46
+ zip.file("project.xml", projectXml);
47
+ return zip.generateAsync({ type: "arraybuffer" });
48
+ };
49
+ })(DawProject || (DawProject = {}));
@@ -1,8 +1,9 @@
1
- import { ProjectDecoder } from "@opendaw/studio-adapters";
2
- export declare class DawProjectExporter {
3
- #private;
4
- static exportProject(skeleton: ProjectDecoder.Skeleton): DawProjectExporter;
5
- constructor(skeleton: ProjectDecoder.Skeleton);
6
- toProjectXml(): string;
1
+ import { FileReferenceSchema, ProjectSchema } from "@opendaw/lib-dawproject";
2
+ import { Project } from "../Project";
3
+ export declare namespace DawProjectExporter {
4
+ interface ResourcePacker {
5
+ write(path: string, buffer: ArrayBufferLike): FileReferenceSchema;
6
+ }
7
+ const write: (project: Project, resourcePacker: ResourcePacker) => ProjectSchema;
7
8
  }
8
9
  //# sourceMappingURL=DawProjectExporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DawProjectExporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectExporter.ts"],"names":[],"mappings":"AASA,OAAO,EAAC,cAAc,EAAC,MAAM,0BAA0B,CAAA;AAEvD,qBAAa,kBAAkB;;IAC3B,MAAM,CAAC,aAAa,CAAC,QAAQ,EAAE,cAAc,CAAC,QAAQ,GAAG,kBAAkB;gBAM/D,QAAQ,EAAE,cAAc,CAAC,QAAQ;IAE7C,YAAY,IAAI,MAAM;CAoBzB"}
1
+ {"version":3,"file":"DawProjectExporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectExporter.ts"],"names":[],"mappings":"AAGA,OAAO,EAaH,mBAAmB,EAKnB,aAAa,EAUhB,MAAM,yBAAyB,CAAA;AAchC,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAQlC,yBAAiB,kBAAkB,CAAC;IAChC,UAAiB,cAAc;QAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,mBAAmB,CAAA;KAAC;IAE5F,MAAM,KAAK,GAAI,SAAS,OAAO,EAAE,gBAAgB,cAAc,kBA4PrE,CAAA;CACJ"}
@@ -1,29 +1,252 @@
1
+ import { asDefined, asInstanceOf, Color, ifDefined, isInstanceOf, Option, UUID } from "@opendaw/lib-std";
1
2
  import { Xml } from "@opendaw/lib-xml";
2
- import { ApplicationSchema, ArrangementSchema, ProjectSchema, RealParameterSchema, TransportSchema, Unit } from "@opendaw/lib-dawproject";
3
- export class DawProjectExporter {
4
- static exportProject(skeleton) {
5
- return new DawProjectExporter(skeleton);
6
- }
7
- #skeleton;
8
- constructor(skeleton) { this.#skeleton = skeleton; }
9
- toProjectXml() {
10
- const { rootBox, timelineBox } = this.#skeleton.mandatoryBoxes;
11
- const element = Xml.toElement("Project", Xml.element({
3
+ import { dbToGain, PPQN } from "@opendaw/lib-dsp";
4
+ 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";
5
+ import { AddressIdEncoder, BooleanField } from "@opendaw/lib-box";
6
+ import { AudioUnitType } from "@opendaw/studio-enums";
7
+ import { AudioFileBox, AudioUnitBox, NoteEventBox, NoteEventCollectionBox, TrackBox } from "@opendaw/studio-boxes";
8
+ import { AudioUnitExportLayout } from "./AudioUnitExportLayout";
9
+ import { ColorCodes } from "../ColorCodes";
10
+ import { Html } from "@opendaw/lib-dom";
11
+ import { encodeWavFloat } from "../Wav";
12
+ import { DeviceBoxUtils } from "@opendaw/studio-adapters";
13
+ import { DeviceIO } from "./DeviceIO";
14
+ export var DawProjectExporter;
15
+ (function (DawProjectExporter) {
16
+ DawProjectExporter.write = (project, resourcePacker) => {
17
+ const ids = new AddressIdEncoder();
18
+ const { boxGraph, timelineBox, rootBox, sampleManager } = project;
19
+ const audioUnits = rootBox.audioUnits.pointerHub.incoming()
20
+ .map(({ box }) => asInstanceOf(box, AudioUnitBox))
21
+ .sort((a, b) => a.index.getValue() - b.index.getValue());
22
+ boxGraph.boxes().forEach(box => box.accept({
23
+ visitAudioFileBox: (box) => sampleManager.getOrCreate(box.address.uuid).data
24
+ .ifSome(({ frames, numberOfFrames, sampleRate, numberOfChannels }) => resourcePacker.write(`samples/${box.fileName.getValue()}.wav`, encodeWavFloat({
25
+ channels: frames,
26
+ duration: numberOfFrames * sampleRate,
27
+ numberOfChannels,
28
+ sampleRate,
29
+ numFrames: numberOfFrames
30
+ })))
31
+ }));
32
+ const writeTransport = () => Xml.element({
33
+ tempo: Xml.element({
34
+ id: ids.getOrCreate(timelineBox.bpm.address),
35
+ value: timelineBox.bpm.getValue(),
36
+ unit: Unit.BPM
37
+ }, RealParameterSchema),
38
+ timeSignature: Xml.element({
39
+ numerator: timelineBox.signature.nominator.getValue(),
40
+ denominator: timelineBox.signature.denominator.getValue()
41
+ }, TimeSignatureParameterSchema)
42
+ }, TransportSchema);
43
+ const writeDevices = (field, deviceRole) => field.pointerHub
44
+ .incoming().map(({ box }) => {
45
+ const enabled = ("enabled" in box && isInstanceOf(box.enabled, BooleanField)
46
+ ? Option.wrap(box.enabled)
47
+ : Option.None)
48
+ .mapOr(field => ParameterEncoder.bool(ids.getOrCreate(field.address), field.getValue(), "On/Off"), undefined);
49
+ const deviceID = box.name;
50
+ const deviceName = DeviceBoxUtils.lookupLabelField(box).getValue();
51
+ const deviceVendor = "openDAW";
52
+ const id = ids.getOrCreate(box.address);
53
+ return Xml.element({
54
+ id,
55
+ deviceID,
56
+ deviceRole,
57
+ deviceName,
58
+ deviceVendor,
59
+ enabled,
60
+ loaded: true,
61
+ automatedParameters: [],
62
+ state: resourcePacker
63
+ .write(`presets/${UUID.toString(box.address.uuid)}`, DeviceIO.exportDevice(box))
64
+ }, BuiltinDeviceSchema);
65
+ });
66
+ const colorForAudioType = (unitType) => {
67
+ const cssColor = ColorCodes.forAudioType(unitType);
68
+ if (cssColor === "") {
69
+ return "red";
70
+ }
71
+ const [r, g, b] = Html.readCssVarColor(ColorCodes.forAudioType(unitType))[0];
72
+ const RR = Math.round(r * 255).toString(16).padStart(2, "0");
73
+ const GG = Math.round(g * 255).toString(16).padStart(2, "0");
74
+ const BB = Math.round(b * 255).toString(16).padStart(2, "0");
75
+ return `#${RR}${GG}${BB}`;
76
+ };
77
+ const writeStructure = () => {
78
+ const tracks = AudioUnitExportLayout.layout(audioUnits);
79
+ const writeAudioUnitBox = (audioUnitBox, tracks) => {
80
+ const unitType = audioUnitBox.type.getValue();
81
+ const color = colorForAudioType(unitType);
82
+ const isPrimary = unitType === AudioUnitType.Output;
83
+ const isAux = unitType === AudioUnitType.Aux;
84
+ const inputBox = audioUnitBox.input.pointerHub.incoming().at(0)?.box;
85
+ const contentType = isPrimary ? "audio notes" // we copied that value from bitwig
86
+ : isAux ? "audio" : (() =>
87
+ // TODO Another location to remember to put devices in...?
88
+ // We could also read the first track type?
89
+ inputBox?.accept({
90
+ visitTapeDeviceBox: () => "audio",
91
+ visitVaporisateurDeviceBox: () => "notes",
92
+ visitNanoDeviceBox: () => "notes",
93
+ visitPlayfieldDeviceBox: () => "notes",
94
+ visitAudioBusBox: () => "tracks"
95
+ }))() ?? undefined;
96
+ return Xml.element({
97
+ id: ids.getOrCreate(audioUnitBox.address),
98
+ name: DeviceBoxUtils.lookupLabelField(inputBox).getValue(),
99
+ loaded: true,
100
+ color,
101
+ contentType,
102
+ channel: Xml.element({
103
+ id: ifDefined(inputBox, ({ address }) => ids.getOrCreate(address)),
104
+ destination: isPrimary
105
+ ? undefined
106
+ : audioUnitBox.output.targetVertex
107
+ .mapOr(({ box }) => ids.getOrCreate(box.address), undefined),
108
+ role: (() => {
109
+ switch (unitType) {
110
+ case AudioUnitType.Instrument:
111
+ return ChannelRole.REGULAR;
112
+ case AudioUnitType.Aux:
113
+ return ChannelRole.EFFECT;
114
+ case AudioUnitType.Bus:
115
+ case AudioUnitType.Output:
116
+ return ChannelRole.MASTER;
117
+ }
118
+ })(),
119
+ devices: [
120
+ ...(writeDevices(audioUnitBox.midiEffects, DeviceRole.NOTE_FX)),
121
+ ...(writeDevices(audioUnitBox.input, DeviceRole.INSTRUMENT)),
122
+ ...(writeDevices(audioUnitBox.audioEffects, DeviceRole.AUDIO_FX))
123
+ ],
124
+ volume: ParameterEncoder.linear(ids.getOrCreate(audioUnitBox.volume.address), dbToGain(audioUnitBox.volume.getValue()), 0.0, 2.0, "Volume"),
125
+ pan: ParameterEncoder.normalized(ids.getOrCreate(audioUnitBox.panning.address), (audioUnitBox.panning.getValue() + 1.0) / 2.0, 0.0, 1.0, "Pan")
126
+ }, ChannelSchema),
127
+ tracks
128
+ }, TrackSchema);
129
+ };
130
+ const writeTracks = (tracks) => tracks.map((track) => writeAudioUnitBox(track.audioUnit, writeTracks(track.children)));
131
+ return writeTracks(tracks);
132
+ };
133
+ const writeAudioRegion = (region) => {
134
+ const audioFileBox = asInstanceOf(region.file.targetVertex.unwrap("No file at region").box, AudioFileBox);
135
+ const audioElement = sampleManager.getOrCreate(audioFileBox.address.uuid).data
136
+ .map(({ numberOfFrames, sampleRate, numberOfChannels }) => Xml.element({
137
+ duration: numberOfFrames / sampleRate,
138
+ channels: numberOfChannels,
139
+ sampleRate,
140
+ algorithm: AudioAlgorithm.REPITCH,
141
+ file: Xml.element({
142
+ path: `samples/${audioFileBox.fileName.getValue()}.wav`,
143
+ external: false
144
+ }, FileReferenceSchema)
145
+ }, AudioSchema));
146
+ const duration = region.duration.getValue() / PPQN.Quarter;
147
+ return Xml.element({
148
+ clips: [Xml.element({
149
+ time: region.position.getValue() / PPQN.Quarter,
150
+ duration,
151
+ contentTimeUnit: TimeUnit.BEATS,
152
+ playStart: 0.0,
153
+ loopStart: 0.0,
154
+ loopEnd: region.loopDuration.getValue() / PPQN.Quarter,
155
+ enable: !region.mute.getValue(),
156
+ name: region.label.getValue(),
157
+ color: Color.hslToHex(region.hue.getValue(), 1.0, 0.60),
158
+ content: [Xml.element({
159
+ content: audioElement.mapOr(element => [element], []),
160
+ contentTimeUnit: "beats",
161
+ warps: [
162
+ Xml.element({
163
+ time: 0.0,
164
+ contentTime: 0.0
165
+ }, WarpSchema),
166
+ Xml.element({
167
+ time: duration,
168
+ contentTime: audioElement.mapOr(element => element.duration, 0)
169
+ }, WarpSchema)
170
+ ]
171
+ }, WarpsSchema)]
172
+ }, ClipSchema)]
173
+ }, ClipsSchema);
174
+ };
175
+ const writeNoteRegion = (region) => {
176
+ const collectionBox = asInstanceOf(region.events.targetVertex
177
+ .unwrap("No notes in region").box, NoteEventCollectionBox);
178
+ return Xml.element({
179
+ clips: [Xml.element({
180
+ time: region.position.getValue() / PPQN.Quarter,
181
+ duration: region.duration.getValue() / PPQN.Quarter,
182
+ contentTimeUnit: TimeUnit.BEATS,
183
+ playStart: 0.0,
184
+ loopStart: 0.0,
185
+ loopEnd: region.loopDuration.getValue() / PPQN.Quarter,
186
+ enable: !region.mute.getValue(),
187
+ name: region.label.getValue(),
188
+ color: Color.hslToHex(region.hue.getValue(), 1.0, 0.60),
189
+ content: [Xml.element({
190
+ notes: collectionBox.events.pointerHub.incoming()
191
+ .map(({ box }) => asInstanceOf(box, NoteEventBox))
192
+ .map(box => Xml.element({
193
+ time: box.position.getValue() / PPQN.Quarter,
194
+ duration: box.duration.getValue() / PPQN.Quarter,
195
+ key: box.pitch.getValue(),
196
+ channel: 0,
197
+ vel: box.velocity.getValue(),
198
+ rel: box.velocity.getValue()
199
+ }, NoteSchema))
200
+ }, NotesSchema)]
201
+ }, ClipSchema)]
202
+ }, ClipsSchema);
203
+ };
204
+ // TODO Implement!
205
+ const writeValueRegion = (region) => Xml.element({
206
+ clips: [Xml.element({
207
+ time: region.position.getValue() / PPQN.Quarter,
208
+ duration: region.duration.getValue() / PPQN.Quarter,
209
+ contentTimeUnit: TimeUnit.BEATS,
210
+ playStart: 0.0,
211
+ loopStart: 0.0,
212
+ loopEnd: region.loopDuration.getValue() / PPQN.Quarter,
213
+ enable: !region.mute.getValue(),
214
+ name: region.label.getValue(),
215
+ color: Color.hslToHex(region.hue.getValue(), 1.0, 0.60),
216
+ content: []
217
+ }, ClipSchema)]
218
+ }, ClipsSchema);
219
+ const writeLanes = () => {
220
+ return audioUnits
221
+ .flatMap(audioUnitBox => audioUnitBox.tracks.pointerHub.incoming()
222
+ .map(({ box }) => asInstanceOf(box, TrackBox))
223
+ .sort((a, b) => a.index.getValue() - b.index.getValue())
224
+ .map(trackBox => Xml.element({
225
+ id: ids.getOrCreate(trackBox.address),
226
+ track: ids.getOrCreate(audioUnitBox.address),
227
+ lanes: trackBox.regions.pointerHub.incoming()
228
+ .map(({ box }) => asDefined(box.accept({
229
+ visitAudioRegionBox: (region) => writeAudioRegion(region),
230
+ visitNoteRegionBox: (region) => writeNoteRegion(region),
231
+ visitValueRegionBox: (region) => writeValueRegion(region)
232
+ }), "Could not write region."))
233
+ }, LanesSchema)));
234
+ };
235
+ return Xml.element({
12
236
  version: "1.0",
13
237
  application: Xml.element({
14
238
  name: "openDAW",
15
239
  version: "0.1"
16
240
  }, ApplicationSchema),
17
- transport: Xml.element({
18
- tempo: Xml.element({
19
- value: timelineBox.bpm.getValue(),
20
- unit: Unit.BPM
21
- }, RealParameterSchema)
22
- }, TransportSchema),
23
- structure: [],
24
- arrangement: Xml.element({}, ArrangementSchema),
241
+ transport: writeTransport(),
242
+ structure: writeStructure(),
243
+ arrangement: Xml.element({
244
+ lanes: Xml.element({
245
+ lanes: writeLanes(),
246
+ timeUnit: TimeUnit.BEATS
247
+ }, LanesSchema)
248
+ }, ArrangementSchema),
25
249
  scenes: []
26
- }, ProjectSchema));
27
- return Xml.pretty(element);
28
- }
29
- }
250
+ }, ProjectSchema);
251
+ };
252
+ })(DawProjectExporter || (DawProjectExporter = {}));
@@ -2,15 +2,48 @@ import { describe, it } from "vitest";
2
2
  import { fileURLToPath } from "url";
3
3
  import * as path from "node:path";
4
4
  import * as fs from "node:fs";
5
- import { ProjectDecoder } from "@opendaw/studio-adapters";
6
- import { ProjectMigration } from "../ProjectMigration";
5
+ import { Project } from "../Project";
6
+ import { Option, panic, Terminable } from "@opendaw/lib-std";
7
+ import { Xml } from "@opendaw/lib-xml";
8
+ import { FileReferenceSchema } from "@opendaw/lib-dawproject";
7
9
  import { DawProjectExporter } from "./DawProjectExporter";
8
10
  describe("DawProjectExport", () => {
9
11
  it("export", async () => {
10
12
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
- const buffer = fs.readFileSync(path.join(__dirname, "../../../../../packages/app/studio/public/templates/Fatso.od"));
12
- const skeleton = ProjectDecoder.decode(buffer.buffer);
13
- ProjectMigration.migrate(skeleton);
14
- console.debug(DawProjectExporter.exportProject(skeleton).toProjectXml());
13
+ const projectPath = "../../../../../test-files/all-devices.od";
14
+ const buffer = fs.readFileSync(path.join(__dirname, projectPath));
15
+ const arrayBuffer = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
16
+ const project = Project.load({
17
+ sampleRate: 44100,
18
+ sampleManager: new class {
19
+ record(loader) {
20
+ throw new Error("Method not implemented.");
21
+ }
22
+ getOrCreate(format) {
23
+ return new class {
24
+ data = Option.None;
25
+ peaks = Option.None;
26
+ uuid = format;
27
+ state = { type: "progress", progress: 0.0 };
28
+ meta = Option.None;
29
+ invalidate() { throw new Error("Method not implemented."); }
30
+ subscribe(_observer) {
31
+ return Terminable.Empty;
32
+ }
33
+ };
34
+ }
35
+ invalidate(_uuid) {
36
+ return panic("Method not implemented.");
37
+ }
38
+ }
39
+ }, arrayBuffer);
40
+ const schema = DawProjectExporter.write(project, {
41
+ write: (path, buffer) => {
42
+ console.debug(`store ${buffer.byteLength} bytes at ${path}`);
43
+ return Xml.element({ path, external: false }, FileReferenceSchema);
44
+ }
45
+ });
46
+ // console.dir(schema, {depth: Number.MAX_SAFE_INTEGER})
47
+ console.debug(Xml.pretty(Xml.toElement("Project", schema)));
15
48
  });
16
49
  });
@@ -0,0 +1,12 @@
1
+ import { UUID } from "@opendaw/lib-std";
2
+ import { ProjectSchema } from "@opendaw/lib-dawproject";
3
+ import { ProjectDecoder } from "@opendaw/studio-adapters";
4
+ import { DawProject } from "./DawProject";
5
+ export declare namespace DawProjectImport {
6
+ type Result = {
7
+ audioIds: ReadonlyArray<UUID.Format>;
8
+ skeleton: ProjectDecoder.Skeleton;
9
+ };
10
+ const read: (schema: ProjectSchema, resources: DawProject.ResourceProvider) => Promise<Result>;
11
+ }
12
+ //# sourceMappingURL=DawProjectImport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DawProjectImport.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectImport.ts"],"names":[],"mappings":"AAAA,OAAO,EAgBH,IAAI,EAEP,MAAM,kBAAkB,CAAA;AAGzB,OAAO,EAcH,aAAa,EAOhB,MAAM,yBAAyB,CAAA;AAuBhC,OAAO,EAAyC,cAAc,EAAY,MAAM,0BAA0B,CAAA;AAC1G,OAAO,EAAC,UAAU,EAAC,MAAM,cAAc,CAAA;AAQvC,yBAAiB,gBAAgB,CAAC;IAW9B,KAAY,MAAM,GAAG;QACjB,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,QAAQ,EAAE,cAAc,CAAC,QAAQ,CAAA;KACpC,CAAA;IAOM,MAAM,IAAI,GAAU,QAAQ,aAAa,EAAE,WAAW,UAAU,CAAC,gBAAgB,KAAG,OAAO,CAAC,MAAM,CA6WxG,CAAA;CAaJ"}