@opendaw/studio-core 0.0.58 → 0.0.60
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/AudioOfflineRenderer.d.ts +2 -2
- package/dist/AudioOfflineRenderer.d.ts.map +1 -1
- package/dist/AudioOfflineRenderer.js +9 -9
- package/dist/AudioUtils.d.ts +4 -0
- package/dist/AudioUtils.d.ts.map +1 -0
- package/dist/AudioUtils.js +20 -0
- 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 +17 -3
- package/dist/Engine.d.ts +1 -1
- package/dist/Engine.d.ts.map +1 -1
- package/dist/EngineFacade.d.ts +1 -1
- package/dist/EngineFacade.d.ts.map +1 -1
- package/dist/EngineFacade.js +1 -1
- package/dist/EngineWorklet.d.ts.map +1 -1
- package/dist/EngineWorklet.js +7 -8
- package/dist/ExternalLib.d.ts +0 -1
- package/dist/ExternalLib.d.ts.map +1 -1
- package/dist/ExternalLib.js +0 -1
- package/dist/FilePickerAcceptTypes.d.ts.map +1 -1
- package/dist/Preferences.d.ts +4 -0
- package/dist/Preferences.d.ts.map +1 -1
- package/dist/Preferences.js +2 -0
- package/dist/RecordingWorklet.d.ts +2 -1
- package/dist/RecordingWorklet.d.ts.map +1 -1
- package/dist/WavFile.d.ts +4 -7
- package/dist/WavFile.d.ts.map +1 -1
- package/dist/WavFile.js +22 -21
- package/dist/Workers.d.ts +2 -0
- package/dist/Workers.d.ts.map +1 -1
- package/dist/Workers.js +11 -0
- package/dist/capture/CaptureAudio.d.ts.map +1 -1
- package/dist/capture/CaptureAudio.js +0 -2
- package/dist/capture/RecordAudio.d.ts.map +1 -1
- package/dist/capture/RecordAudio.js +3 -1
- package/dist/cloud/CloudBackupProjects.js +4 -4
- package/dist/cloud/CloudBackupSamples.d.ts.map +1 -1
- package/dist/cloud/CloudBackupSamples.js +3 -9
- package/dist/cloud/CloudBackupSoundfonts.js +1 -1
- package/dist/dawproject/DawProjectExporter.d.ts.map +1 -1
- package/dist/dawproject/DawProjectExporter.js +2 -12
- package/dist/dawproject/DawProjectImporter.d.ts.map +1 -1
- package/dist/dawproject/DawProjectImporter.js +5 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/midi/MIDIReceiver.d.ts +12 -0
- package/dist/midi/MIDIReceiver.d.ts.map +1 -0
- package/dist/midi/MIDIReceiver.js +65 -0
- package/dist/midi/MidiDevices.d.ts +4 -1
- package/dist/midi/MidiDevices.d.ts.map +1 -1
- package/dist/midi/MidiDevices.js +40 -1
- package/dist/processors.js +17 -19
- package/dist/processors.js.map +4 -4
- package/dist/project/Project.d.ts.map +1 -1
- package/dist/project/Project.js +14 -2
- package/dist/project/ProjectApi.d.ts +13 -4
- package/dist/project/ProjectApi.d.ts.map +1 -1
- package/dist/project/ProjectApi.js +71 -29
- package/dist/project/ProjectBundle.d.ts +2 -2
- package/dist/project/ProjectBundle.d.ts.map +1 -1
- package/dist/project/ProjectBundle.js +3 -3
- package/dist/project/ProjectMeta.d.ts +2 -0
- package/dist/project/ProjectMeta.d.ts.map +1 -1
- package/dist/project/ProjectMeta.js +1 -0
- package/dist/project/ProjectMigration.d.ts.map +1 -1
- package/dist/project/ProjectMigration.js +47 -5
- package/dist/project/ProjectProfile.d.ts +1 -0
- package/dist/project/ProjectProfile.d.ts.map +1 -1
- package/dist/project/ProjectProfile.js +5 -0
- package/dist/project/audio/AudioContentFactory.d.ts +34 -0
- package/dist/project/audio/AudioContentFactory.d.ts.map +1 -0
- package/dist/project/audio/AudioContentFactory.js +107 -0
- package/dist/project/audio/AudioContentHelpers.d.ts +7 -0
- package/dist/project/audio/AudioContentHelpers.d.ts.map +1 -0
- package/dist/project/audio/AudioContentHelpers.js +17 -0
- package/dist/project/audio/AudioContentModifier.d.ts +10 -0
- package/dist/project/audio/AudioContentModifier.d.ts.map +1 -0
- package/dist/project/audio/AudioContentModifier.js +129 -0
- package/dist/project/audio/AudioFileBoxFactory.d.ts +8 -0
- package/dist/project/audio/AudioFileBoxFactory.d.ts.map +1 -0
- package/dist/project/audio/AudioFileBoxFactory.js +36 -0
- package/dist/project/audio/index.d.ts +4 -0
- package/dist/project/audio/index.d.ts.map +1 -0
- package/dist/project/audio/index.js +3 -0
- package/dist/project/index.d.ts +1 -0
- package/dist/project/index.d.ts.map +1 -1
- package/dist/project/index.js +1 -0
- package/dist/samples/DefaultSampleLoader.d.ts +2 -1
- package/dist/samples/DefaultSampleLoader.d.ts.map +1 -1
- package/dist/samples/DefaultSampleLoader.js +1 -1
- package/dist/samples/DefaultSampleLoaderManager.d.ts +3 -1
- package/dist/samples/DefaultSampleLoaderManager.d.ts.map +1 -1
- package/dist/samples/DefaultSampleLoaderManager.js +13 -0
- package/dist/samples/OpenSampleAPI.d.ts +2 -1
- package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
- package/dist/samples/OpenSampleAPI.js +2 -2
- package/dist/samples/SampleAPI.d.ts +2 -1
- package/dist/samples/SampleAPI.d.ts.map +1 -1
- package/dist/samples/SampleProvider.d.ts +2 -1
- package/dist/samples/SampleProvider.d.ts.map +1 -1
- package/dist/samples/SampleService.d.ts.map +1 -1
- package/dist/samples/SampleStorage.d.ts +2 -1
- package/dist/samples/SampleStorage.d.ts.map +1 -1
- package/dist/samples/SampleStorage.js +6 -5
- package/dist/soundfont/OpenSoundfontAPI.d.ts.map +1 -1
- package/dist/soundfont/OpenSoundfontAPI.js +3 -3
- package/dist/workers-main.js +1 -5
- package/dist/workers-main.js.map +4 -4
- package/package.json +15 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudBackupSamples.d.ts","sourceRoot":"","sources":["../../src/cloud/CloudBackupSamples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,SAAS,EAAE,QAAQ,EAAmB,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGlG,OAAO,
|
|
1
|
+
{"version":3,"file":"CloudBackupSamples.d.ts","sourceRoot":"","sources":["../../src/cloud/CloudBackupSamples.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,SAAS,EAAE,QAAQ,EAAmB,IAAI,EAAC,MAAM,kBAAkB,CAAA;AAGlG,OAAO,EAAC,MAAM,EAAC,MAAM,0BAA0B,CAAA;AAE/C,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAA;AAM3C,qBAAa,kBAAkB;;IAC3B,MAAM,CAAC,QAAQ,CAAC,UAAU,aAAY;IACtC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,SAAkC;IACnE,MAAM,CAAC,QAAQ,CAAC,eAAe,GAAI,aAAW,MAAM,EAAE,aAAW,MAAM,aAAY;IAEnF,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,MAAM;WAE5B,KAAK,CAAC,YAAY,EAAE,YAAY,EAC1B,QAAQ,EAAE,QAAQ,CAAC,OAAO,EAC1B,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC;IAgBzC,OAAO;CAoHV"}
|
|
@@ -48,7 +48,7 @@ export class CloudBackupSamples {
|
|
|
48
48
|
progress((index + 1) / length);
|
|
49
49
|
this.#log(`Uploading sample '${sample.name}'`);
|
|
50
50
|
const arrayBuffer = await SampleStorage.get().load(UUID.parse(sample.uuid))
|
|
51
|
-
.then(([
|
|
51
|
+
.then(([data]) => WavFile.encodeFloats(data));
|
|
52
52
|
const path = CloudBackupSamples.pathFor(sample.uuid);
|
|
53
53
|
await Promises.approvedRetry(() => this.#cloudHandler.upload(path, arrayBuffer), error => ({
|
|
54
54
|
headline: "Upload failed",
|
|
@@ -103,14 +103,8 @@ export class CloudBackupSamples {
|
|
|
103
103
|
progress((index + 1) / length);
|
|
104
104
|
this.#log(`Downloading sample '${sample.name}'`);
|
|
105
105
|
const path = CloudBackupSamples.pathFor(sample.uuid);
|
|
106
|
-
const buffer = await Promises.guardedRetry(() => this.#cloudHandler.download(path), network.
|
|
107
|
-
const
|
|
108
|
-
const audioData = {
|
|
109
|
-
sampleRate: waveAudio.sampleRate,
|
|
110
|
-
numberOfFrames: waveAudio.numFrames,
|
|
111
|
-
numberOfChannels: waveAudio.channels.length,
|
|
112
|
-
frames: waveAudio.channels
|
|
113
|
-
};
|
|
106
|
+
const buffer = await Promises.guardedRetry(() => this.#cloudHandler.download(path), network.defaultRetry);
|
|
107
|
+
const audioData = WavFile.decodeFloats(buffer);
|
|
114
108
|
const shifts = SamplePeaks.findBestFit(audioData.numberOfFrames);
|
|
115
109
|
const peaks = await Workers.Peak.generateAsync(Progress.Empty, shifts, audioData.frames, audioData.numberOfFrames, audioData.numberOfChannels);
|
|
116
110
|
await SampleStorage.get().save({
|
|
@@ -100,7 +100,7 @@ export class CloudBackupSoundfonts {
|
|
|
100
100
|
progress((index + 1) / length);
|
|
101
101
|
this.#log(`Downloading soundfont '${soundfont.name}'`);
|
|
102
102
|
const path = CloudBackupSoundfonts.pathFor(soundfont.uuid);
|
|
103
|
-
const buffer = await Promises.guardedRetry(() => this.#cloudHandler.download(path), network.
|
|
103
|
+
const buffer = await Promises.guardedRetry(() => this.#cloudHandler.download(path), network.defaultRetry);
|
|
104
104
|
await SoundfontStorage.get().save({
|
|
105
105
|
uuid: UUID.parse(soundfont.uuid),
|
|
106
106
|
file: buffer,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DawProjectExporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectExporter.ts"],"names":[],"mappings":"AAKA,OAAO,EAaH,mBAAmB,EAKnB,aAAa,EAUhB,MAAM,yBAAyB,CAAA;AAahC,OAAO,EAA6B,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAA;AAKzG,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,
|
|
1
|
+
{"version":3,"file":"DawProjectExporter.d.ts","sourceRoot":"","sources":["../../src/dawproject/DawProjectExporter.ts"],"names":[],"mappings":"AAKA,OAAO,EAaH,mBAAmB,EAKnB,aAAa,EAUhB,MAAM,yBAAyB,CAAA;AAahC,OAAO,EAA6B,eAAe,EAAE,mBAAmB,EAAC,MAAM,0BAA0B,CAAA;AAKzG,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,kBAoPlH,CAAA;CACJ"}
|
|
@@ -20,13 +20,7 @@ export var DawProjectExporter;
|
|
|
20
20
|
.sort((a, b) => a.index.getValue() - b.index.getValue());
|
|
21
21
|
boxGraph.boxes().forEach(box => box.accept({
|
|
22
22
|
visitAudioFileBox: (box) => sampleManager.getOrCreate(box.address.uuid).data
|
|
23
|
-
.ifSome((
|
|
24
|
-
channels: frames,
|
|
25
|
-
duration: numberOfFrames * sampleRate,
|
|
26
|
-
numberOfChannels,
|
|
27
|
-
sampleRate,
|
|
28
|
-
numFrames: numberOfFrames
|
|
29
|
-
})))
|
|
23
|
+
.ifSome((data) => resourcePacker.write(`samples/${box.fileName.getValue()}.wav`, WavFile.encodeFloats(data)))
|
|
30
24
|
}));
|
|
31
25
|
const writeTransport = () => Xml.element({
|
|
32
26
|
tempo: Xml.element({
|
|
@@ -63,11 +57,7 @@ export var DawProjectExporter;
|
|
|
63
57
|
}, BuiltinDeviceSchema);
|
|
64
58
|
});
|
|
65
59
|
const colorForAudioType = (unitType) => {
|
|
66
|
-
const
|
|
67
|
-
if (cssColor === "") {
|
|
68
|
-
return "red";
|
|
69
|
-
}
|
|
70
|
-
const [r, g, b] = Html.readCssVarColor(ColorCodes.forAudioType(unitType))[0];
|
|
60
|
+
const [r, g, b] = Html.readCssVarColor(ColorCodes.forAudioType(unitType).toString())[0];
|
|
71
61
|
const RR = Math.round(r * 255).toString(16).padStart(2, "0");
|
|
72
62
|
const GG = Math.round(g * 255).toString(16).padStart(2, "0");
|
|
73
63
|
const BB = Math.round(b * 255).toString(16).padStart(2, "0");
|
|
@@ -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,EAOhB,MAAM,yBAAyB,CAAA;
|
|
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,EAOhB,MAAM,yBAAyB,CAAA;AAwBhC,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,CA6XxG,CAAA;CAaJ"}
|
|
@@ -3,8 +3,8 @@ import { BoxGraph } from "@opendaw/lib-box";
|
|
|
3
3
|
import { gainToDb, PPQN } from "@opendaw/lib-dsp";
|
|
4
4
|
import { ChannelRole, ClipsSchema, DeviceRole, EqualizerSchema, LanesSchema, NotesSchema, PointsSchema, SendType, TrackSchema, WarpsSchema } from "@opendaw/lib-dawproject";
|
|
5
5
|
import { AudioSendRouting, AudioUnitType, IconSymbol } from "@opendaw/studio-enums";
|
|
6
|
-
import { AudioBusBox, AudioFileBox, AudioRegionBox, AudioUnitBox, AuxSendBox, BoxIO, CaptureAudioBox, CaptureMidiBox, GrooveShuffleBox, NoteEventBox, NoteEventCollectionBox, NoteRegionBox, RootBox, TimelineBox, TrackBox, UnknownAudioEffectDeviceBox, UnknownMidiEffectDeviceBox, UserInterfaceBox } from "@opendaw/studio-boxes";
|
|
7
|
-
import { AudioUnitOrdering, DeviceBoxUtils, InstrumentFactories,
|
|
6
|
+
import { AudioBusBox, AudioFileBox, 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, DeviceBoxUtils, InstrumentFactories, TrackType } from "@opendaw/studio-adapters";
|
|
8
8
|
import { DeviceIO } from "./DeviceIO";
|
|
9
9
|
import { BuiltinDevices } from "./BuiltinDevices";
|
|
10
10
|
export var DawProjectImport;
|
|
@@ -169,7 +169,7 @@ export var DawProjectImport;
|
|
|
169
169
|
box.collection.refer(rootBox.audioBusses);
|
|
170
170
|
box.label.setValue(track.name ?? "");
|
|
171
171
|
box.icon.setValue(IconSymbol.toName(icon));
|
|
172
|
-
box.color.setValue(ColorCodes.forAudioType(type));
|
|
172
|
+
box.color.setValue(ColorCodes.forAudioType(type).toString());
|
|
173
173
|
box.enabled.setValue(true);
|
|
174
174
|
box.output.refer(audioUnitBox.input);
|
|
175
175
|
});
|
|
@@ -319,6 +319,7 @@ export var DawProjectImport;
|
|
|
319
319
|
box.endInSeconds.setValue(asDefined(audio.duration, "Duration not defined"));
|
|
320
320
|
}));
|
|
321
321
|
audioIdSet.add(uuid, true);
|
|
322
|
+
const collectionBox = ValueEventCollectionBox.create(boxGraph, UUID.generate());
|
|
322
323
|
AudioRegionBox.create(boxGraph, UUID.generate(), box => {
|
|
323
324
|
const position = asDefined(clip.time, "Time not defined");
|
|
324
325
|
const duration = asDefined(clip.duration, "Duration not defined");
|
|
@@ -331,6 +332,7 @@ export var DawProjectImport;
|
|
|
331
332
|
box.mute.setValue(clip.enable === false);
|
|
332
333
|
box.regions.refer(trackBox.regions);
|
|
333
334
|
box.file.refer(audioFileBox);
|
|
335
|
+
box.events.refer(collectionBox.owners);
|
|
334
336
|
});
|
|
335
337
|
};
|
|
336
338
|
return Promise.all(arrangement?.lanes?.lanes?.filter(timeline => isInstanceOf(timeline, LanesSchema))
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./ui";
|
|
|
11
11
|
export * from "./ysync";
|
|
12
12
|
export * from "./AudioDevices";
|
|
13
13
|
export * from "./AudioOfflineRenderer";
|
|
14
|
+
export * from "./AudioUtils";
|
|
14
15
|
export * from "./EffectBox";
|
|
15
16
|
export * from "./EffectFactory";
|
|
16
17
|
export * from "./EffectFactories";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,mBAAmB,UAAU,CAAA;AAC7B,cAAc,QAAQ,CAAA;AACtB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,MAAM,CAAA;AACpB,cAAc,SAAS,CAAA;AAEvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,wBAAwB,CAAA;AACtC,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAA;AACzB,cAAc,SAAS,CAAA;AACvB,cAAc,cAAc,CAAA;AAC5B,mBAAmB,UAAU,CAAA;AAC7B,cAAc,QAAQ,CAAA;AACtB,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,MAAM,CAAA;AACpB,cAAc,SAAS,CAAA;AAEvB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,wBAAwB,CAAA;AACtC,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,mBAAmB,CAAA;AACjC,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,eAAe,CAAA;AAC7B,cAAc,yBAAyB,CAAA;AACvC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,WAAW,CAAA;AACzB,cAAc,WAAW,CAAA;AACzB,cAAc,iBAAiB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./ui";
|
|
|
10
10
|
export * from "./ysync";
|
|
11
11
|
export * from "./AudioDevices";
|
|
12
12
|
export * from "./AudioOfflineRenderer";
|
|
13
|
+
export * from "./AudioUtils";
|
|
13
14
|
export * from "./EffectBox";
|
|
14
15
|
export * from "./EffectFactory";
|
|
15
16
|
export * from "./EffectFactories";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { int, Terminable } from "@opendaw/lib-std";
|
|
2
|
+
type MIDIMessageCallback = (deviceId: string, data: Uint8Array, timeMs: int) => void;
|
|
3
|
+
export declare class MIDIReceiver implements Terminable {
|
|
4
|
+
#private;
|
|
5
|
+
static create(context: BaseAudioContext, callback: MIDIMessageCallback): MIDIReceiver;
|
|
6
|
+
private constructor();
|
|
7
|
+
get sab(): SharedArrayBuffer;
|
|
8
|
+
get port(): MessagePort;
|
|
9
|
+
terminate(): void;
|
|
10
|
+
}
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=MIDIReceiver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MIDIReceiver.d.ts","sourceRoot":"","sources":["../../src/midi/MIDIReceiver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAEhD,KAAK,mBAAmB,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAA;AAEpF,qBAAa,YAAa,YAAW,UAAU;;IAC3C,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,mBAAmB,GAAG,YAAY;IAsBrF,OAAO;IAgBP,IAAI,GAAG,IAAI,iBAAiB,CAAmB;IAC/C,IAAI,IAAI,IAAI,WAAW,CAA6B;IAEpD,SAAS,IAAI,IAAI;CAwBpB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export class MIDIReceiver {
|
|
2
|
+
static create(context, callback) {
|
|
3
|
+
const MIDI_RING_SIZE = 2048;
|
|
4
|
+
const sab = new SharedArrayBuffer(MIDI_RING_SIZE * 2 * 4 + 8);
|
|
5
|
+
const channel = new MessageChannel();
|
|
6
|
+
const hasOutputLatency = context instanceof AudioContext;
|
|
7
|
+
return new MIDIReceiver(sab, channel, (deviceId, data, relativeTimeInMs) => {
|
|
8
|
+
let delay = 20.0; // default 20ms
|
|
9
|
+
if (hasOutputLatency) {
|
|
10
|
+
delay = context.outputLatency / 1000.0;
|
|
11
|
+
}
|
|
12
|
+
callback(deviceId, data, relativeTimeInMs + delay);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
#sab;
|
|
16
|
+
#channel;
|
|
17
|
+
#indices;
|
|
18
|
+
#ring;
|
|
19
|
+
#messageMask;
|
|
20
|
+
#onMessage;
|
|
21
|
+
#deviceIds = new Map();
|
|
22
|
+
constructor(sab, channel, onMessage) {
|
|
23
|
+
this.#sab = sab;
|
|
24
|
+
this.#channel = channel;
|
|
25
|
+
this.#indices = new Uint32Array(sab, 0, 2);
|
|
26
|
+
this.#ring = new Uint32Array(sab, 8);
|
|
27
|
+
this.#messageMask = (this.#ring.length >> 1) - 1;
|
|
28
|
+
this.#onMessage = onMessage;
|
|
29
|
+
this.#channel.port1.onmessage = (event) => {
|
|
30
|
+
if (event.data?.registerDevice) {
|
|
31
|
+
this.#deviceIds.set(event.data.id, event.data.registerDevice);
|
|
32
|
+
}
|
|
33
|
+
this.#read();
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
get sab() { return this.#sab; }
|
|
37
|
+
get port() { return this.#channel.port2; }
|
|
38
|
+
terminate() { this.#channel.port1.close(); }
|
|
39
|
+
#read() {
|
|
40
|
+
let readIdx = Atomics.load(this.#indices, 1);
|
|
41
|
+
const writeIdx = Atomics.load(this.#indices, 0);
|
|
42
|
+
while (readIdx !== writeIdx) {
|
|
43
|
+
const offset = readIdx << 1;
|
|
44
|
+
const packed1 = this.#ring[offset];
|
|
45
|
+
const packed2 = this.#ring[offset + 1];
|
|
46
|
+
const length = packed1 >>> 30;
|
|
47
|
+
const deviceIdNum = (packed1 >>> 24) & 0x3F;
|
|
48
|
+
const status = (packed1 >>> 16) & 0xFF;
|
|
49
|
+
const data1 = (packed1 >>> 8) & 0xFF;
|
|
50
|
+
const data2 = packed1 & 0xFF;
|
|
51
|
+
const deviceId = this.#deviceIds.get(deviceIdNum) ?? "";
|
|
52
|
+
const data = new Uint8Array(length);
|
|
53
|
+
data[0] = status;
|
|
54
|
+
if (length > 1) {
|
|
55
|
+
data[1] = data1;
|
|
56
|
+
}
|
|
57
|
+
if (length > 2) {
|
|
58
|
+
data[2] = data2;
|
|
59
|
+
}
|
|
60
|
+
this.#onMessage(deviceId, data, packed2);
|
|
61
|
+
readIdx = (readIdx + 1) & this.#messageMask;
|
|
62
|
+
}
|
|
63
|
+
Atomics.store(this.#indices, 1, readIdx);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { byte, MutableObservableValue, ObservableOption, Observer, Option, Subscription } from "@opendaw/lib-std";
|
|
1
|
+
import { byte, MutableObservableValue, ObservableOption, Observer, Option, Procedure, Subscription } from "@opendaw/lib-std";
|
|
2
2
|
import { SoftwareMIDIInput } from "./SoftwareMIDIInput";
|
|
3
3
|
export declare class MidiDevices {
|
|
4
4
|
#private;
|
|
5
5
|
static canRequestMidiAccess(): boolean;
|
|
6
6
|
static readonly softwareMIDIInput: SoftwareMIDIInput;
|
|
7
|
+
static createSoftwareMIDIOutput(procedure: Procedure<Uint8Array>, name: string, id?: string): MIDIOutput;
|
|
7
8
|
static requestPermission(): Promise<undefined>;
|
|
8
9
|
static get(): ObservableOption<MIDIAccess>;
|
|
9
10
|
static subscribeMessageEvents(observer: Observer<MIDIMessageEvent>, channel?: byte): Subscription;
|
|
10
11
|
static inputDevices(): ReadonlyArray<MIDIInput>;
|
|
12
|
+
static outputDevices(): ReadonlyArray<MIDIOutput>;
|
|
11
13
|
static findInputDeviceById(id: string): Option<MIDIInput>;
|
|
14
|
+
static findOutputDeviceById(id: string): Option<MIDIOutput>;
|
|
12
15
|
static externalInputDevices(): Option<ReadonlyArray<MIDIInput>>;
|
|
13
16
|
static externalOutputDevices(): Option<ReadonlyArray<MIDIOutput>>;
|
|
14
17
|
static panic(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MidiDevices.d.ts","sourceRoot":"","sources":["../../src/midi/MidiDevices.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,IAAI,EAIJ,sBAAsB,EAEtB,gBAAgB,EAEhB,QAAQ,EACR,MAAM,
|
|
1
|
+
{"version":3,"file":"MidiDevices.d.ts","sourceRoot":"","sources":["../../src/midi/MidiDevices.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,IAAI,EAIJ,sBAAsB,EAEtB,gBAAgB,EAEhB,QAAQ,EACR,MAAM,EAEN,SAAS,EACT,YAAY,EAGf,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAC,iBAAiB,EAAC,MAAM,qBAAqB,CAAA;AAErD,qBAAa,WAAW;;IACpB,MAAM,CAAC,oBAAoB,IAAI,OAAO;IAEtC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,CAA0B;IAI9E,MAAM,CAAC,wBAAwB,CAAC,SAAS,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU;WAgC3F,iBAAiB;IAiB9B,MAAM,CAAC,GAAG,IAAI,gBAAgB,CAAC,UAAU,CAAC;IAE1C,MAAM,CAAC,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,EAAE,IAAI,GAAG,YAAY;IAWjG,MAAM,CAAC,YAAY,IAAI,aAAa,CAAC,SAAS,CAAC;IAK/C,MAAM,CAAC,aAAa,IAAI,aAAa,CAAC,UAAU,CAAC;IAMjD,MAAM,CAAC,mBAAmB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,SAAS,CAAC;IAIzD,MAAM,CAAC,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;IAI3D,MAAM,CAAC,oBAAoB,IAAI,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IAI/D,MAAM,CAAC,qBAAqB,IAAI,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;IAIjE,MAAM,CAAC,KAAK,IAAI,IAAI;IAkBpB,MAAM,CAAC,SAAS,IAAI,sBAAsB,CAAC,OAAO,CAAC;CAqCtD"}
|
package/dist/midi/MidiDevices.js
CHANGED
|
@@ -7,7 +7,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import { Errors, Lazy, MutableObservableOption, MutableObservableValue, Notifier, Option, Terminator } from "@opendaw/lib-std";
|
|
10
|
+
import { Errors, Lazy, MutableObservableOption, MutableObservableValue, Notifier, Option, panic, Terminator, UUID } from "@opendaw/lib-std";
|
|
11
11
|
import { MidiData } from "@opendaw/lib-midi";
|
|
12
12
|
import { Promises } from "@opendaw/lib-runtime";
|
|
13
13
|
import { MIDIMessageSubscriber } from "./MIDIMessageSubscriber";
|
|
@@ -15,6 +15,37 @@ import { SoftwareMIDIInput } from "./SoftwareMIDIInput";
|
|
|
15
15
|
export class MidiDevices {
|
|
16
16
|
static canRequestMidiAccess() { return "requestMIDIAccess" in navigator; }
|
|
17
17
|
static softwareMIDIInput = new SoftwareMIDIInput();
|
|
18
|
+
static #softwareMIDIOutputs = new Map();
|
|
19
|
+
static createSoftwareMIDIOutput(procedure, name, id) {
|
|
20
|
+
const output = new class {
|
|
21
|
+
id = id ?? UUID.toString(UUID.generate());
|
|
22
|
+
name = name;
|
|
23
|
+
manufacturer = null;
|
|
24
|
+
state = "connected";
|
|
25
|
+
connection = "open";
|
|
26
|
+
type = "output";
|
|
27
|
+
version = null;
|
|
28
|
+
send(data, _timestamp) {
|
|
29
|
+
if (data instanceof Uint8Array) {
|
|
30
|
+
procedure(data);
|
|
31
|
+
}
|
|
32
|
+
else if (Array.isArray(data) && data.every(value => typeof value === "number")) {
|
|
33
|
+
procedure(new Uint8Array(data));
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
return panic("MIDI output data must be an array of numbers or a Uint8Array");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
addEventListener(_type, _listener, _options) { }
|
|
40
|
+
removeEventListener(_type, _listener, _options) { }
|
|
41
|
+
close() { return Promise.resolve(this); }
|
|
42
|
+
open() { return Promise.resolve(this); }
|
|
43
|
+
dispatchEvent(_event) { return false; }
|
|
44
|
+
onstatechange = null;
|
|
45
|
+
};
|
|
46
|
+
MidiDevices.#softwareMIDIOutputs.set(output.id, output);
|
|
47
|
+
return output;
|
|
48
|
+
}
|
|
18
49
|
static #memoizedRequest = Promises.memoizeAsync(() => navigator.requestMIDIAccess({ sysex: false }));
|
|
19
50
|
static async requestPermission() {
|
|
20
51
|
if (this.canRequestMidiAccess()) {
|
|
@@ -47,9 +78,17 @@ export class MidiDevices {
|
|
|
47
78
|
return this.externalInputDevices()
|
|
48
79
|
.mapOr((inputs) => Array.from(inputs.values()).concat(this.softwareMIDIInput), [this.softwareMIDIInput]);
|
|
49
80
|
}
|
|
81
|
+
static outputDevices() {
|
|
82
|
+
const softwareOutputs = Array.from(this.#softwareMIDIOutputs.values());
|
|
83
|
+
return this.externalOutputDevices()
|
|
84
|
+
.mapOr((inputs) => Array.from(inputs.values()).concat(...softwareOutputs), softwareOutputs);
|
|
85
|
+
}
|
|
50
86
|
static findInputDeviceById(id) {
|
|
51
87
|
return Option.wrap(this.inputDevices().find(input => input.id === id));
|
|
52
88
|
}
|
|
89
|
+
static findOutputDeviceById(id) {
|
|
90
|
+
return Option.wrap(this.outputDevices().find(output => output.id === id));
|
|
91
|
+
}
|
|
53
92
|
static externalInputDevices() {
|
|
54
93
|
return this.get().map(({ inputs }) => Array.from(inputs.values()));
|
|
55
94
|
}
|