alphatheta-connect 0.25.3 → 0.26.1

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/lib/index.js CHANGED
@@ -1356,7 +1356,9 @@ async function viaLocal(local, opts) {
1356
1356
  if (!orm) {
1357
1357
  break;
1358
1358
  }
1359
- yield orm.findTrack(entry.id);
1359
+ // Playlist entries reference the track through trackId; entry.id is the
1360
+ // entry's own row id (or its index, for OneLibrary), not a track.
1361
+ yield orm.findTrack(entry.trackId);
1360
1362
  }
1361
1363
  };
1362
1364
  const tracks = { [Symbol.asyncIterator]: iterateTracks };
@@ -3255,7 +3257,9 @@ var RekordboxAnlz = (function() {
3255
3257
  this.time = this._io.readU4be();
3256
3258
  this.loopTime = this._io.readU4be();
3257
3259
  this.colorId = this._io.readU1();
3258
- this._unnamed9 = this._io.readBytes(11);
3260
+ this._unnamed9 = this._io.readBytes(7);
3261
+ this.loopNumerator = this._io.readU2be();
3262
+ this.loopDenominator = this._io.readU2be();
3259
3263
  if (this.lenEntry > 43) {
3260
3264
  this.lenComment = this._io.readU4be();
3261
3265
  }
@@ -3275,7 +3279,7 @@ var RekordboxAnlz = (function() {
3275
3279
  this.colorBlue = this._io.readU1();
3276
3280
  }
3277
3281
  if ((this.lenEntry - this.lenComment) > 48) {
3278
- this._unnamed16 = this._io.readBytes(((this.lenEntry - 48) - this.lenComment));
3282
+ this._unnamed18 = this._io.readBytes(((this.lenEntry - 48) - this.lenComment));
3279
3283
  }
3280
3284
  }
3281
3285
 
@@ -3307,6 +3311,16 @@ var RekordboxAnlz = (function() {
3307
3311
  * and has been assigned a color.
3308
3312
  */
3309
3313
 
3314
+ /**
3315
+ * The numerator of the loop size fraction for a quantized loop,
3316
+ * e.g. 4 for a 4-beat loop. Zero when the loop is not quantized.
3317
+ */
3318
+
3319
+ /**
3320
+ * The denominator of the loop size fraction for a quantized loop,
3321
+ * e.g. 1 for a 4-beat loop.
3322
+ */
3323
+
3310
3324
  /**
3311
3325
  * The comment assigned to this cue by the DJ, if any, with a trailing NUL.
3312
3326
  */
@@ -5760,16 +5774,20 @@ function makeBeatGrid(data) {
5760
5774
  * Fill cue and loop data from the ANLZ section
5761
5775
  */
5762
5776
  function makeCueAndLoop(data) {
5763
- return data.body.cues.map((entry) => {
5777
+ return data.body.cues
5778
+ .map((entry) => {
5764
5779
  // Cues with the status 0 are likely leftovers that were removed
5765
- const button = entry.hotCue === 0 ? false : entry.type;
5780
+ // `hotCue` is the button number (1-8, A-H); zero marks a memory cue.
5781
+ // `type` only says whether the entry is a cue point (1) or a loop (2).
5782
+ const button = entry.hotCue === 0 ? false : entry.hotCue;
5766
5783
  const isCue = entry.type === 0x01;
5767
5784
  const isLoop = entry.type === 0x02;
5768
5785
  // NOTE: Unlike the remotedb, these entries are already in milliseconds.
5769
5786
  const offset = entry.time;
5770
5787
  const length = entry.loopTime - offset;
5771
5788
  return (0, utils_1.makeCueLoopEntry)(isCue, isLoop, offset, length, button);
5772
- });
5789
+ })
5790
+ .filter((c) => c !== null);
5773
5791
  }
5774
5792
  /**
5775
5793
  * Fill waveform HD data from the ANLZ section
@@ -5805,9 +5823,13 @@ function makeExtendedCues(data) {
5805
5823
  b: (_c = entry.colorBlue) !== null && _c !== void 0 ? _c : 0,
5806
5824
  };
5807
5825
  }
5808
- // Add comment if present
5826
+ // Add comment if present. The tag stores it with a trailing NUL, which
5827
+ // is not part of what the DJ typed.
5809
5828
  if (entry.lenComment > 0 && entry.comment) {
5810
- cue.comment = entry.comment;
5829
+ const comment = entry.comment.replace(/\0+$/, '');
5830
+ if (comment.length > 0) {
5831
+ cue.comment = comment;
5832
+ }
5811
5833
  }
5812
5834
  // Add quantized loop information if present
5813
5835
  if (entry.loopNumerator !== undefined && entry.loopNumerator > 0) {
@@ -5873,19 +5895,24 @@ function makeSongStructure(data) {
5873
5895
  },
5874
5896
  };
5875
5897
  const mood = (_a = moodMap[data.body.mood]) !== null && _a !== void 0 ? _a : 'high';
5876
- const bank = (_b = bankMap[data.body.rawBank]) !== null && _b !== void 0 ? _b : 'default';
5898
+ const bank = (_b = bankMap[data.body.bank]) !== null && _b !== void 0 ? _b : 'default';
5899
+ // Field names follow the Kaitai-generated object (rekordbox_anlz.ksy
5900
+ // `song_structure_entry`): `phraseNumber`, `beatNumber`, `fillIn`,
5901
+ // `fillInBeatNumber`, and `kind` is a `phrase_high` / `phrase_mid` /
5902
+ // `phrase_low` object whose `id` carries the raw kind value.
5877
5903
  const phrases = data.body.entries.map((entry) => {
5878
5904
  var _a;
5905
+ const kind = typeof entry.kind === 'object' ? entry.kind.id : entry.kind;
5879
5906
  const phrase = {
5880
- index: entry.index,
5881
- beat: entry.beat,
5882
- kind: entry.kind,
5883
- phraseType: (_a = phraseTypeMap[mood][entry.kind]) !== null && _a !== void 0 ? _a : 'Unknown',
5907
+ index: entry.phraseNumber,
5908
+ beat: entry.beatNumber,
5909
+ kind,
5910
+ phraseType: (_a = phraseTypeMap[mood][kind]) !== null && _a !== void 0 ? _a : 'Unknown',
5884
5911
  };
5885
5912
  // Add fill-in information if present
5886
- if (entry.fill > 0) {
5887
- phrase.fill = entry.fill;
5888
- phrase.fillBeat = entry.beatFill;
5913
+ if (entry.fillIn > 0) {
5914
+ phrase.fill = entry.fillIn;
5915
+ phrase.fillBeat = entry.fillInBeatNumber;
5889
5916
  }
5890
5917
  return phrase;
5891
5918
  });
@@ -7187,7 +7214,12 @@ class ProlinkNetwork {
7187
7214
  }
7188
7215
  const tx = Telemetry.startTransaction({ name: 'connect' });
7189
7216
  const connectMethod = (_a = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").connectMethod) !== null && _a !== void 0 ? _a : 'active';
7217
+ // Pick the device number once and keep it. A CDJ-3000 that already holds
7218
+ // a record for our IP ignores a re-claim under a different number, so a
7219
+ // disconnect/connect cycle must present the same identity (see
7220
+ // getStagehandMac).
7190
7221
  const vcdjId = (_b = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjId) !== null && _b !== void 0 ? _b : (connectMethod === 'stagehand' ? (0, virtualcdj_1.generateStagehandDeviceId)() : constants_1.DEFAULT_VCDJ_ID);
7222
+ __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjId = vcdjId;
7191
7223
  const vcdjName = (_c = __classPrivateFieldGet(this, _ProlinkNetwork_config, "f").vcdjName) !== null && _c !== void 0 ? _c : (connectMethod === 'stagehand' ? 'Stagehand' : undefined);
7192
7224
  // Create VCDJ or Stagehand device
7193
7225
  const vcdj = connectMethod === 'stagehand'
@@ -14146,7 +14178,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
14146
14178
  var _StagehandAnnouncer_instances, _StagehandAnnouncer_announceSocket, _StagehandAnnouncer_vcdj, _StagehandAnnouncer_intervalHandle, _StagehandAnnouncer_currentStage, _StagehandAnnouncer_stageCounter, _StagehandAnnouncer_iface, _StagehandAnnouncer_logger, _StagehandAnnouncer_onStartupComplete, _StagehandAnnouncer_mac, _StagehandAnnouncer_startStartup, _StagehandAnnouncer_sendPacket, _StagehandAnnouncer_sendStagePackets, _StagehandAnnouncer_advanceStage, _StagehandAnnouncer_startKeepAlive;
14147
14179
  Object.defineProperty(exports, "__esModule", ({ value: true }));
14148
14180
  exports.StagehandAnnouncer = exports.getVirtualStagehand = exports.StagehandStartupStage = exports.STAGEHAND_KEEP_ALIVE_INTERVAL = exports.STAGEHAND_STARTUP_INTERVAL = void 0;
14149
- exports.generateStagehandMac = generateStagehandMac;
14181
+ exports.getStagehandMac = getStagehandMac;
14150
14182
  exports.generateStagehandDeviceId = generateStagehandDeviceId;
14151
14183
  exports.makeStagehand0aPacket = makeStagehand0aPacket;
14152
14184
  exports.makeStagehand02Packet = makeStagehand02Packet;
@@ -14165,17 +14197,21 @@ var StagehandStartupStage;
14165
14197
  StagehandStartupStage[StagehandStartupStage["KeepAlive"] = 6] = "KeepAlive";
14166
14198
  })(StagehandStartupStage || (exports.StagehandStartupStage = StagehandStartupStage = {}));
14167
14199
  /**
14168
- * Generates a randomized MAC address with the AlphaTheta OUI (c8:3d:fc).
14200
+ * The protocol-layer MAC a Stagehand device embeds in its 0x02 claim and 0x06
14201
+ * keep-alive: the AlphaTheta OUI (c8:3d:fc) followed by the low three bytes of
14202
+ * the interface's own MAC.
14203
+ *
14204
+ * This must stay stable for the life of the host. A CDJ-3000 records a peer by
14205
+ * the identity in its claim, and once it holds a record for our IP it ignores
14206
+ * later claims from the same IP that carry a different MAC or device number:
14207
+ * the new peer never receives the unicast status/position stream. Observed on
14208
+ * emulated CDJ-3000 firmware 3.20: a freshly randomized identity on every
14209
+ * connect() was served once and then never again until the player rebooted,
14210
+ * while the previously registered identity kept being served immediately.
14169
14211
  */
14170
- function generateStagehandMac() {
14171
- const mac = new Uint8Array(6);
14172
- mac[0] = 0xc8;
14173
- mac[1] = 0x3d;
14174
- mac[2] = 0xfc;
14175
- mac[3] = Math.floor(Math.random() * 256);
14176
- mac[4] = Math.floor(Math.random() * 256);
14177
- mac[5] = Math.floor(Math.random() * 256);
14178
- return mac;
14212
+ function getStagehandMac(iface) {
14213
+ const ifaceMac = iface.mac.split(':').map(s => parseInt(s, 16));
14214
+ return Uint8Array.from([0xc8, 0x3d, 0xfc, ...ifaceMac.slice(3, 6)]);
14179
14215
  }
14180
14216
  /**
14181
14217
  * Generates a random Stagehand device ID in the observed range of 141 to 211.
@@ -14189,9 +14225,9 @@ function generateStagehandDeviceId() {
14189
14225
  * @param iface - The network interface to use
14190
14226
  * @param id - The device ID to use (defaults to random Stagehand ID)
14191
14227
  * @param name - The device name (defaults to 'Stagehand')
14192
- * @param macAddr - The optional randomized MAC address
14228
+ * @param macAddr - The protocol-layer MAC (defaults to one derived from iface)
14193
14229
  */
14194
- const getVirtualStagehand = (iface, id = generateStagehandDeviceId(), name = 'Stagehand', macAddr = generateStagehandMac()) => ({
14230
+ const getVirtualStagehand = (iface, id = generateStagehandDeviceId(), name = 'Stagehand', macAddr = getStagehandMac(iface)) => ({
14195
14231
  id,
14196
14232
  name,
14197
14233
  type: types_1.DeviceType.Stagehand,