moontide-mcp 2.0.1 → 2.1.0

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 (46) hide show
  1. package/README.md +44 -6
  2. package/dist/ask.js +30 -8
  3. package/dist/mcp.js +60 -14
  4. package/dist/protocol.js +89 -2
  5. package/dist/reference.js +22 -0
  6. package/dist/session.js +53 -0
  7. package/package.json +1 -1
  8. package/page/ask-view.js +21 -7
  9. package/page/ask.js +292 -34
  10. package/page/change-timing.js +25 -4
  11. package/page/harmony.js +13 -0
  12. package/page/index.html +4 -3
  13. package/page/jam-model.js +11 -2
  14. package/page/jam-view.js +17 -0
  15. package/page/lights.js +278 -0
  16. package/page/main.js +1723 -140
  17. package/page/midi-clock.js +1 -1
  18. package/page/midi-out.js +12 -0
  19. package/page/mixer-groups.js +114 -0
  20. package/page/mixer-model.js +172 -29
  21. package/page/mixer-rewrite.js +30 -1
  22. package/page/mixer-view.js +282 -13
  23. package/page/note-edit.js +267 -0
  24. package/page/note-locate.js +346 -0
  25. package/page/note-panel.js +381 -0
  26. package/page/note-tag.js +126 -0
  27. package/page/page-rewrite.js +184 -0
  28. package/page/song-edit.js +230 -0
  29. package/page/song-fit.js +250 -0
  30. package/page/song-grid-model.js +491 -0
  31. package/page/song-grid-view.js +710 -0
  32. package/page/song-prefs.js +100 -0
  33. package/page/structure-check.js +216 -0
  34. package/page/structure-view.js +38 -0
  35. package/page/structure.js +760 -0
  36. package/page/style.css +879 -84
  37. package/page/takeover.js +20 -5
  38. package/page/timeline-edit-view.js +1956 -0
  39. package/page/timeline-gesture.js +279 -0
  40. package/page/timeline.js +196 -3
  41. package/page/tracks.js +37 -8
  42. package/page/ui-state.js +10 -5
  43. package/page/views.js +25 -8
  44. package/reference/functions.md +1 -0
  45. package/reference/midi.md +2 -0
  46. package/reference/structure.md +131 -0
package/page/takeover.js CHANGED
@@ -64,7 +64,7 @@ export function gatePattern(oldPattern, newPattern, boundary, { TimeSpan, leadCy
64
64
  * The waiting change of the page: one record at most (a newer change replaces it, last wins). The factory
65
65
  * only keeps the record and calls the injected hooks; the page decides what follows the takeover.
66
66
  * getScheduler() -> the scheduler (started, pattern, cps, lastEnd), getTypes() -> { TimeSpan },
67
- * getTiming() -> the parsed timing of the change being evaluated ({ at, lineLength }),
67
+ * getTiming() -> the parsed timing of the change being evaluated ({ at, lineLength }, plus atCycle when the change is written for one given line),
68
68
  * getCps() -> the tempo that plays now (cycles per second), for the line and the lead hook; the scheduler's own cps
69
69
  * by default, but a program's setcps has already reached the scheduler when a change is armed, so the page gives the
70
70
  * tempo from before the evaluation,
@@ -138,18 +138,29 @@ export function createTakeover({
138
138
  }
139
139
 
140
140
  return {
141
- /** null when the change takes over at once; otherwise { boundary }. Changes no state. */
141
+ /**
142
+ * null when the change takes over at once; otherwise { boundary }. A timing that carries `atCycle` (a change written
143
+ * for one given line, see pinnedTiming) takes that line while it is still at least MIN_TAKEOVER_LEAD_SECONDS ahead
144
+ * of the scheduler frontier: { boundary: atCycle, pinned: true }; once it is closer, the next line of the timing's
145
+ * own length is taken and the result says { pinned: false }, so the caller can write its change again for that line.
146
+ * Changes no state.
147
+ */
142
148
  plan() {
143
149
  const timing = getTiming();
144
150
  if (timing.at === 'now' || !isPlaying()) return null;
145
151
  const scheduler = getScheduler();
152
+ const cps = getCps();
153
+ const pinnedLine = timing.atCycle;
154
+ if (pinnedLine !== undefined && (pinnedLine - scheduler.lastEnd) / cps >= MIN_TAKEOVER_LEAD_SECONDS) {
155
+ return { boundary: pinnedLine, pinned: true };
156
+ }
146
157
  const boundary = boundaryCycle({
147
158
  frontier: scheduler.lastEnd,
148
- cps: getCps(),
159
+ cps,
149
160
  lineLength: timing.lineLength,
150
161
  minLeadSeconds: MIN_TAKEOVER_LEAD_SECONDS,
151
162
  });
152
- return { boundary };
163
+ return pinnedLine === undefined ? { boundary } : { boundary, pinned: false };
153
164
  },
154
165
 
155
166
  /**
@@ -242,7 +253,11 @@ export function createTakeover({
242
253
  record.finishers.push(fn);
243
254
  },
244
255
 
245
- /** Drops the waiting record (no-op without one); its continuations never run. */
256
+ /**
257
+ * Drops the waiting record (no-op without one); its continuations never run. `reason` says why: 'stop' (the sound
258
+ * stopped), 'replaced' (a newer change took its place), 'superseded' and 'unload' (this tab lost its role or closes) and
259
+ * 'canceled', the person's own cancel of a waiting section launch.
260
+ */
246
261
  cancel,
247
262
 
248
263
  /** The poll fallback: finishes the waiting record when the scheduler's cycle has reached its boundary. */