@opendaw/studio-core 0.0.91 → 0.0.93

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/AudioDevices.d.ts +2 -0
  2. package/dist/AudioDevices.d.ts.map +1 -1
  3. package/dist/AudioDevices.js +3 -0
  4. package/dist/AudioOfflineRenderer.d.ts +2 -0
  5. package/dist/AudioOfflineRenderer.d.ts.map +1 -1
  6. package/dist/AudioOfflineRenderer.js +2 -1
  7. package/dist/Engine.d.ts +2 -1
  8. package/dist/Engine.d.ts.map +1 -1
  9. package/dist/EngineFacade.d.ts +2 -1
  10. package/dist/EngineFacade.d.ts.map +1 -1
  11. package/dist/EngineFacade.js +3 -0
  12. package/dist/EngineWorklet.d.ts +2 -1
  13. package/dist/EngineWorklet.d.ts.map +1 -1
  14. package/dist/EngineWorklet.js +8 -2
  15. package/dist/OfflineEngineRenderer.d.ts +16 -5
  16. package/dist/OfflineEngineRenderer.d.ts.map +1 -1
  17. package/dist/OfflineEngineRenderer.js +85 -38
  18. package/dist/OpenDAWHeaders.d.ts.map +1 -1
  19. package/dist/OpenDAWHeaders.js +1 -2
  20. package/dist/RecordingWorklet.d.ts.map +1 -1
  21. package/dist/RecordingWorklet.js +0 -1
  22. package/dist/StudioPreferences.d.ts +22 -12
  23. package/dist/StudioPreferences.d.ts.map +1 -1
  24. package/dist/StudioSettings.d.ts +22 -12
  25. package/dist/StudioSettings.d.ts.map +1 -1
  26. package/dist/StudioSettings.js +41 -12
  27. package/dist/WavFile.d.ts.map +1 -1
  28. package/dist/WavFile.js +33 -9
  29. package/dist/capture/CaptureAudio.js +4 -4
  30. package/dist/capture/RecordAudio.d.ts.map +1 -1
  31. package/dist/capture/RecordAudio.js +49 -12
  32. package/dist/capture/RecordMidi.d.ts.map +1 -1
  33. package/dist/capture/RecordMidi.js +44 -8
  34. package/dist/capture/Recording.d.ts +2 -0
  35. package/dist/capture/Recording.d.ts.map +1 -1
  36. package/dist/capture/Recording.js +6 -2
  37. package/dist/midi/MIDIReceiver.d.ts +2 -2
  38. package/dist/midi/MIDIReceiver.d.ts.map +1 -1
  39. package/dist/midi/MIDIReceiver.js +2 -7
  40. package/dist/midi/index.d.ts +1 -0
  41. package/dist/midi/index.d.ts.map +1 -1
  42. package/dist/midi/index.js +1 -0
  43. package/dist/offline-engine.js +1 -1
  44. package/dist/offline-engine.js.map +3 -3
  45. package/dist/processors.js +15 -15
  46. package/dist/processors.js.map +4 -4
  47. package/dist/project/Project.d.ts +2 -1
  48. package/dist/project/Project.d.ts.map +1 -1
  49. package/dist/project/Project.js +18 -3
  50. package/dist/project/ProjectMigration.d.ts.map +1 -1
  51. package/dist/project/ProjectMigration.js +18 -251
  52. package/dist/project/migration/MigrateAudioClipBox.d.ts +4 -0
  53. package/dist/project/migration/MigrateAudioClipBox.d.ts.map +1 -0
  54. package/dist/project/migration/MigrateAudioClipBox.js +32 -0
  55. package/dist/project/migration/MigrateAudioFileBox.d.ts +5 -0
  56. package/dist/project/migration/MigrateAudioFileBox.d.ts.map +1 -0
  57. package/dist/project/migration/MigrateAudioFileBox.js +13 -0
  58. package/dist/project/migration/MigrateAudioRegionBox.d.ts +4 -0
  59. package/dist/project/migration/MigrateAudioRegionBox.d.ts.map +1 -0
  60. package/dist/project/migration/MigrateAudioRegionBox.js +54 -0
  61. package/dist/project/migration/MigrateAudioUnitBox.d.ts +4 -0
  62. package/dist/project/migration/MigrateAudioUnitBox.d.ts.map +1 -0
  63. package/dist/project/migration/MigrateAudioUnitBox.js +19 -0
  64. package/dist/project/migration/MigrateDelayDeviceBox.d.ts +4 -0
  65. package/dist/project/migration/MigrateDelayDeviceBox.d.ts.map +1 -0
  66. package/dist/project/migration/MigrateDelayDeviceBox.js +36 -0
  67. package/dist/project/migration/MigrateMIDIOutputDeviceBox.d.ts +4 -0
  68. package/dist/project/migration/MigrateMIDIOutputDeviceBox.d.ts.map +1 -0
  69. package/dist/project/migration/MigrateMIDIOutputDeviceBox.js +20 -0
  70. package/dist/project/migration/MigrateRevampDeviceBox.d.ts +4 -0
  71. package/dist/project/migration/MigrateRevampDeviceBox.d.ts.map +1 -0
  72. package/dist/project/migration/MigrateRevampDeviceBox.js +7 -0
  73. package/dist/project/migration/MigrateTimelineBox.d.ts +4 -0
  74. package/dist/project/migration/MigrateTimelineBox.d.ts.map +1 -0
  75. package/dist/project/migration/MigrateTimelineBox.js +10 -0
  76. package/dist/project/migration/MigrateValueEventBox.d.ts +4 -0
  77. package/dist/project/migration/MigrateValueEventBox.d.ts.map +1 -0
  78. package/dist/project/migration/MigrateValueEventBox.js +32 -0
  79. package/dist/project/migration/MigrateValueEventCollection.d.ts +4 -0
  80. package/dist/project/migration/MigrateValueEventCollection.d.ts.map +1 -0
  81. package/dist/project/migration/MigrateValueEventCollection.js +59 -0
  82. package/dist/project/migration/MigrateValueEventCollection.test.d.ts +2 -0
  83. package/dist/project/migration/MigrateValueEventCollection.test.d.ts.map +1 -0
  84. package/dist/project/migration/MigrateValueEventCollection.test.js +199 -0
  85. package/dist/project/migration/MigrateVaporisateurDeviceBox.d.ts +4 -0
  86. package/dist/project/migration/MigrateVaporisateurDeviceBox.d.ts.map +1 -0
  87. package/dist/project/migration/MigrateVaporisateurDeviceBox.js +28 -0
  88. package/dist/project/migration/MigrateZeitgeistDeviceBox.d.ts +4 -0
  89. package/dist/project/migration/MigrateZeitgeistDeviceBox.d.ts.map +1 -0
  90. package/dist/project/migration/MigrateZeitgeistDeviceBox.js +8 -0
  91. package/dist/project/migration/index.d.ts +13 -0
  92. package/dist/project/migration/index.d.ts.map +1 -0
  93. package/dist/project/migration/index.js +12 -0
  94. package/dist/samples/OpenSampleAPI.d.ts.map +1 -1
  95. package/dist/samples/OpenSampleAPI.js +3 -0
  96. package/dist/ui/generic/ClipboardManager.js +1 -1
  97. package/dist/ui/generic/ContextMenu.d.ts +1 -1
  98. package/dist/ui/generic/ContextMenu.js +1 -1
  99. package/dist/ui/generic/{menu-item.d.ts → MenuItems.d.ts} +1 -1
  100. package/dist/ui/generic/{menu-item.d.ts.map → MenuItems.d.ts.map} +1 -1
  101. package/dist/ui/index.d.ts +1 -1
  102. package/dist/ui/index.js +1 -1
  103. package/dist/workers-main.js +1 -1
  104. package/dist/workers-main.js.map +3 -3
  105. package/dist/ysync/YMapper.d.ts.map +1 -1
  106. package/dist/ysync/YMapper.js +7 -3
  107. package/package.json +15 -15
  108. /package/dist/ui/generic/{menu-item.js → MenuItems.js} +0 -0
package/dist/WavFile.js CHANGED
@@ -30,25 +30,49 @@ export var WavFile;
30
30
  if (fmtOffset < 0 || dataOffset < 0) {
31
31
  return panic("Missing fmt or data chunk");
32
32
  }
33
- const audioFormat = view.getUint16(fmtOffset, true); // 3 = IEEE float
33
+ const audioFormat = view.getUint16(fmtOffset, true); // 1 = PCM, 3 = IEEE float
34
34
  const numberOfChannels = view.getUint16(fmtOffset + 2, true);
35
35
  const sampleRate = view.getUint32(fmtOffset + 4, true);
36
36
  const blockAlign = view.getUint16(fmtOffset + 12, true);
37
37
  const bitsPerSample = view.getUint16(fmtOffset + 14, true);
38
- if (audioFormat !== 3 || bitsPerSample !== 32) {
39
- return panic("Expected 32-bit float WAV (format 3)");
40
- }
41
- if (blockAlign !== numberOfChannels * 4) {
38
+ const bytesPerSample = bitsPerSample / 8;
39
+ if (blockAlign !== numberOfChannels * bytesPerSample) {
42
40
  return panic("Invalid block alignment");
43
41
  }
44
42
  const numberOfFrames = Math.floor(dataSize / blockAlign);
45
- const interleaved = new Float32Array(buffer, dataOffset, numberOfFrames * numberOfChannels);
46
43
  const audioData = AudioData.create(sampleRate, numberOfFrames, numberOfChannels);
47
- for (let i = 0, w = 0; i < numberOfFrames; i++) {
48
- for (let c = 0; c < numberOfChannels; c++) {
49
- audioData.frames[c][i] = interleaved[w++];
44
+ if (audioFormat === 3 && bitsPerSample === 32) {
45
+ // 32-bit float
46
+ const interleaved = new Float32Array(buffer, dataOffset, numberOfFrames * numberOfChannels);
47
+ for (let i = 0, w = 0; i < numberOfFrames; i++) {
48
+ for (let c = 0; c < numberOfChannels; c++) {
49
+ audioData.frames[c][i] = interleaved[w++];
50
+ }
51
+ }
52
+ }
53
+ else if (audioFormat === 1 && bitsPerSample === 16) {
54
+ // 16-bit PCM
55
+ for (let i = 0, offset = dataOffset; i < numberOfFrames; i++) {
56
+ for (let c = 0; c < numberOfChannels; c++) {
57
+ audioData.frames[c][i] = view.getInt16(offset, true) / 32768;
58
+ offset += 2;
59
+ }
50
60
  }
51
61
  }
62
+ else if (audioFormat === 1 && bitsPerSample === 24) {
63
+ // 24-bit PCM
64
+ for (let i = 0, offset = dataOffset; i < numberOfFrames; i++) {
65
+ for (let c = 0; c < numberOfChannels; c++) {
66
+ const low = view.getUint16(offset, true);
67
+ const high = view.getInt8(offset + 2);
68
+ audioData.frames[c][i] = (high * 65536 + low) / 8388608;
69
+ offset += 3;
70
+ }
71
+ }
72
+ }
73
+ else {
74
+ return panic(`Unsupported WAV format: ${audioFormat}, ${bitsPerSample}-bit`);
75
+ }
52
76
  return audioData;
53
77
  };
54
78
  WavFile.encodeFloats = (audio, maxLength = Number.MAX_SAFE_INTEGER) => {
@@ -90,10 +90,10 @@ export class CaptureAudio extends Capture {
90
90
  }
91
91
  }
92
92
  this.#stopStream();
93
- const deviceId = this.deviceId.getValue().unwrapOrElse("default");
93
+ const deviceId = this.deviceId.getValue().unwrapOrUndefined() ?? AudioDevices.defaultInput?.deviceId;
94
94
  const channelCount = this.#requestChannels.unwrapOrElse(1);
95
95
  return AudioDevices.requestStream({
96
- deviceId: { exact: deviceId },
96
+ deviceId: isDefined(deviceId) ? { exact: deviceId } : undefined,
97
97
  echoCancellation: false,
98
98
  noiseSuppression: false,
99
99
  autoGainControl: false,
@@ -103,8 +103,8 @@ export class CaptureAudio extends Capture {
103
103
  const track = tracks.at(0);
104
104
  const settings = track?.getSettings();
105
105
  const gotDeviceId = settings?.deviceId;
106
- console.debug(`new stream. device requested: ${deviceId}, got: ${gotDeviceId ?? "unknown"}. channelCount requested: ${channelCount}, got: ${settings?.channelCount}`);
107
- if (deviceId === "default" || deviceId === gotDeviceId) {
106
+ console.debug(`new stream. device requested: ${deviceId ?? "default"}, got: ${gotDeviceId ?? "unknown"}. channelCount requested: ${channelCount}, got: ${settings?.channelCount}`);
107
+ if (isUndefined(deviceId) || deviceId === gotDeviceId) {
108
108
  this.#stream.wrap(stream);
109
109
  }
110
110
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAUzF,OAAO,EAAa,mBAAmB,EAAY,MAAM,0BAA0B,CAAA;AACnF,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,yBAAiB,WAAW,CAAC;IACzB,KAAK,kBAAkB,GAAG;QACtB,gBAAgB,EAAE,gBAAgB,CAAA;QAClC,WAAW,EAAE,WAAW,CAAA;QACxB,aAAa,EAAE,mBAAmB,CAAA;QAClC,YAAY,EAAE,YAAY,CAAA;QAC1B,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,aAAa,EAAE,MAAM,CAAA;KACxB,CAAA;IAQD,MAAM,CAAC,MAAM,KAAK,GACd,yGASG,kBAAkB,KACnB,UA2IL,CAAA;;CACJ"}
1
+ {"version":3,"file":"RecordAudio.d.ts","sourceRoot":"","sources":["../../src/capture/RecordAudio.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2C,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAUvG,OAAO,EAAa,mBAAmB,EAA2B,MAAM,0BAA0B,CAAA;AAClG,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAClC,OAAO,EAAC,gBAAgB,EAAC,MAAM,qBAAqB,CAAA;AACpD,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAA;AAGjC,yBAAiB,WAAW,CAAC;IACzB,KAAK,kBAAkB,GAAG;QACtB,gBAAgB,EAAE,gBAAgB,CAAA;QAClC,WAAW,EAAE,WAAW,CAAA;QACxB,aAAa,EAAE,mBAAmB,CAAA;QAClC,YAAY,EAAE,YAAY,CAAA;QAC1B,OAAO,EAAE,OAAO,CAAA;QAChB,OAAO,EAAE,OAAO,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;QACd,aAAa,EAAE,MAAM,CAAA;KACxB,CAAA;IAQD,MAAM,CAAC,MAAM,KAAK,GACd,yGASG,kBAAkB,KACnB,UAyKL,CAAA;;CACJ"}
@@ -1,7 +1,7 @@
1
- import { Option, quantizeFloor, Terminable, Terminator, UUID } from "@opendaw/lib-std";
1
+ import { asInstanceOf, Option, quantizeFloor, Terminable, Terminator, UUID } from "@opendaw/lib-std";
2
2
  import { dbToGain, PPQN, TimeBase } from "@opendaw/lib-dsp";
3
- import { AudioFileBox, AudioPitchStretchBox, AudioRegionBox, ValueEventCollectionBox, WarpMarkerBox } from "@opendaw/studio-boxes";
4
- import { ColorCodes, TrackType } from "@opendaw/studio-adapters";
3
+ import { AudioFileBox, AudioPitchStretchBox, AudioRegionBox, TrackBox, ValueEventCollectionBox, WarpMarkerBox } from "@opendaw/studio-boxes";
4
+ import { ColorCodes, TrackType, UnionBoxTypes } from "@opendaw/studio-adapters";
5
5
  import { RecordTrack } from "./RecordTrack";
6
6
  export var RecordAudio;
7
7
  (function (RecordAudio) {
@@ -24,7 +24,7 @@ export var RecordAudio;
24
24
  let lastPosition = 0;
25
25
  let currentWaveformOffset = outputLatency;
26
26
  let takeNumber = 0;
27
- const { tempoMap, env: { audioContext: { sampleRate } } } = project;
27
+ const { tempoMap, env: { audioContext: { sampleRate } }, engine: { preferences: { settings: { recording } } } } = project;
28
28
  const { loopArea } = timelineBox;
29
29
  const createFileBox = () => {
30
30
  const fileDateString = new Date()
@@ -67,8 +67,43 @@ export var RecordAudio;
67
67
  warpMarkerBox.position.setValue(loopDurationPPQN);
68
68
  warpMarkerBox.seconds.setValue(seconds);
69
69
  }
70
- if (trackBox.isAttached()) {
71
- trackBox.enabled.setValue(false);
70
+ const { olderTakeAction, olderTakeScope } = recording;
71
+ if (olderTakeScope === "all") {
72
+ for (const track of capture.audioUnitBox.tracks.pointerHub.incoming()
73
+ .map(({ box }) => asInstanceOf(box, TrackBox))) {
74
+ const trackType = track.type.getValue();
75
+ if (trackType === TrackType.Value || trackType === TrackType.Undefined) {
76
+ continue;
77
+ }
78
+ if (track === trackBox) {
79
+ continue;
80
+ }
81
+ if (olderTakeAction === "disable-track") {
82
+ if (track.isAttached()) {
83
+ track.enabled.setValue(false);
84
+ }
85
+ }
86
+ else {
87
+ for (const region of track.regions.pointerHub.incoming()
88
+ .map(({ box }) => UnionBoxTypes.asRegionBox(box))) {
89
+ if (region.isAttached()) {
90
+ region.mute.setValue(true);
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ else {
97
+ if (olderTakeAction === "disable-track") {
98
+ if (trackBox.isAttached()) {
99
+ trackBox.enabled.setValue(false);
100
+ }
101
+ }
102
+ else {
103
+ if (regionBox.isAttached()) {
104
+ regionBox.mute.setValue(true);
105
+ }
106
+ }
72
107
  }
73
108
  };
74
109
  const startNewTake = (position) => {
@@ -94,12 +129,14 @@ export var RecordAudio;
94
129
  const loopEnabled = loopArea.enabled.getValue();
95
130
  const loopFrom = loopArea.from.getValue();
96
131
  const loopTo = loopArea.to.getValue();
97
- const loopDurationPPQN = loopTo - loopFrom;
98
- const loopDurationSeconds = tempoMap.intervalToSeconds(loopFrom, loopTo);
99
- if (loopEnabled && currentTake.nonEmpty() && currentPosition < lastPosition) {
132
+ const allowTakes = project.engine.preferences.settings.recording.allowTakes;
133
+ if (loopEnabled && allowTakes && currentTake.nonEmpty() && currentPosition < lastPosition) {
100
134
  editing.modify(() => {
101
- currentTake.ifSome(take => finalizeTake(take, loopDurationPPQN));
102
- currentWaveformOffset += loopDurationSeconds;
135
+ currentTake.ifSome(take => {
136
+ const actualDurationPPQN = take.regionBox.duration.getValue();
137
+ finalizeTake(take, actualDurationPPQN);
138
+ currentWaveformOffset += tempoMap.intervalToSeconds(0, actualDurationPPQN);
139
+ });
103
140
  startNewTake(loopFrom);
104
141
  }, false);
105
142
  }
@@ -116,7 +153,7 @@ export var RecordAudio;
116
153
  editing.modify(() => {
117
154
  if (regionBox.isAttached()) {
118
155
  const { duration, loopDuration } = regionBox;
119
- const maxDuration = loopEnabled ? loopTo - regionBox.position.getValue() : Infinity;
156
+ const maxDuration = loopEnabled && allowTakes ? loopTo - regionBox.position.getValue() : Infinity;
120
157
  const distanceInPPQN = Math.min(maxDuration, Math.floor(currentPosition - regionBox.position.getValue()));
121
158
  duration.setValue(distanceInPPQN);
122
159
  loopDuration.setValue(distanceInPPQN);
@@ -1 +1 @@
1
- {"version":3,"file":"RecordMidi.d.ts","sourceRoot":"","sources":["../../src/capture/RecordMidi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,QAAQ,EAAuC,UAAU,EAAmB,MAAM,kBAAkB,CAAA;AAGvH,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;IAgBD,MAAM,CAAC,MAAM,KAAK,GAAI,gCAA8B,iBAAiB,KAAG,UAmHvE,CAAA;;CACJ"}
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,UAgJvE,CAAA;;CACJ"}
@@ -1,7 +1,7 @@
1
- import { Option, quantizeCeil, quantizeFloor, Terminator, UUID } from "@opendaw/lib-std";
1
+ import { asInstanceOf, Option, quantizeCeil, quantizeFloor, Terminator, UUID } from "@opendaw/lib-std";
2
2
  import { PPQN } from "@opendaw/lib-dsp";
3
- import { NoteEventBox, NoteEventCollectionBox, NoteRegionBox } from "@opendaw/studio-boxes";
4
- import { ColorCodes, NoteSignal, TrackType } from "@opendaw/studio-adapters";
3
+ import { NoteEventBox, NoteEventCollectionBox, NoteRegionBox, TrackBox } from "@opendaw/studio-boxes";
4
+ import { ColorCodes, NoteSignal, TrackType, UnionBoxTypes } from "@opendaw/studio-adapters";
5
5
  import { RecordTrack } from "./RecordTrack";
6
6
  export var RecordMidi;
7
7
  (function (RecordMidi) {
@@ -9,7 +9,7 @@ export var RecordMidi;
9
9
  RecordMidi.start = ({ notifier, project, capture }) => {
10
10
  const beats = PPQN.fromSignature(1, project.timelineBox.signature.denominator.getValue());
11
11
  const { editing, boxGraph, engine, env: { audioContext }, timelineBox } = project;
12
- const { position, isRecording } = engine;
12
+ const { position, isRecording, preferences: { settings: { recording } } } = engine;
13
13
  const { loopArea } = timelineBox;
14
14
  const terminator = new Terminator();
15
15
  const activeNotes = new Map();
@@ -40,8 +40,43 @@ export var RecordMidi;
40
40
  regionBox.duration.setValue(loopDurationPPQN);
41
41
  regionBox.loopDuration.setValue(loopDurationPPQN);
42
42
  }
43
- if (trackBox.isAttached()) {
44
- trackBox.enabled.setValue(false);
43
+ const { olderTakeAction, olderTakeScope } = recording;
44
+ if (olderTakeScope === "all") {
45
+ for (const track of capture.audioUnitBox.tracks.pointerHub.incoming()
46
+ .map(({ box }) => asInstanceOf(box, TrackBox))) {
47
+ const trackType = track.type.getValue();
48
+ if (trackType === TrackType.Value || trackType === TrackType.Undefined) {
49
+ continue;
50
+ }
51
+ if (track === trackBox) {
52
+ continue;
53
+ }
54
+ if (olderTakeAction === "disable-track") {
55
+ if (track.isAttached()) {
56
+ track.enabled.setValue(false);
57
+ }
58
+ }
59
+ else {
60
+ for (const region of track.regions.pointerHub.incoming()
61
+ .map(({ box }) => UnionBoxTypes.asRegionBox(box))) {
62
+ if (region.isAttached()) {
63
+ region.mute.setValue(true);
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ else {
70
+ if (olderTakeAction === "disable-track") {
71
+ if (trackBox.isAttached()) {
72
+ trackBox.enabled.setValue(false);
73
+ }
74
+ }
75
+ else {
76
+ if (regionBox.isAttached()) {
77
+ regionBox.mute.setValue(true);
78
+ }
79
+ }
45
80
  }
46
81
  };
47
82
  const startNewTake = (position) => {
@@ -57,7 +92,8 @@ export var RecordMidi;
57
92
  const loopFrom = loopArea.from.getValue();
58
93
  const loopTo = loopArea.to.getValue();
59
94
  const loopDurationPPQN = loopTo - loopFrom;
60
- if (loopEnabled && currentTake.nonEmpty() && currentPosition < lastPosition) {
95
+ const allowTakes = project.engine.preferences.settings.recording.allowTakes;
96
+ if (loopEnabled && allowTakes && currentTake.nonEmpty() && currentPosition < lastPosition) {
61
97
  positionOffset += loopDurationPPQN;
62
98
  editing.modify(() => {
63
99
  currentTake.ifSome(take => finalizeTake(take, loopDurationPPQN));
@@ -75,7 +111,7 @@ export var RecordMidi;
75
111
  editing.modify(() => {
76
112
  if (regionBox.isAttached() && collection.isAttached()) {
77
113
  const { position: regionPosition, duration, loopDuration } = regionBox;
78
- const maxDuration = loopEnabled ? loopTo - regionPosition.getValue() : Infinity;
114
+ const maxDuration = loopEnabled && allowTakes ? loopTo - regionPosition.getValue() : Infinity;
79
115
  const newDuration = Math.min(maxDuration, quantizeCeil(writePosition, beats) - regionPosition.getValue());
80
116
  duration.setValue(newDuration);
81
117
  loopDuration.setValue(newDuration);
@@ -2,8 +2,10 @@ import { Terminable } from "@opendaw/lib-std";
2
2
  import { Project } from "../project";
3
3
  export declare class Recording {
4
4
  #private;
5
+ readonly countIn: boolean;
5
6
  static get isRecording(): boolean;
6
7
  static start(project: Project, countIn: boolean): Promise<Terminable>;
8
+ static wasCountingIn(): boolean;
7
9
  private constructor();
8
10
  }
9
11
  //# sourceMappingURL=Recording.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Recording.d.ts","sourceRoot":"","sources":["../../src/capture/Recording.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAK7F,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAElC,qBAAa,SAAS;;IAClB,MAAM,KAAK,WAAW,IAAI,OAAO,CAA2B;WAE/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IA8D3E,OAAO;CACV"}
1
+ {"version":3,"file":"Recording.d.ts","sourceRoot":"","sources":["../../src/capture/Recording.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,UAAU,EAAa,MAAM,kBAAkB,CAAA;AAK7F,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAA;AAElC,qBAAa,SAAS;;IAmEE,QAAQ,CAAC,OAAO,EAAE,OAAO;IAlE7C,MAAM,KAAK,WAAW,IAAI,OAAO,CAA2B;WAE/C,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IA8D3E,MAAM,CAAC,aAAa,IAAI,OAAO;IAE/B,OAAO;CACV"}
@@ -4,6 +4,7 @@ import { AudioUnitType } from "@opendaw/studio-enums";
4
4
  import { AudioUnitBox } from "@opendaw/studio-boxes";
5
5
  import { InstrumentFactories } from "@opendaw/studio-adapters";
6
6
  export class Recording {
7
+ countIn;
7
8
  static get isRecording() { return this.#isRecording; }
8
9
  static async start(project, countIn) {
9
10
  if (this.#isRecording) {
@@ -36,7 +37,7 @@ export class Recording {
36
37
  this.#isRecording = false;
37
38
  };
38
39
  terminator.ownAll(engine.isRecording.subscribe(stop), engine.isCountingIn.subscribe(stop), Terminable.create(() => Recording.#instance = Option.None));
39
- this.#instance = Option.wrap(new Recording());
40
+ this.#instance = Option.wrap(new Recording(countIn));
40
41
  return terminator;
41
42
  }
42
43
  static #prepare({ api, captureDevices, editing, rootBox, userEditingManager }) {
@@ -60,5 +61,8 @@ export class Recording {
60
61
  }
61
62
  static #isRecording = false;
62
63
  static #instance = Option.None;
63
- constructor() { }
64
+ static wasCountingIn() { return this.#instance.mapOr(recording => recording.countIn, () => false); }
65
+ constructor(countIn) {
66
+ this.countIn = countIn;
67
+ }
64
68
  }
@@ -1,8 +1,8 @@
1
- import { int, Terminable } from "@opendaw/lib-std";
1
+ import { int, Provider, Terminable } from "@opendaw/lib-std";
2
2
  type MIDIMessageCallback = (deviceId: string, data: Uint8Array, timeMs: int) => void;
3
3
  export declare class MIDIReceiver implements Terminable {
4
4
  #private;
5
- static create(context: BaseAudioContext, callback: MIDIMessageCallback): MIDIReceiver;
5
+ static create(outputLatencyProvider: Provider<number>, callback: MIDIMessageCallback): MIDIReceiver;
6
6
  private constructor();
7
7
  get sab(): SharedArrayBuffer;
8
8
  get port(): MessagePort;
@@ -1 +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"}
1
+ {"version":3,"file":"MIDIReceiver.d.ts","sourceRoot":"","sources":["../../src/midi/MIDIReceiver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAC,MAAM,kBAAkB,CAAA;AAE1D,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,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,mBAAmB,GAAG,YAAY;IAiBnG,OAAO;IAgBP,IAAI,GAAG,IAAI,iBAAiB,CAAmB;IAC/C,IAAI,IAAI,IAAI,WAAW,CAA6B;IAEpD,SAAS,IAAI,IAAI;CAwBpB"}
@@ -1,15 +1,10 @@
1
1
  export class MIDIReceiver {
2
- static create(context, callback) {
2
+ static create(outputLatencyProvider, callback) {
3
3
  const MIDI_RING_SIZE = 2048;
4
4
  const sab = new SharedArrayBuffer(MIDI_RING_SIZE * 2 * 4 + 8);
5
5
  const channel = new MessageChannel();
6
- const hasOutputLatency = context instanceof AudioContext;
7
6
  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);
7
+ callback(deviceId, data, relativeTimeInMs + outputLatencyProvider());
13
8
  });
14
9
  }
15
10
  #sab;
@@ -1,3 +1,4 @@
1
1
  export * from "./MidiDevices";
2
2
  export * from "./MIDILearning";
3
+ export * from "./MIDIReceiver";
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/midi/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/midi/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAA;AAC7B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA"}
@@ -1,2 +1,3 @@
1
1
  export * from "./MidiDevices";
2
2
  export * from "./MIDILearning";
3
+ export * from "./MIDIReceiver";
@@ -1,2 +1,2 @@
1
- var h=n=>n!=null;var x=(n,e="asDefined failed")=>n??p(U(e));var U=n=>n instanceof Function?n():n;var z=n=>{throw new Error(`Unhandled ${n}`)},p=n=>{throw typeof n=="string"?new Error(n):n},q=(n,e)=>n?void 0:p(U(e));var G=n=>new Proxy({},{get(){return p(n)}});var F=class{value;status="success";constructor(e){this.value=e}error=G("Cannot access error when succeeded")},_=class{error;status="failure";constructor(e){this.error=e}value=G("Cannot access value when failed")},V=n=>{try{return new F(n())}catch(e){return new _(e)}};var Y=()=>{};var N;(function(n){n[n.Ascending=1]="Ascending",n[n.Descending=-1]="Descending"})(N||(N={}));var b=class{static#e=Object.freeze(new Array(0));static empty=()=>this.#e;static clear=e=>{e.length=0};static replace=(e,t)=>{e.length=0,e.push(...t)};static consume=(e,t)=>{for(let s=0;s<e.length;)t(e[s])?e.splice(s,1):s++};static peekFirst=e=>e.at(0)??null;static peekLast=e=>e.at(-1)??null;static getFirst=(e,t)=>x(e.at(0),t);static getLast=(e,t)=>x(e.at(-1),t);static getPrev=(e,t)=>{let s=e.indexOf(t);return s===-1?p(`${t} not found in ${e}`):x(e.at((s-1)%e.length),"Internal Error")};static getNext=(e,t)=>{let s=e.indexOf(t);return s===-1?p(`${t} not found in ${e}`):x(e.at((s+1)%e.length),"Internal Error")};static removeLast=(e,t)=>x(e.pop(),t);static create=(e,t)=>{let s=new Array(t);for(let r=0;r<t;r++)s[r]=e(r);return s};static equals=(e,t)=>{if(e.length!==t.length)return!1;for(let s=0;s<e.length;s++)if(e[s]!==t[s])return!1;return!0};static satisfy=(e,t)=>{if(e.length<2)return!0;let s=e[0];for(let r=1;r<e.length;r++)if(!t(s,e[r]))return!1;return!0};static remove=(e,t)=>{let s=e.indexOf(t);if(s===-1)return p(`${t} not found in ${e}`);e.splice(s,1)};static removeIf=(e,t)=>{for(let s=e.length-1;s>=0;s--)t(e[s])&&e.splice(s,1)};static removeOpt=(e,t)=>{let s=e.indexOf(t);return s===-1?!1:(e.splice(s,1),!0)};static hasDuplicates=e=>new Set(e).size<e.length;static removeDuplicates=e=>{let t=0,s=new Set;for(let r of e)s.has(r)||(s.add(r),e[t++]=r);return e.length=t,e};static removeDuplicateKeys=(e,t)=>{let s=0,r=new Set;for(let o of e){let i=o[t];r.has(i)||(r.add(i),e[s++]=o)}return e.length=s,e};static subtract(e,t,s){return e.filter(r=>!t.some(o=>s(r,o)))}static intersect(e,t,s){return e.filter(r=>t.some(o=>s(r,o)))}static merge(e,t,s){return[...e.filter(r=>!t.some(o=>s(r,o))),...t]}static*iterate(e){for(let t=0;t<e.length;t++)yield e[t]}static*iterateReverse(e){for(let t=e.length-1;t>=0;t--)yield e[t]}static*iterateStateFull(e){let t=e.length-1;for(let s=0;s<=t;s++)yield{value:e[s],isFirst:s===0,isLast:s===t}}static*iterateAdjacent(e){if(!(e.length<=1))for(let t=1,s=e[0];t<e.length;t++){let r=e[t];yield[s,r],s=r}}static isSorted(e,t=N.Ascending){if(e.length<2)return!0;let s=e[0];for(let r=1;r<e.length;r++){let o=e[r];if(Math.sign(s-o)===t)return!1;s=o}return!0}static toRecord(e,t){return e.reduce((s,r)=>(s[t(r)]=r,s),{})}static concatArrayBuffers(e,t){let s=new ArrayBuffer(e.byteLength+t.byteLength),r=new Uint8Array(s);return r.set(new Uint8Array(e),0),r.set(new Uint8Array(t),e.byteLength),s}};var I=class{static*empty(){}static one(e){return[e]}static count(e){let t=0;for(let s of e)t++;return t}static some(e,t){for(let s of e)if(t(s))return!0;return!1}static every(e,t){for(let s of e)if(!t(s))return!1;return!0}static reduce(e,t,s){let r=s,o=0;for(let i of e)r=t(r,i,o++);return r}static includes(e,t){for(let s of e)if(s===t)return!0;return!1}static forEach(e,t){for(let s of e)t(s)}static*map(e,t){let s=0;for(let r of e)yield t(r,s++)}static*take(e,t){let s=0;for(let r of e){if(s++>=t)return;yield r}}static filter(e,t){let s=[];for(let r of e)t(r)&&s.push(r);return s}static filterMap(e,t){let s=[];for(let r of e){let o=t(r);h(o)&&s.push(o)}return s}static reverse(e){let t=[];for(let s of e)t.push(s);return t.reverse()}static*pairWise(e){let t=e[Symbol.iterator](),{done:s,value:r}=t.next(),o=r;if(s!==!0)for(;;){let{done:i,value:a}=t.next();if(i===!0){yield[o,null];return}yield[o,a],o=a}}};var K=Object.freeze({Empty:{terminate:Y},create:n=>({terminate:n}),many:(...n)=>({terminate:()=>{for(;n.length>0;)n.pop().terminate()}})});var E=class{static subscribeMany(e,...t){return K.many(...t.map(s=>s.subscribe(()=>e(s))))}#e=new Set;subscribe(e){return this.#e.add(e),{terminate:()=>this.#e.delete(e)}}isEmpty(){return this.#e.size===0}notify(e){this.#e.forEach(t=>t(e))}observers(){return this.#e}terminate(){this.#e.clear()}};var T=class n{static POSITIVE_INFINITY=new n(Number.POSITIVE_INFINITY);static millis=e=>new n(e);static seconds=e=>new n(e*n.#e);static minutes=e=>new n(e*n.#t);static hours=e=>new n(e*n.#r);static days=e=>new n(e*n.#o);static toHHMMSS=e=>((e/3600|0)+100).toString().slice(1)+":"+((e/60|0)%60+100).toString().slice(1)+":"+(e%60+100).toString().slice(1);static#e=1e3;static#t=6e4;static#r=36e5;static#o=864e5;#s;constructor(e){this.#s=e}millis(){return this.#s}absSeconds(){return Math.abs(this.#s)/n.#e}absMinutes(){return Math.abs(this.#s)/n.#t}absHours(){return Math.abs(this.#s)/n.#r}absDays(){return Math.abs(this.#s)/n.#o}split(){return{d:Math.floor(this.absDays()),h:Math.floor(this.absHours())%24,m:Math.floor(this.absMinutes())%60,s:Math.floor(this.absSeconds())%60}}isNow(){return this.#s===0}isPast(){return this.#s<0}isFuture(){return this.#s>0}toUnitString(){let e,t,s=Math.floor(Math.abs(this.#s)/1e3),r=Math.floor(s/60),o=Math.floor(r/60),i=Math.floor(o/24);return s<60?(e=s,t="second"):r<60?(e=r,t="minute"):o<24?(e=o,t="hour"):(e=i,t="day"),new Intl.RelativeTimeFormat("en",{numeric:"auto",style:"long"}).format(e*Math.sign(this.#s),t)}toString(){if(isNaN(this.#s))return"NaN";if(!isFinite(this.#s))return"\u221E";let{d:e,h:t,m:s,s:r}=this.split();return e>0?[n.#n("d",e),n.#n("h",t),n.#n("m",s),n.#n("s",r)].join(", "):t>0?[n.#n("h",t),n.#n("m",s),n.#n("s",r)].join(", "):s>0?[n.#n("m",s),n.#n("s",r)].join(", "):r>0?n.#n("s",r):"now"}static#n=(e,t)=>{switch(e){case"d":return`${t} ${t<2?"day":"days"}`;case"h":return`${t} ${t<2?"hour":"hours"}`;case"m":return`${t} ${t<2?"minute":"minutes"}`;case"s":return`${t} ${t<2?"second":"seconds"}`;default:return z(e)}}};var $;(function(n){n.sender=(r,o)=>o(new t(r)),n.executor=(r,o)=>new s(r,o);let e=r=>{let o=[];for(let i of r)i instanceof MessagePort&&o.push(i),typeof ImageBitmap<"u"&&i instanceof ImageBitmap&&o.push(i),typeof OffscreenCanvas<"u"&&i instanceof OffscreenCanvas&&o.push(i);return o};class t{#e;#t=new Map;#r;#o=0;constructor(o){this.#e=o,this.#r=o.subscribe(this.#s)}terminate(){this.#r.terminate()}dispatchAndForget=(o,...i)=>{let a=e(i);this.#e.send({type:"send",returnId:!1,func:o.name,args:Array.from(I.map(i,c=>({value:c})))},a)};dispatchAndReturn=(o,...i)=>new Promise((a,c)=>{let l=I.reduce(i,(u,v,d)=>(typeof v=="function"&&u.push([d,v]),u),[]);this.#t.set(this.#o,{executorTuple:{resolve:a,reject:c},callbacks:new Map(l)});let f=e(i);this.#e.send({type:"send",returnId:this.#o,func:o.name,args:Array.from(I.map(i,(u,v)=>typeof u=="function"?{callback:v}:{value:u}))},f),this.#o++});#s=o=>{let i=this.#t.get(o.returnId);h(i)?o.type==="resolve"?(i.executorTuple.resolve(o.resolve),this.#t.delete(o.returnId)):o.type==="reject"?(i.executorTuple.reject(o.reject),this.#t.delete(o.returnId)):o.type==="callback"&&i.callbacks?.get(o.funcAt).apply(this,o.args):p(`Promise has already been resolved. ${JSON.stringify(o)}`)}}class s{#e;#t;#r;constructor(o,i){this.#e=o,this.#t=i,this.#r=o.subscribe(this.#o)}terminate(){this.#r.terminate()}#o=o=>{q(o.type==="send",()=>"Message type must be 'send'");let i=Object.getPrototypeOf(this.#t)===Object.getPrototypeOf({})?this.#t:Object.getPrototypeOf(this.#t),a=x(i[o.func],`${o.func.toString()} does not exists on ${this.#t}`),c=o.returnId;if(c===!1)a.apply(this.#t,o.args.map(l=>"value"in l?l.value:p(`${o.func.toString()} has no promise.`)));else try{a.apply(this.#t,o.args.map(f=>"callback"in f?(...u)=>this.#i(c,f.callback,u):f.value)).then(f=>{try{this.#s(c,f)}catch(u){this.#n(c,u)}},f=>this.#n(c,f))}catch(l){this.#n(c,l)}};#s=(o,i)=>this.#e.send({type:"resolve",returnId:o,resolve:i});#n=(o,i)=>this.#e.send({type:"reject",returnId:o,reject:i});#i=(o,i,a)=>this.#e.send({type:"callback",returnId:o,funcAt:i,args:a})}n.Executor=s})($||($={}));var W={for:n=>new D(n)},re=[],D=class{#e;#t=new E;constructor(e){if(this.#e=e,h(e.onmessage)||h(e.onmessageerror))throw console.error(e),new Error(`${e} is already wrapped.`);e.onmessage=t=>this.#t.notify(t.data),e.onmessageerror=t=>{throw new Error(t.type)}}send(e,t){this.#e.postMessage(e,t??re)}channel(e){return new k(this,e)}subscribe(e){return this.#t.subscribe(e)}terminate(){this.#t.terminate(),this.#e.onmessage=null,this.#e.onmessageerror=null}},k=class n{#e;#t;#r=new E;#o;constructor(e,t){this.#e=e,this.#t=t,this.#o=e.subscribe(s=>{"__id__"in s&&s.__id__==="42"&&"message"in s&&"channel"in s&&s.channel===t&&this.#r.notify(s.message)})}send(e,t){this.#e.send({__id__:"42",channel:this.#t,message:e},t)}channel(e){return new n(this,e)}subscribe(e){return this.#r.subscribe(e)}terminate(){this.#o.terminate(),this.#r.terminate()}};var A;(function(n){n.frame=()=>new Promise(e=>requestAnimationFrame(()=>e())),n.frames=e=>new Promise(t=>{let s=e,r=()=>{--s<=0?t():requestAnimationFrame(r)};requestAnimationFrame(r)}),n.timeSpan=(e,...t)=>new Promise(s=>setTimeout(s,e.millis(),...t)),n.event=(e,t)=>new Promise(s=>e.addEventListener(t,s,{once:!0})),n.observable=e=>new Promise(t=>{let s=e.subscribe(()=>{s.terminate(),t()})}),n.complete=e=>new Promise((t,s)=>{let r=setInterval(()=>{let{status:o,value:i,error:a}=V(()=>e.next());if(o==="success"){let{done:c,value:l}=i;c&&(clearInterval(r),t(l))}else clearInterval(r),s(a)},0)})})(A||(A={}));var C=(n,e)=>Math.floor(3840/e)*n,Z=(n,e=4,t=4)=>{let s=C(1,t),r=Math.floor(n/s),o=Math.floor(r/e),a=(Math.floor(n)-C(o*e,t))%s,c=Math.floor(a/240),l=a%240;return{bars:o,beats:r-o*e,semiquavers:c,ticks:l}},J=(n,e)=>n*e/60*960,X=(n,e)=>n*60/960/e,oe=(n,e)=>e*60/960/n,ie=(n,e,t)=>J(n/t,e),ae=(n,e,t)=>X(n,e)*t,ee={Bar:3840,Quarter:960,SemiQuaver:240,fromSignature:C,toParts:Z,secondsToPulses:J,pulsesToSeconds:X,secondsToBpm:oe,samplesToPulses:ie,pulsesToSamples:ae,toString:(n,e=4,t=4)=>{let{bars:s,beats:r,semiquavers:o,ticks:i}=Z(n|0,e,t);return`${s+1}.${r+1}.${o+1}:${i}`}};var P=128,Te=ee.fromSignature(1,48);var ce=Math.log(10)/20;var te=n=>Math.exp(n*ce);var L=class{port;constructor(){this.port=globalThis.__workletPort__}};function se(n){let e=globalThis;e.sampleRate=n.sampleRate,e.currentFrame=0,e.currentTime=0,e.AudioWorkletProcessor=L,e.registerProcessor=(t,s)=>{e.__registeredProcessors__=e.__registeredProcessors__||{},e.__registeredProcessors__[t]=s}}function R(n,e){let t=globalThis;t.currentFrame=n,t.currentTime=n/e}var B=null,Q=null,y=48e3,w=2,j=!1,m=0;$.executor(W.for(self).channel("offline-engine"),{async initialize(n,e,t){y=t.sampleRate,w=t.numberOfChannels,Q=e,m=0,se({sampleRate:y}),globalThis.__workletPort__=n,await import(t.processorsUrl);let s=globalThis.__registeredProcessors__["engine-processor"];B=new s({processorOptions:{syncStreamBuffer:t.syncStreamBuffer,controlFlagsBuffer:t.controlFlagsBuffer,project:t.project,exportConfiguration:t.exportConfiguration}})},async step(n){let e=b.create(()=>new Float32Array(n),w),t=b.create(()=>new Float32Array(P),w),s=0;for(;s<n;){let r=[t];R(m,y),B.process([[]],r),m+=P;let o=n-s,i=Math.min(o,P);for(let a=0;a<w;a++)e[a].set(r[0][a].subarray(0,i),s);s+=i}return e},async render(n){let{silenceThresholdDb:e,silenceDurationSeconds:t,maxDurationSeconds:s}=n,r=te(e??-72),o=Math.ceil((t??10)*y),i=h(s)?Math.ceil(s*y):1/0,a=b.create(()=>[],w),c=0,l=!1,f=0;for(j=!0,await A.timeSpan(T.seconds(0));j&&m<i;){let d=[b.create(()=>new Float32Array(P),w)];R(m,y);let S=B.process([[]],d),M=0;for(let g of d[0])for(let ne of g){let H=Math.abs(ne);H>M&&(M=H)}let O=M<=r;if(M>r&&(l=!0),O&&l){if(c+=P,c>=o)break}else c=0;for(let g=0;g<w;g++)a[g].push(d[0][g].slice());if(m+=P,!S)break;m-f>=y&&(f=m,h(Q)&&Q.postMessage({frames:m}),await new Promise(g=>setTimeout(g,0)))}let u=m-c+Math.min(y/4,c);return b.create(v=>{let d=new Float32Array(u),S=0;for(let M of a[v]){if(S>=u)break;let O=Math.min(M.length,u-S);d.set(M.subarray(0,O),S),S+=O}return d},w)},stop(){j=!1}});
1
+ var h=n=>n!=null;var x=(n,t="asDefined failed")=>n??p(U(t));var U=n=>n instanceof Function?n():n;var z=n=>{throw new Error(`Unhandled ${n}`)},p=n=>{throw typeof n=="string"?new Error(n):n},q=(n,t)=>n?void 0:p(U(t));var V=n=>new Proxy({},{get(){return p(n)}});var $=class{value;status="success";constructor(t){this.value=t}error=V("Cannot access error when succeeded")},A=class{error;status="failure";constructor(t){this.error=t}value=V("Cannot access value when failed")},G=n=>{try{return new $(n())}catch(t){return new A(t)}};var Y=()=>{};var _;(function(n){n[n.Ascending=1]="Ascending",n[n.Descending=-1]="Descending"})(_||(_={}));var b=class{static#t=Object.freeze(new Array(0));static empty=()=>this.#t;static clear=t=>{t.length=0};static replace=(t,e)=>{t.length=0,t.push(...e)};static consume=(t,e)=>{for(let s=0;s<t.length;)e(t[s])?t.splice(s,1):s++};static peekFirst=t=>t.at(0)??null;static peekLast=t=>t.at(-1)??null;static getFirst=(t,e)=>x(t.at(0),e);static getLast=(t,e)=>x(t.at(-1),e);static getPrev=(t,e)=>{let s=t.indexOf(e);return s===-1?p(`${e} not found in ${t}`):x(t.at((s-1)%t.length),"Internal Error")};static getNext=(t,e)=>{let s=t.indexOf(e);return s===-1?p(`${e} not found in ${t}`):x(t.at((s+1)%t.length),"Internal Error")};static removeLast=(t,e)=>x(t.pop(),e);static create=(t,e)=>{let s=new Array(e);for(let r=0;r<e;r++)s[r]=t(r);return s};static equals=(t,e)=>{if(t.length!==e.length)return!1;for(let s=0;s<t.length;s++)if(t[s]!==e[s])return!1;return!0};static satisfy=(t,e)=>{if(t.length<2)return!0;let s=t[0];for(let r=1;r<t.length;r++)if(!e(s,t[r]))return!1;return!0};static remove=(t,e)=>{let s=t.indexOf(e);if(s===-1)return p(`${e} not found in ${t}`);t.splice(s,1)};static removeIf=(t,e)=>{for(let s=t.length-1;s>=0;s--)e(t[s])&&t.splice(s,1)};static removeOpt=(t,e)=>{let s=t.indexOf(e);return s===-1?!1:(t.splice(s,1),!0)};static hasDuplicates=t=>new Set(t).size<t.length;static removeDuplicates=t=>{let e=0,s=new Set;for(let r of t)s.has(r)||(s.add(r),t[e++]=r);return t.length=e,t};static removeDuplicateKeys=(t,e)=>{let s=0,r=new Set;for(let o of t){let i=o[e];r.has(i)||(r.add(i),t[s++]=o)}return t.length=s,t};static subtract(t,e,s){return t.filter(r=>!e.some(o=>s(r,o)))}static intersect(t,e,s){return t.filter(r=>e.some(o=>s(r,o)))}static merge(t,e,s){return[...t.filter(r=>!e.some(o=>s(r,o))),...e]}static*iterate(t){for(let e=0;e<t.length;e++)yield t[e]}static*iterateReverse(t){for(let e=t.length-1;e>=0;e--)yield t[e]}static*iterateStateFull(t){let e=t.length-1;for(let s=0;s<=e;s++)yield{value:t[s],isFirst:s===0,isLast:s===e}}static*iterateAdjacent(t){if(!(t.length<=1))for(let e=1,s=t[0];e<t.length;e++){let r=t[e];yield[s,r],s=r}}static isSorted(t,e=_.Ascending){if(t.length<2)return!0;let s=t[0];for(let r=1;r<t.length;r++){let o=t[r];if(Math.sign(s-o)===e)return!1;s=o}return!0}static toRecord(t,e){return t.reduce((s,r)=>(s[e(r)]=r,s),{})}static concatArrayBuffers(t,e){let s=new ArrayBuffer(t.byteLength+e.byteLength),r=new Uint8Array(s);return r.set(new Uint8Array(t),0),r.set(new Uint8Array(e),t.byteLength),s}};var S=class{static*empty(){}static one(t){return[t]}static count(t){let e=0;for(let s of t)e++;return e}static some(t,e){for(let s of t)if(e(s))return!0;return!1}static every(t,e){for(let s of t)if(!e(s))return!1;return!0}static reduce(t,e,s){let r=s,o=0;for(let i of t)r=e(r,i,o++);return r}static includes(t,e){for(let s of t)if(s===e)return!0;return!1}static forEach(t,e){for(let s of t)e(s)}static*map(t,e){let s=0;for(let r of t)yield e(r,s++)}static*take(t,e){let s=0;for(let r of t){if(s++>=e)return;yield r}}static filter(t,e){let s=[];for(let r of t)e(r)&&s.push(r);return s}static filterMap(t,e){let s=[];for(let r of t){let o=e(r);h(o)&&s.push(o)}return s}static reverse(t){let e=[];for(let s of t)e.push(s);return e.reverse()}static*pairWise(t){let e=t[Symbol.iterator](),{done:s,value:r}=e.next(),o=r;if(s!==!0)for(;;){let{done:i,value:a}=e.next();if(i===!0){yield[o,null];return}yield[o,a],o=a}}};var K=Object.freeze({Empty:{terminate:Y},create:n=>({terminate:n}),many:(...n)=>({terminate:()=>{for(;n.length>0;)n.pop().terminate()}})});var T=class{static subscribeMany(t,...e){return K.many(...e.map(s=>s.subscribe(()=>t(s))))}#t=new Set;subscribe(t){return this.#t.add(t),{terminate:()=>this.#t.delete(t)}}isEmpty(){return this.#t.size===0}notify(t){this.#t.forEach(e=>e(t))}observers(){return this.#t}terminate(){this.#t.clear()}};var O=class n{static createEstimator=()=>{let t=performance.now(),e=n.millis(Number.POSITIVE_INFINITY),s=0;return r=>{if(r===0)return n.POSITIVE_INFINITY;if(r>=1)return n.millis(0);let o=performance.now()-t;return o>s*1e3&&(e=n.millis(o/r-o),s++),e}};static POSITIVE_INFINITY=new n(Number.POSITIVE_INFINITY);static millis=t=>new n(t);static seconds=t=>new n(t*n.#t);static minutes=t=>new n(t*n.#e);static hours=t=>new n(t*n.#r);static days=t=>new n(t*n.#o);static toHHMMSS=t=>((t/3600|0)+100).toString().slice(1)+":"+((t/60|0)%60+100).toString().slice(1)+":"+(t%60+100).toString().slice(1);static#t=1e3;static#e=6e4;static#r=36e5;static#o=864e5;#s;constructor(t){this.#s=t}millis(){return this.#s}absSeconds(){return Math.abs(this.#s)/n.#t}absMinutes(){return Math.abs(this.#s)/n.#e}absHours(){return Math.abs(this.#s)/n.#r}absDays(){return Math.abs(this.#s)/n.#o}split(){return{d:Math.floor(this.absDays()),h:Math.floor(this.absHours())%24,m:Math.floor(this.absMinutes())%60,s:Math.floor(this.absSeconds())%60}}isNow(){return this.#s===0}isPast(){return this.#s<0}isFuture(){return this.#s>0}toUnitString(){let t,e,s=Math.floor(Math.abs(this.#s)/1e3),r=Math.floor(s/60),o=Math.floor(r/60),i=Math.floor(o/24);return s<60?(t=s,e="second"):r<60?(t=r,e="minute"):o<24?(t=o,e="hour"):(t=i,e="day"),new Intl.RelativeTimeFormat("en",{numeric:"auto",style:"long"}).format(t*Math.sign(this.#s),e)}toString(){if(isNaN(this.#s))return"NaN";if(!isFinite(this.#s))return"\u221E";let{d:t,h:e,m:s,s:r}=this.split();return t>0?[n.#n("d",t),n.#n("h",e),n.#n("m",s),n.#n("s",r)].join(", "):e>0?[n.#n("h",e),n.#n("m",s),n.#n("s",r)].join(", "):s>0?[n.#n("m",s),n.#n("s",r)].join(", "):r>0?n.#n("s",r):"now"}static#n=(t,e)=>{switch(t){case"d":return`${e} ${e<2?"day":"days"}`;case"h":return`${e} ${e<2?"hour":"hours"}`;case"m":return`${e} ${e<2?"minute":"minutes"}`;case"s":return`${e} ${e<2?"second":"seconds"}`;default:return z(t)}}};var F;(function(n){n.sender=(r,o)=>o(new e(r)),n.executor=(r,o)=>new s(r,o);let t=r=>{let o=[];for(let i of r)i instanceof MessagePort&&o.push(i),typeof ImageBitmap<"u"&&i instanceof ImageBitmap&&o.push(i),typeof OffscreenCanvas<"u"&&i instanceof OffscreenCanvas&&o.push(i);return o};class e{#t;#e=new Map;#r;#o=0;constructor(o){this.#t=o,this.#r=o.subscribe(this.#s)}terminate(){this.#r.terminate()}dispatchAndForget=(o,...i)=>{let a=t(i);this.#t.send({type:"send",returnId:!1,func:o.name,args:Array.from(S.map(i,c=>({value:c})))},a)};dispatchAndReturn=(o,...i)=>new Promise((a,c)=>{let l=S.reduce(i,(u,v,d)=>(typeof v=="function"&&u.push([d,v]),u),[]);this.#e.set(this.#o,{executorTuple:{resolve:a,reject:c},callbacks:new Map(l)});let f=t(i);this.#t.send({type:"send",returnId:this.#o,func:o.name,args:Array.from(S.map(i,(u,v)=>typeof u=="function"?{callback:v}:{value:u}))},f),this.#o++});#s=o=>{let i=this.#e.get(o.returnId);h(i)?o.type==="resolve"?(i.executorTuple.resolve(o.resolve),this.#e.delete(o.returnId)):o.type==="reject"?(i.executorTuple.reject(o.reject),this.#e.delete(o.returnId)):o.type==="callback"&&i.callbacks?.get(o.funcAt).apply(this,o.args):p(`Promise has already been resolved. ${JSON.stringify(o)}`)}}class s{#t;#e;#r;constructor(o,i){this.#t=o,this.#e=i,this.#r=o.subscribe(this.#o)}terminate(){this.#r.terminate()}#o=o=>{q(o.type==="send",()=>"Message type must be 'send'");let i=Object.getPrototypeOf(this.#e)===Object.getPrototypeOf({})?this.#e:Object.getPrototypeOf(this.#e),a=x(i[o.func],`${o.func.toString()} does not exists on ${this.#e}`),c=o.returnId;if(c===!1)a.apply(this.#e,o.args.map(l=>"value"in l?l.value:p(`${o.func.toString()} has no promise.`)));else try{a.apply(this.#e,o.args.map(f=>"callback"in f?(...u)=>this.#i(c,f.callback,u):f.value)).then(f=>{try{this.#s(c,f)}catch(u){this.#n(c,u)}},f=>this.#n(c,f))}catch(l){this.#n(c,l)}};#s=(o,i)=>this.#t.send({type:"resolve",returnId:o,resolve:i});#n=(o,i)=>this.#t.send({type:"reject",returnId:o,reject:i});#i=(o,i,a)=>this.#t.send({type:"callback",returnId:o,funcAt:i,args:a})}n.Executor=s})(F||(F={}));var W={for:n=>new D(n)},rt=[],D=class{#t;#e=new T;constructor(t){if(this.#t=t,h(t.onmessage)||h(t.onmessageerror))throw console.error(t),new Error(`${t} is already wrapped.`);t.onmessage=e=>this.#e.notify(e.data),t.onmessageerror=e=>{throw new Error(e.type)}}send(t,e){this.#t.postMessage(t,e??rt)}channel(t){return new k(this,t)}subscribe(t){return this.#e.subscribe(t)}terminate(){this.#e.terminate(),this.#t.onmessage=null,this.#t.onmessageerror=null}},k=class n{#t;#e;#r=new T;#o;constructor(t,e){this.#t=t,this.#e=e,this.#o=t.subscribe(s=>{"__id__"in s&&s.__id__==="42"&&"message"in s&&"channel"in s&&s.channel===e&&this.#r.notify(s.message)})}send(t,e){this.#t.send({__id__:"42",channel:this.#e,message:t},e)}channel(t){return new n(this,t)}subscribe(t){return this.#r.subscribe(t)}terminate(){this.#o.terminate(),this.#r.terminate()}};var N;(function(n){n.frame=()=>new Promise(t=>requestAnimationFrame(()=>t())),n.frames=t=>new Promise(e=>{let s=t,r=()=>{--s<=0?e():requestAnimationFrame(r)};requestAnimationFrame(r)}),n.timeSpan=(t,...e)=>new Promise(s=>setTimeout(s,t.millis(),...e)),n.event=(t,e)=>new Promise(s=>t.addEventListener(e,s,{once:!0})),n.observable=t=>new Promise(e=>{let s=t.subscribe(()=>{s.terminate(),e()})}),n.complete=t=>new Promise((e,s)=>{let r=setInterval(()=>{let{status:o,value:i,error:a}=G(()=>t.next());if(o==="success"){let{done:c,value:l}=i;c&&(clearInterval(r),e(l))}else clearInterval(r),s(a)},0)})})(N||(N={}));var C=(n,t)=>Math.floor(3840/t)*n,Z=(n,t=4,e=4)=>{let s=C(1,e),r=Math.floor(n/s),o=Math.floor(r/t),a=(Math.floor(n)-C(o*t,e))%s,c=Math.floor(a/240),l=a%240;return{bars:o,beats:r-o*t,semiquavers:c,ticks:l}},J=(n,t)=>n*t/60*960,X=(n,t)=>n*60/960/t,ot=(n,t)=>t*60/960/n,it=(n,t,e)=>J(n/e,t),at=(n,t,e)=>X(n,t)*e,tt={Bar:3840,Quarter:960,SemiQuaver:240,fromSignature:C,toParts:Z,secondsToPulses:J,pulsesToSeconds:X,secondsToBpm:ot,samplesToPulses:it,pulsesToSamples:at,toString:(n,t=4,e=4)=>{let{bars:s,beats:r,semiquavers:o,ticks:i}=Z(n|0,t,e);return`${s+1}.${r+1}.${o+1}:${i}`}};var I=128,Ot=tt.fromSignature(1,48);var ct=Math.log(10)/20;var et=n=>Math.exp(n*ct);var L=class{port;constructor(){this.port=globalThis.__workletPort__}};function st(n){let t=globalThis;t.sampleRate=n.sampleRate,t.currentFrame=0,t.currentTime=0,t.AudioWorkletProcessor=L,t.registerProcessor=(e,s)=>{t.__registeredProcessors__=t.__registeredProcessors__||{},t.__registeredProcessors__[e]=s}}function R(n,t){let e=globalThis;e.currentFrame=n,e.currentTime=n/t}var B=null,Q=null,y=48e3,w=2,j=!1,m=0;F.executor(W.for(self).channel("offline-engine"),{async initialize(n,t,e){y=e.sampleRate,w=e.numberOfChannels,Q=t,m=0,st({sampleRate:y}),globalThis.__workletPort__=n,await import(e.processorsUrl);let s=globalThis.__registeredProcessors__["engine-processor"];B=new s({processorOptions:{syncStreamBuffer:e.syncStreamBuffer,controlFlagsBuffer:e.controlFlagsBuffer,project:e.project,exportConfiguration:e.exportConfiguration}})},async step(n){let t=b.create(()=>new Float32Array(n),w),e=b.create(()=>new Float32Array(I),w),s=0;for(;s<n;){let r=[e];R(m,y),B.process([[]],r),m+=I;let o=n-s,i=Math.min(o,I);for(let a=0;a<w;a++)t[a].set(r[0][a].subarray(0,i),s);s+=i}return t},async render(n){let{silenceThresholdDb:t,silenceDurationSeconds:e,maxDurationSeconds:s}=n,r=et(t??-72),o=Math.ceil((e??10)*y),i=h(s)?Math.ceil(s*y):1/0,a=b.create(()=>[],w),c=0,l=!1,f=0;for(j=!0,await N.timeSpan(O.seconds(0));j&&m<i;){let d=[b.create(()=>new Float32Array(I),w)];R(m,y);let P=B.process([[]],d),M=0;for(let g of d[0])for(let nt of g){let H=Math.abs(nt);H>M&&(M=H)}let E=M<=r;if(M>r&&(l=!0),E&&l){if(c+=I,c>=o)break}else c=0;for(let g=0;g<w;g++)a[g].push(d[0][g].slice());if(m+=I,!P)break;m-f>=y&&(f=m,h(Q)&&Q.postMessage({frames:m}),await new Promise(g=>setTimeout(g,0)))}let u=m-c+Math.min(y/4,c);return b.create(v=>{let d=new Float32Array(u),P=0;for(let M of a[v]){if(P>=u)break;let E=Math.min(M.length,u-P);d.set(M.subarray(0,E),P),P+=E}return d},w)},stop(){j=!1}});
2
2
  //# sourceMappingURL=offline-engine.js.map