@ugfoundation/swaralipi-js 0.7.5 → 0.7.7

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 (41) hide show
  1. package/dist/{batch-DLPDVNFK.js → batch-6MCPHHKF.js} +5 -5
  2. package/dist/{batch-DLPDVNFK.js.map → batch-6MCPHHKF.js.map} +1 -1
  3. package/dist/{chunk-YAXYP7BR.js → chunk-ALN4SWMS.js} +3 -3
  4. package/dist/{chunk-YAXYP7BR.js.map → chunk-ALN4SWMS.js.map} +1 -1
  5. package/dist/{chunk-UF5OSJRP.js → chunk-QM4CXKW2.js} +11 -3
  6. package/dist/chunk-QM4CXKW2.js.map +1 -0
  7. package/dist/{chunk-ZAK3QRDN.js → chunk-QQC6WVLJ.js} +4 -4
  8. package/dist/{chunk-ZAK3QRDN.js.map → chunk-QQC6WVLJ.js.map} +1 -1
  9. package/dist/{chunk-2SAZWTTK.js → chunk-TKTQCUKD.js} +5 -5
  10. package/dist/chunk-TKTQCUKD.js.map +1 -0
  11. package/dist/cli.cjs +1 -1
  12. package/dist/cli.cjs.map +1 -1
  13. package/dist/cli.js +3 -3
  14. package/dist/convert/index.cjs +1 -1
  15. package/dist/convert/index.cjs.map +1 -1
  16. package/dist/convert/index.js +3 -3
  17. package/dist/index.cjs +11 -1
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +1 -1
  20. package/dist/index.d.ts +1 -1
  21. package/dist/index.js +2 -2
  22. package/dist/player/index.cjs +41 -7
  23. package/dist/player/index.cjs.map +1 -1
  24. package/dist/player/index.d.cts +15 -1
  25. package/dist/player/index.d.ts +15 -1
  26. package/dist/player/index.js +34 -8
  27. package/dist/player/index.js.map +1 -1
  28. package/dist/spec/index.cjs +11 -1
  29. package/dist/spec/index.cjs.map +1 -1
  30. package/dist/spec/index.d.cts +18 -4
  31. package/dist/spec/index.d.ts +18 -4
  32. package/dist/spec/index.js +2 -2
  33. package/dist/viewer/index.cjs +21 -5
  34. package/dist/viewer/index.cjs.map +1 -1
  35. package/dist/viewer/index.d.cts +0 -27
  36. package/dist/viewer/index.d.ts +0 -27
  37. package/dist/viewer/index.js +3 -4
  38. package/dist/viewer/index.js.map +1 -1
  39. package/package.json +1 -1
  40. package/dist/chunk-2SAZWTTK.js.map +0 -1
  41. package/dist/chunk-UF5OSJRP.js.map +0 -1
@@ -54,7 +54,8 @@ interface PlayerOptions {
54
54
  * `requestAnimationFrame`, which stops the moment a screen locks, so anything
55
55
  * hanging off it freezes until the reader looks at the page again. Use this for
56
56
  * consumers that are not drawing (media-session metadata, analytics); it fires
57
- * up to one lookahead (~0.1s) early and only in doc mode. */
57
+ * early — one transport lookahead (~0.1s) plus MEDIA_LEAD_SEC — and only in
58
+ * doc mode. */
58
59
  onEvent?: (path: string | null) => void;
59
60
  /** Taal mode only (`loadTaal`): called on the draw thread once per matra with
60
61
  * the beat index within the cycle (0-based, `< numBeats`), so a consumer can
@@ -92,6 +93,19 @@ declare class SwaralipiPlayer {
92
93
  get taalId(): TaalId | undefined;
93
94
  /** Whether the effective rhythm will actually be a sampled tabla. */
94
95
  get usesTabla(): boolean;
96
+ /**
97
+ * Length of one play-through in seconds, for a progress bar (the OS media
98
+ * session's, typically). Derived from the loaded notation on every read and
99
+ * never stored, because every input can move: re-engrave the document, drag
100
+ * the tempo, switch the rhythm off, and this changes with it. `Infinity` in
101
+ * taal mode (one avartan looping, no end — the value the Media Session spec
102
+ * reserves for exactly that), 0 with nothing loaded, and clamped by a preview
103
+ * cap when one is set, since that is when playback will really stop.
104
+ */
105
+ get durationSec(): number;
106
+ /** Seconds played so far, off the Transport's own clock — so it holds while
107
+ * paused, and reads 0 before the first play and after stop(). */
108
+ get positionSec(): number;
95
109
  /** Set the document to play. Stops any current playback. */
96
110
  load(doc: Swaralipi): void;
97
111
  /**
@@ -54,7 +54,8 @@ interface PlayerOptions {
54
54
  * `requestAnimationFrame`, which stops the moment a screen locks, so anything
55
55
  * hanging off it freezes until the reader looks at the page again. Use this for
56
56
  * consumers that are not drawing (media-session metadata, analytics); it fires
57
- * up to one lookahead (~0.1s) early and only in doc mode. */
57
+ * early — one transport lookahead (~0.1s) plus MEDIA_LEAD_SEC — and only in
58
+ * doc mode. */
58
59
  onEvent?: (path: string | null) => void;
59
60
  /** Taal mode only (`loadTaal`): called on the draw thread once per matra with
60
61
  * the beat index within the cycle (0-based, `< numBeats`), so a consumer can
@@ -92,6 +93,19 @@ declare class SwaralipiPlayer {
92
93
  get taalId(): TaalId | undefined;
93
94
  /** Whether the effective rhythm will actually be a sampled tabla. */
94
95
  get usesTabla(): boolean;
96
+ /**
97
+ * Length of one play-through in seconds, for a progress bar (the OS media
98
+ * session's, typically). Derived from the loaded notation on every read and
99
+ * never stored, because every input can move: re-engrave the document, drag
100
+ * the tempo, switch the rhythm off, and this changes with it. `Infinity` in
101
+ * taal mode (one avartan looping, no end — the value the Media Session spec
102
+ * reserves for exactly that), 0 with nothing loaded, and clamped by a preview
103
+ * cap when one is set, since that is when playback will really stop.
104
+ */
105
+ get durationSec(): number;
106
+ /** Seconds played so far, off the Transport's own clock — so it holds while
107
+ * paused, and reads 0 before the first play and after stop(). */
108
+ get positionSec(): number;
95
109
  /** Set the document to play. Stops any current playback. */
96
110
  load(doc: Swaralipi): void;
97
111
  /**
@@ -1,9 +1,10 @@
1
- import { DEFAULT_SOUNDS_BASE, INSTRUMENTS, SAMPLED_TAALS, instrumentSampleUrl, probeUrl, normalizeBase, nearestTablaBpm, tablaBpms, buildSchedule, quantizeLoopEnd, midiToSampleName, glideTargets, triggerGlide, createSampler, createBuffers, tablaUrl, tablaShiftSemitones, TABLA_GRAIN_OVERLAP_SEC, TABLA_GRAIN_SEC, createDrumKit, drumPattern, createMetronome, TANPURA_PCS, createTanpura, parseTonic, MEEND_HOLD, sCurve } from '../chunk-2SAZWTTK.js';
2
- export { ARC_RAW_RE, DEFAULT_SOUNDS_BASE, DRUM_KIT_BASE, INSTRUMENTS, MEEND_HOLD, OCTAVE_OFFSET, SALAMANDER_BASE, SAMPLED_TAALS, SHUDDHA, TABLA_BPMS, TABLA_VARIATIONS, TONEJS_INSTRUMENTS_BASE, buildSchedule, createBuffers, drumPattern, glideTargets, instrumentSampleUrl, isArcRaw, meendContinuations, midiToSampleName, nearestSampleKey, nearestTablaBpm, normalizeBase, parseTonic, probeUrl, quantizeLoopEnd, sCurve, sampleFileName, santoorUrls, subsetUrls, svaraSemitone, svaraToMidi, tablaBpms, tablaUrl, triggerGlide } from '../chunk-2SAZWTTK.js';
3
- import { TAALS } from '../chunk-UF5OSJRP.js';
1
+ import { DEFAULT_SOUNDS_BASE, INSTRUMENTS, SAMPLED_TAALS, buildSchedule, instrumentSampleUrl, probeUrl, normalizeBase, nearestTablaBpm, tablaBpms, quantizeLoopEnd, midiToSampleName, glideTargets, triggerGlide, createSampler, createBuffers, tablaUrl, tablaShiftSemitones, TABLA_GRAIN_OVERLAP_SEC, TABLA_GRAIN_SEC, createDrumKit, drumPattern, createMetronome, TANPURA_PCS, createTanpura, parseTonic, MEEND_HOLD, sCurve } from '../chunk-TKTQCUKD.js';
2
+ export { ARC_RAW_RE, DEFAULT_SOUNDS_BASE, DRUM_KIT_BASE, INSTRUMENTS, MEEND_HOLD, OCTAVE_OFFSET, SALAMANDER_BASE, SAMPLED_TAALS, SHUDDHA, TABLA_BPMS, TABLA_VARIATIONS, TONEJS_INSTRUMENTS_BASE, buildSchedule, createBuffers, drumPattern, glideTargets, instrumentSampleUrl, isArcRaw, meendContinuations, midiToSampleName, nearestSampleKey, nearestTablaBpm, normalizeBase, parseTonic, probeUrl, quantizeLoopEnd, sCurve, sampleFileName, santoorUrls, subsetUrls, svaraSemitone, svaraToMidi, tablaBpms, tablaUrl, triggerGlide } from '../chunk-TKTQCUKD.js';
3
+ import { TAALS } from '../chunk-QM4CXKW2.js';
4
4
 
5
5
  // src/player/player.ts
6
6
  var STOP_FADE_SEC = 0.5;
7
+ var MEDIA_LEAD_SEC = 0.25;
7
8
  function midiRange(schedule) {
8
9
  let lo = Infinity;
9
10
  let hi = -Infinity;
@@ -17,6 +18,9 @@ function midiRange(schedule) {
17
18
  }
18
19
  return lo <= hi ? { lo, hi } : void 0;
19
20
  }
21
+ function playDurationSec(schedule, spb, rhythm) {
22
+ return schedule.totalBeats * spb + (rhythm !== "none" ? schedule.pickupBeats * spb : 0) + spb;
23
+ }
20
24
  async function loadedOrWarn(Tone) {
21
25
  try {
22
26
  await Tone.loaded();
@@ -97,6 +101,27 @@ var SwaralipiPlayer = class {
97
101
  const id = this.#taalId();
98
102
  return this.#opts.rhythm === "tabla" && id !== void 0 && SAMPLED_TAALS.has(id) && !!this.#opts.soundsBaseUrl;
99
103
  }
104
+ /**
105
+ * Length of one play-through in seconds, for a progress bar (the OS media
106
+ * session's, typically). Derived from the loaded notation on every read and
107
+ * never stored, because every input can move: re-engrave the document, drag
108
+ * the tempo, switch the rhythm off, and this changes with it. `Infinity` in
109
+ * taal mode (one avartan looping, no end — the value the Media Session spec
110
+ * reserves for exactly that), 0 with nothing loaded, and clamped by a preview
111
+ * cap when one is set, since that is when playback will really stop.
112
+ */
113
+ get durationSec() {
114
+ if (this.#taal !== void 0) return Infinity;
115
+ if (this.#doc === void 0) return 0;
116
+ const schedule = buildSchedule(this.#doc, { tonic: this.#opts.tonic, baseOctave: this.#opts.baseOctave });
117
+ const full = playDurationSec(schedule, 60 / this.#effectiveBpm(), this.#opts.rhythm);
118
+ return Math.min(full, this.#opts.previewLimitSec);
119
+ }
120
+ /** Seconds played so far, off the Transport's own clock — so it holds while
121
+ * paused, and reads 0 before the first play and after stop(). */
122
+ get positionSec() {
123
+ return this.#tone?.getTransport().seconds ?? 0;
124
+ }
100
125
  /* ----------------------------------------------------------------- */
101
126
  /* Loading + transport control */
102
127
  /* ----------------------------------------------------------------- */
@@ -409,6 +434,7 @@ var SwaralipiPlayer = class {
409
434
  }
410
435
  const draw = Tone.getDraw();
411
436
  const shift = this.#opts.rhythm !== "none" ? schedule.pickupBeats * spb : 0;
437
+ const mediaLead = Math.min(MEDIA_LEAD_SEC, spb);
412
438
  schedule.events.forEach((ev, i) => {
413
439
  const at = ev.beat * spb + shift;
414
440
  if (ev.midi !== null && ev.glide !== true) {
@@ -442,12 +468,12 @@ var SwaralipiPlayer = class {
442
468
  transport.scheduleOnce((time) => melody.triggerAttackRelease(name, dur, time), at);
443
469
  }
444
470
  }
445
- transport.scheduleOnce((time) => {
446
- this.#opts.onEvent?.(ev.path);
447
- draw.schedule(() => this.#emitHighlight(ev.path), time);
448
- }, at);
471
+ if (this.#opts.onEvent !== void 0) {
472
+ transport.scheduleOnce(() => this.#opts.onEvent?.(ev.path), Math.max(at - mediaLead, 0));
473
+ }
474
+ transport.scheduleOnce((time) => draw.schedule(() => this.#emitHighlight(ev.path), time), at);
449
475
  });
450
- const endAt = schedule.totalBeats * spb + shift + spb;
476
+ const endAt = playDurationSec(schedule, spb, this.#opts.rhythm);
451
477
  transport.scheduleOnce((time) => {
452
478
  this.#opts.onEvent?.(null);
453
479
  draw.schedule(() => this.#emitHighlight(null), time);