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