@opendaw/studio-core 0.0.74 → 0.0.82
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CaptureMidi.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,UAAU,EACb,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAEnD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"CaptureMidi.d.ts","sourceRoot":"","sources":["../../src/capture/CaptureMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAOH,QAAQ,EACR,MAAM,EACN,YAAY,EACZ,UAAU,EACb,MAAM,kBAAkB,CAAA;AAIzB,OAAO,EAAC,YAAY,EAAE,cAAc,EAAC,MAAM,uBAAuB,CAAA;AAClE,OAAO,EAAC,UAAU,EAAC,MAAM,0BAA0B,CAAA;AAEnD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AACjC,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAA;AAG/C,qBAAa,WAAY,SAAQ,OAAO,CAAC,cAAc,CAAC;;gBAOxC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc;IA+B/F,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAEhC,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY;IAE5D,IAAI,KAAK,IAAI,MAAM,CAgBlB;IAED,IAAI,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAIhC;IAEK,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBvC,cAAc,IAAI,UAAU;CA6C/B"}
|
|
@@ -6,7 +6,6 @@ import { NoteSignal } from "@opendaw/studio-adapters";
|
|
|
6
6
|
import { MidiDevices } from "../midi";
|
|
7
7
|
import { Capture } from "./Capture";
|
|
8
8
|
import { RecordMidi } from "./RecordMidi";
|
|
9
|
-
var warn = Errors.warn;
|
|
10
9
|
export class CaptureMidi extends Capture {
|
|
11
10
|
#streamGenerator;
|
|
12
11
|
#notifier = new Notifier();
|
|
@@ -78,7 +77,7 @@ export class CaptureMidi extends Capture {
|
|
|
78
77
|
if (option.nonEmpty()) {
|
|
79
78
|
const deviceId = option.unwrap();
|
|
80
79
|
if (isUndefined(inputs.find(device => deviceId === device.id))) {
|
|
81
|
-
return warn(`Could not find MIDI device with id: '${deviceId}'`);
|
|
80
|
+
return Errors.warn(`Could not find MIDI device with id: '${deviceId}'`);
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,QAAQ,EAAuC,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGlH,OAAO,EAAa,UAAU,EAAY,MAAM,0BAA0B,CAAA;AAC1E,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;
|
|
1
|
+
{"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAO,QAAQ,EAAuC,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGlH,OAAO,EAAa,UAAU,EAAY,MAAM,0BAA0B,CAAA;AAC1E,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;IAID,MAAM,CAAC,MAAM,KAAK,GAAI,gCAA8B,iBAAiB,KAAG,UAuEvE,CAAA;;CACJ"}
|
|
@@ -1,24 +1,44 @@
|
|
|
1
|
-
import { Option, quantizeCeil,
|
|
1
|
+
import { Option, quantizeCeil, quantizeRound, Terminator, UUID } from "@opendaw/lib-std";
|
|
2
2
|
import { PPQN } from "@opendaw/lib-dsp";
|
|
3
3
|
import { NoteEventBox, NoteEventCollectionBox, NoteRegionBox } from "@opendaw/studio-boxes";
|
|
4
4
|
import { ColorCodes, NoteSignal, TrackType } from "@opendaw/studio-adapters";
|
|
5
5
|
import { RecordTrack } from "./RecordTrack";
|
|
6
6
|
export var RecordMidi;
|
|
7
7
|
(function (RecordMidi) {
|
|
8
|
+
const MIN_NOTE_DURATION = PPQN.fromSignature(1, 128);
|
|
8
9
|
RecordMidi.start = ({ notifier, project, capture }) => {
|
|
9
|
-
console.debug("RecordMidi.start");
|
|
10
10
|
const beats = PPQN.fromSignature(1, project.timelineBox.signature.denominator.getValue());
|
|
11
|
-
const { editing, boxGraph, engine } = project;
|
|
11
|
+
const { editing, boxGraph, engine, env: { audioContext }, timelineBox: { bpm } } = project;
|
|
12
12
|
const { position, isRecording } = engine;
|
|
13
13
|
const trackBox = RecordTrack.findOrCreate(editing, capture.audioUnitBox, TrackType.Notes);
|
|
14
14
|
const terminator = new Terminator();
|
|
15
15
|
const activeNotes = new Map();
|
|
16
|
+
const latency = PPQN.secondsToPulses(audioContext.outputLatency ?? 10.0, bpm.getValue());
|
|
16
17
|
let writing = Option.None;
|
|
18
|
+
const createRegion = () => {
|
|
19
|
+
const writePosition = position.getValue() + latency;
|
|
20
|
+
editing.modify(() => {
|
|
21
|
+
const collection = NoteEventCollectionBox.create(boxGraph, UUID.generate());
|
|
22
|
+
const region = NoteRegionBox.create(boxGraph, UUID.generate(), box => {
|
|
23
|
+
box.regions.refer(trackBox.regions);
|
|
24
|
+
box.events.refer(collection.owners);
|
|
25
|
+
box.position.setValue(Math.max(quantizeRound(writePosition, beats), 0));
|
|
26
|
+
box.hue.setValue(ColorCodes.forTrackType(TrackType.Notes));
|
|
27
|
+
});
|
|
28
|
+
engine.ignoreNoteRegion(region.address.uuid);
|
|
29
|
+
writing = Option.wrap({ region, collection });
|
|
30
|
+
}, false);
|
|
31
|
+
};
|
|
17
32
|
terminator.own(position.catchupAndSubscribe(owner => {
|
|
18
33
|
if (writing.isEmpty()) {
|
|
19
|
-
|
|
34
|
+
if (isRecording.getValue()) {
|
|
35
|
+
createRegion();
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
20
40
|
}
|
|
21
|
-
const writePosition = owner.getValue();
|
|
41
|
+
const writePosition = owner.getValue() + latency;
|
|
22
42
|
const { region, collection } = writing.unwrap();
|
|
23
43
|
editing.modify(() => {
|
|
24
44
|
if (region.isAttached() && collection.isAttached()) {
|
|
@@ -28,7 +48,7 @@ export var RecordMidi;
|
|
|
28
48
|
loopDuration.setValue(newDuration);
|
|
29
49
|
for (const event of activeNotes.values()) {
|
|
30
50
|
if (event.isAttached()) {
|
|
31
|
-
event.duration.setValue(writePosition - region.position.getValue() - event.position.getValue());
|
|
51
|
+
event.duration.setValue(Math.max(MIN_NOTE_DURATION, writePosition - region.position.getValue() - event.position.getValue()));
|
|
32
52
|
}
|
|
33
53
|
else {
|
|
34
54
|
activeNotes.delete(event.pitch.getValue());
|
|
@@ -42,30 +62,21 @@ export var RecordMidi;
|
|
|
42
62
|
}, false);
|
|
43
63
|
}));
|
|
44
64
|
terminator.ownAll(notifier.subscribe((signal) => {
|
|
45
|
-
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const ppqn = position.getValue();
|
|
65
|
+
const writePosition = position.getValue() + latency;
|
|
49
66
|
if (NoteSignal.isOn(signal)) {
|
|
50
67
|
const { pitch, velocity } = signal;
|
|
51
68
|
if (writing.isEmpty()) {
|
|
52
|
-
|
|
53
|
-
const collection = NoteEventCollectionBox.create(boxGraph, UUID.generate());
|
|
54
|
-
const region = NoteRegionBox.create(boxGraph, UUID.generate(), box => {
|
|
55
|
-
box.regions.refer(trackBox.regions);
|
|
56
|
-
box.events.refer(collection.owners);
|
|
57
|
-
box.position.setValue(quantizeFloor(ppqn, beats));
|
|
58
|
-
box.hue.setValue(ColorCodes.forTrackType(TrackType.Notes));
|
|
59
|
-
});
|
|
60
|
-
engine.ignoreNoteRegion(region.address.uuid);
|
|
61
|
-
writing = Option.wrap({ region, collection });
|
|
62
|
-
}, false);
|
|
69
|
+
createRegion();
|
|
63
70
|
}
|
|
64
71
|
const { region, collection } = writing.unwrap();
|
|
65
72
|
editing.modify(() => {
|
|
73
|
+
const position = writePosition - region.position.getValue();
|
|
74
|
+
if (position < -PPQN.SemiQuaver) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
66
77
|
activeNotes.set(pitch, NoteEventBox.create(boxGraph, UUID.generate(), box => {
|
|
67
|
-
box.position.setValue(
|
|
68
|
-
box.duration.setValue(
|
|
78
|
+
box.position.setValue(Math.max(0, position));
|
|
79
|
+
box.duration.setValue(MIN_NOTE_DURATION);
|
|
69
80
|
box.pitch.setValue(pitch);
|
|
70
81
|
box.velocity.setValue(velocity);
|
|
71
82
|
box.events.refer(collection.events);
|