@ugfoundation/swaralipi-js 0.3.2 → 0.3.4
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/dist/{batch-5LFXQ67K.js → batch-Y3HKAL3B.js} +5 -5
- package/dist/{batch-5LFXQ67K.js.map → batch-Y3HKAL3B.js.map} +1 -1
- package/dist/{chunk-YE7UVYRY.js → chunk-6ETPFHZ6.js} +5 -3
- package/dist/chunk-6ETPFHZ6.js.map +1 -0
- package/dist/{chunk-32LOBRC2.js → chunk-AIGSKUD3.js} +3 -3
- package/dist/{chunk-32LOBRC2.js.map → chunk-AIGSKUD3.js.map} +1 -1
- package/dist/{chunk-XQYXZPHK.js → chunk-IG2CIUTP.js} +3 -3
- package/dist/{chunk-XQYXZPHK.js.map → chunk-IG2CIUTP.js.map} +1 -1
- package/dist/{chunk-QVNFEWMM.js → chunk-KPKD53NA.js} +4 -4
- package/dist/{chunk-QVNFEWMM.js.map → chunk-KPKD53NA.js.map} +1 -1
- package/dist/cli.cjs +4 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/convert/index.cjs +4 -2
- package/dist/convert/index.cjs.map +1 -1
- package/dist/convert/index.js +3 -3
- package/dist/index.cjs +4 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/player/index.cjs +70 -11
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +17 -4
- package/dist/player/index.d.ts +17 -4
- package/dist/player/index.js +70 -13
- package/dist/player/index.js.map +1 -1
- package/dist/{schedule-CHXz3V6T.d.cts → schedule-C2WN7YOK.d.cts} +1 -1
- package/dist/{schedule-BaE3JGHe.d.ts → schedule-dXV5cUQI.d.ts} +1 -1
- package/dist/spec/index.cjs +4 -2
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.d.cts +2 -2
- package/dist/spec/index.d.ts +2 -2
- package/dist/spec/index.js +2 -2
- package/dist/{taals-DxJ8wRtF.d.ts → taals-CjzBuZ35.d.cts} +8 -1
- package/dist/{taals-DxJ8wRtF.d.cts → taals-CjzBuZ35.d.ts} +8 -1
- package/dist/viewer/index.cjs +28 -2
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +36 -4
- package/dist/viewer/index.d.ts +36 -4
- package/dist/viewer/index.js +25 -3
- package/dist/viewer/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-YE7UVYRY.js.map +0 -1
package/dist/player/index.cjs
CHANGED
|
@@ -17,8 +17,10 @@ var TAALS = {
|
|
|
17
17
|
teentaal: { id: "teentaal", numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] },
|
|
18
18
|
aratheka: { id: "aratheka", numBeats: 16, bhaags: [4, 4, 4, 4], sam: 0, khaali: [8] },
|
|
19
19
|
// আড়াঠেকা
|
|
20
|
-
jhampak: { id: "jhampak", numBeats: 5, bhaags: [3, 2], sam: 0 }
|
|
20
|
+
jhampak: { id: "jhampak", numBeats: 5, bhaags: [3, 2], sam: 0 },
|
|
21
21
|
// ঝম্পক
|
|
22
|
+
dhamaar: { id: "dhamaar", numBeats: 14, bhaags: [5, 2, 3, 4], sam: 0, khaali: [7] }
|
|
23
|
+
// ধামার
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
// src/player/pitch.ts
|
|
@@ -390,6 +392,9 @@ var SwaralipiPlayer = class {
|
|
|
390
392
|
/** Per-song setBpm tweak: beats meta.bpm but is cleared by the next load(). */
|
|
391
393
|
#bpmTweak;
|
|
392
394
|
#doc;
|
|
395
|
+
/** Taal mode (`loadTaal`): loops one avartan of this taal's theka with no
|
|
396
|
+
* melody. Mutually exclusive with `#doc`. */
|
|
397
|
+
#taal;
|
|
393
398
|
#state = "idle";
|
|
394
399
|
#tone;
|
|
395
400
|
/** Master bus everything routes through, so stop() can fade it out. */
|
|
@@ -418,6 +423,7 @@ var SwaralipiPlayer = class {
|
|
|
418
423
|
tanpura: options.tanpura ?? true,
|
|
419
424
|
previewLimitSec: options.previewLimitSec ?? Infinity,
|
|
420
425
|
onHighlight: options.onHighlight,
|
|
426
|
+
onBeat: options.onBeat,
|
|
421
427
|
onState: options.onState,
|
|
422
428
|
onLimit: options.onLimit
|
|
423
429
|
};
|
|
@@ -457,6 +463,23 @@ var SwaralipiPlayer = class {
|
|
|
457
463
|
load(doc) {
|
|
458
464
|
this.#halt();
|
|
459
465
|
this.#doc = doc;
|
|
466
|
+
this.#taal = void 0;
|
|
467
|
+
this.#taalOverride = void 0;
|
|
468
|
+
this.#bpmTweak = void 0;
|
|
469
|
+
this.#setState("ready");
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Taal mode: loop one avartan of a taal's theka (rhythm only, no melody) —
|
|
473
|
+
* for a standalone theka player. `play()` loops indefinitely (tabla loop /
|
|
474
|
+
* drum sequence) and fires `onBeat(beatInCycle)` once per matra on the draw
|
|
475
|
+
* thread so the consumer can highlight the active bol / drum-staff note. The
|
|
476
|
+
* taal's `id` should be a sampled taal (see `SAMPLED_TAALS`) for tabla audio;
|
|
477
|
+
* `variation` picks a tabla loop variation. Stops any current playback.
|
|
478
|
+
*/
|
|
479
|
+
loadTaal(taal) {
|
|
480
|
+
this.#halt();
|
|
481
|
+
this.#taal = taal;
|
|
482
|
+
this.#doc = void 0;
|
|
460
483
|
this.#taalOverride = void 0;
|
|
461
484
|
this.#bpmTweak = void 0;
|
|
462
485
|
this.#setState("ready");
|
|
@@ -464,7 +487,7 @@ var SwaralipiPlayer = class {
|
|
|
464
487
|
/** Start (or resume) playback. Must be triggered from a user gesture so the
|
|
465
488
|
* browser permits `AudioContext` resume. */
|
|
466
489
|
async play() {
|
|
467
|
-
if (this.#doc === void 0 || this.#state === "playing") return;
|
|
490
|
+
if (this.#doc === void 0 && this.#taal === void 0 || this.#state === "playing") return;
|
|
468
491
|
const Tone = await this.#ensureTone();
|
|
469
492
|
await Tone.start();
|
|
470
493
|
if (this.#state === "paused") {
|
|
@@ -512,7 +535,7 @@ var SwaralipiPlayer = class {
|
|
|
512
535
|
this.#master.gain.cancelScheduledValues(now);
|
|
513
536
|
this.#master.gain.rampTo(0, STOP_FADE_SEC, now);
|
|
514
537
|
this.#emitHighlight(null);
|
|
515
|
-
this.#setState(this.#doc ? "ready" : "idle");
|
|
538
|
+
this.#setState(this.#doc || this.#taal ? "ready" : "idle");
|
|
516
539
|
this.#cancelFadeTimer();
|
|
517
540
|
this.#fadeTimer = setTimeout(() => this.#halt(), STOP_FADE_SEC * 1e3 + 60);
|
|
518
541
|
return;
|
|
@@ -534,7 +557,7 @@ var SwaralipiPlayer = class {
|
|
|
534
557
|
this.#restoreMasterGain();
|
|
535
558
|
this.#scheduleIds = [];
|
|
536
559
|
this.#emitHighlight(null);
|
|
537
|
-
if (this.#state !== "idle") this.#setState(this.#doc ? "ready" : "idle");
|
|
560
|
+
if (this.#state !== "idle") this.#setState(this.#doc || this.#taal ? "ready" : "idle");
|
|
538
561
|
}
|
|
539
562
|
#cancelFadeTimer() {
|
|
540
563
|
if (this.#fadeTimer !== void 0) {
|
|
@@ -648,15 +671,16 @@ var SwaralipiPlayer = class {
|
|
|
648
671
|
#emitHighlight(path) {
|
|
649
672
|
this.#opts.onHighlight?.(path);
|
|
650
673
|
}
|
|
651
|
-
/** The tabla variation to play: the doc's own (
|
|
652
|
-
* explicit setTaal override plays the taal's default variation. */
|
|
674
|
+
/** The tabla variation to play: taal-mode taal's, the doc's own (auto mode),
|
|
675
|
+
* else none — an explicit setTaal override plays the taal's default variation. */
|
|
653
676
|
#variation() {
|
|
677
|
+
if (this.#taal !== void 0) return this.#taal.variation;
|
|
654
678
|
return this.#taalAuto ? this.#doc?.meta.taal?.variation : void 0;
|
|
655
679
|
}
|
|
656
|
-
/** Resolve the active taal: an explicit override, else
|
|
680
|
+
/** Resolve the active taal id: taal mode's taal, an explicit override, else
|
|
681
|
+
* the doc's — but only when it names a sampled taal. */
|
|
657
682
|
#taalId() {
|
|
658
|
-
|
|
659
|
-
const id = this.#doc?.meta.taal?.id;
|
|
683
|
+
const id = this.#taal?.id ?? (!this.#taalAuto && this.#taalOverride !== void 0 ? this.#taalOverride : this.#doc?.meta.taal?.id);
|
|
660
684
|
return id !== void 0 && id in TAALS ? id : void 0;
|
|
661
685
|
}
|
|
662
686
|
/** Resolve an instrument id to its def (custom overrides built-ins; the
|
|
@@ -713,6 +737,7 @@ var SwaralipiPlayer = class {
|
|
|
713
737
|
/** Build the melody instrument(s)/rhythm/drone for the current settings and
|
|
714
738
|
* wait for their buffers, then schedule everything on the Transport. */
|
|
715
739
|
async #arrange(Tone) {
|
|
740
|
+
if (this.#taal !== void 0) return this.#arrangeTaal(Tone);
|
|
716
741
|
if (this.#doc === void 0) return;
|
|
717
742
|
const base = this.#opts.soundsBaseUrl;
|
|
718
743
|
const transport = Tone.getTransport();
|
|
@@ -758,6 +783,40 @@ var SwaralipiPlayer = class {
|
|
|
758
783
|
}, schedule.totalBeats * spb);
|
|
759
784
|
transport.scheduleOnce(() => this.stop(), endAt);
|
|
760
785
|
}
|
|
786
|
+
/** Taal mode: loop one avartan forever (tabla loop / drum sequence via
|
|
787
|
+
* #buildRhythm), firing onBeat + a `String(beatInCycle)` highlight each matra
|
|
788
|
+
* on the draw thread. No melody, no tanpura, no auto-stop — it plays until
|
|
789
|
+
* stop(). */
|
|
790
|
+
async #arrangeTaal(Tone) {
|
|
791
|
+
if (this.#taal === void 0) return;
|
|
792
|
+
const base = this.#opts.soundsBaseUrl;
|
|
793
|
+
const transport = Tone.getTransport();
|
|
794
|
+
transport.cancel(0);
|
|
795
|
+
transport.position = 0;
|
|
796
|
+
this.#scheduleIds = [];
|
|
797
|
+
this.#ensureMaster(Tone);
|
|
798
|
+
this.#restoreMasterGain();
|
|
799
|
+
const bpm = this.#effectiveBpm();
|
|
800
|
+
transport.bpm.value = bpm;
|
|
801
|
+
const spb = 60 / bpm;
|
|
802
|
+
this.#buildRhythm(Tone, transport, base, spb);
|
|
803
|
+
await Tone.loaded();
|
|
804
|
+
if (this.#tabla?.buffer?.loaded) {
|
|
805
|
+
this.#tabla.loopEnd = quantizeLoopEnd(this.#tabla.buffer.duration, spb);
|
|
806
|
+
}
|
|
807
|
+
const draw = Tone.getDraw();
|
|
808
|
+
const n = Math.max(1, this.#taal.numBeats);
|
|
809
|
+
let beat = 0;
|
|
810
|
+
const id = transport.scheduleRepeat((time) => {
|
|
811
|
+
const b = beat % n;
|
|
812
|
+
draw.schedule(() => {
|
|
813
|
+
this.#emitHighlight(String(b));
|
|
814
|
+
this.#opts.onBeat?.(b);
|
|
815
|
+
}, time);
|
|
816
|
+
beat += 1;
|
|
817
|
+
}, spb, 0);
|
|
818
|
+
this.#scheduleIds.push(id);
|
|
819
|
+
}
|
|
761
820
|
/** Build (or reuse) the melody sampler for `id`, loading only the samples
|
|
762
821
|
* covering `range`. A cached sampler is reused while it still covers the
|
|
763
822
|
* range; otherwise it's rebuilt (so changing songs/tonic widens it lazily). */
|
|
@@ -788,7 +847,7 @@ var SwaralipiPlayer = class {
|
|
|
788
847
|
if (this.#opts.rhythm === "drums") {
|
|
789
848
|
this.#drums ??= createDrumKit(Tone).connect(master);
|
|
790
849
|
const drums = this.#drums;
|
|
791
|
-
const taal = taalId !== void 0 ? TAALS[taalId] : { numBeats: 4, sam: 0 };
|
|
850
|
+
const taal = this.#taal ?? (taalId !== void 0 ? TAALS[taalId] : { numBeats: 4, sam: 0 });
|
|
792
851
|
const pattern = drumPattern(taal);
|
|
793
852
|
let beat2 = 0;
|
|
794
853
|
const id2 = transport.scheduleRepeat((time) => {
|
|
@@ -802,7 +861,7 @@ var SwaralipiPlayer = class {
|
|
|
802
861
|
if (this.#opts.rhythm === "none" || base === void 0) return;
|
|
803
862
|
this.#metronome ??= createMetronome(Tone, base).connect(master);
|
|
804
863
|
const metro = this.#metronome;
|
|
805
|
-
const cycle = taalId !== void 0 ? TAALS[taalId].numBeats : 4;
|
|
864
|
+
const cycle = this.#taal?.numBeats ?? (taalId !== void 0 ? TAALS[taalId].numBeats : 4);
|
|
806
865
|
let beat = 0;
|
|
807
866
|
const id = transport.scheduleRepeat((time) => {
|
|
808
867
|
metro.volume.setValueAtTime(beat % cycle === 0 ? 0 : -8, time);
|