@ugfoundation/swaralipi-js 0.3.2 → 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-5LFXQ67K.js → batch-6YAUMVHC.js} +4 -4
- package/dist/{batch-5LFXQ67K.js.map → batch-6YAUMVHC.js.map} +1 -1
- package/dist/{chunk-XQYXZPHK.js → chunk-RTCRSOVW.js} +3 -3
- package/dist/{chunk-XQYXZPHK.js.map → chunk-RTCRSOVW.js.map} +1 -1
- package/dist/{chunk-QVNFEWMM.js → chunk-UBJZUKQD.js} +3 -3
- package/dist/{chunk-QVNFEWMM.js.map → chunk-UBJZUKQD.js.map} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/convert/index.cjs +1 -1
- package/dist/convert/index.cjs.map +1 -1
- package/dist/convert/index.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/player/index.cjs +67 -10
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +14 -1
- package/dist/player/index.d.ts +14 -1
- package/dist/player/index.js +67 -10
- package/dist/player/index.js.map +1 -1
- package/dist/spec/index.cjs +1 -1
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.d.cts +1 -1
- package/dist/spec/index.d.ts +1 -1
- package/dist/spec/index.js +1 -1
- package/dist/viewer/index.cjs +25 -1
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +35 -3
- package/dist/viewer/index.d.ts +35 -3
- package/dist/viewer/index.js +23 -1
- package/dist/viewer/index.js.map +1 -1
- package/package.json +1 -1
package/dist/player/index.cjs
CHANGED
|
@@ -390,6 +390,9 @@ var SwaralipiPlayer = class {
|
|
|
390
390
|
/** Per-song setBpm tweak: beats meta.bpm but is cleared by the next load(). */
|
|
391
391
|
#bpmTweak;
|
|
392
392
|
#doc;
|
|
393
|
+
/** Taal mode (`loadTaal`): loops one avartan of this taal's theka with no
|
|
394
|
+
* melody. Mutually exclusive with `#doc`. */
|
|
395
|
+
#taal;
|
|
393
396
|
#state = "idle";
|
|
394
397
|
#tone;
|
|
395
398
|
/** Master bus everything routes through, so stop() can fade it out. */
|
|
@@ -418,6 +421,7 @@ var SwaralipiPlayer = class {
|
|
|
418
421
|
tanpura: options.tanpura ?? true,
|
|
419
422
|
previewLimitSec: options.previewLimitSec ?? Infinity,
|
|
420
423
|
onHighlight: options.onHighlight,
|
|
424
|
+
onBeat: options.onBeat,
|
|
421
425
|
onState: options.onState,
|
|
422
426
|
onLimit: options.onLimit
|
|
423
427
|
};
|
|
@@ -457,6 +461,23 @@ var SwaralipiPlayer = class {
|
|
|
457
461
|
load(doc) {
|
|
458
462
|
this.#halt();
|
|
459
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;
|
|
460
481
|
this.#taalOverride = void 0;
|
|
461
482
|
this.#bpmTweak = void 0;
|
|
462
483
|
this.#setState("ready");
|
|
@@ -464,7 +485,7 @@ var SwaralipiPlayer = class {
|
|
|
464
485
|
/** Start (or resume) playback. Must be triggered from a user gesture so the
|
|
465
486
|
* browser permits `AudioContext` resume. */
|
|
466
487
|
async play() {
|
|
467
|
-
if (this.#doc === void 0 || this.#state === "playing") return;
|
|
488
|
+
if (this.#doc === void 0 && this.#taal === void 0 || this.#state === "playing") return;
|
|
468
489
|
const Tone = await this.#ensureTone();
|
|
469
490
|
await Tone.start();
|
|
470
491
|
if (this.#state === "paused") {
|
|
@@ -512,7 +533,7 @@ var SwaralipiPlayer = class {
|
|
|
512
533
|
this.#master.gain.cancelScheduledValues(now);
|
|
513
534
|
this.#master.gain.rampTo(0, STOP_FADE_SEC, now);
|
|
514
535
|
this.#emitHighlight(null);
|
|
515
|
-
this.#setState(this.#doc ? "ready" : "idle");
|
|
536
|
+
this.#setState(this.#doc || this.#taal ? "ready" : "idle");
|
|
516
537
|
this.#cancelFadeTimer();
|
|
517
538
|
this.#fadeTimer = setTimeout(() => this.#halt(), STOP_FADE_SEC * 1e3 + 60);
|
|
518
539
|
return;
|
|
@@ -534,7 +555,7 @@ var SwaralipiPlayer = class {
|
|
|
534
555
|
this.#restoreMasterGain();
|
|
535
556
|
this.#scheduleIds = [];
|
|
536
557
|
this.#emitHighlight(null);
|
|
537
|
-
if (this.#state !== "idle") this.#setState(this.#doc ? "ready" : "idle");
|
|
558
|
+
if (this.#state !== "idle") this.#setState(this.#doc || this.#taal ? "ready" : "idle");
|
|
538
559
|
}
|
|
539
560
|
#cancelFadeTimer() {
|
|
540
561
|
if (this.#fadeTimer !== void 0) {
|
|
@@ -648,15 +669,16 @@ var SwaralipiPlayer = class {
|
|
|
648
669
|
#emitHighlight(path) {
|
|
649
670
|
this.#opts.onHighlight?.(path);
|
|
650
671
|
}
|
|
651
|
-
/** The tabla variation to play: the doc's own (
|
|
652
|
-
* 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. */
|
|
653
674
|
#variation() {
|
|
675
|
+
if (this.#taal !== void 0) return this.#taal.variation;
|
|
654
676
|
return this.#taalAuto ? this.#doc?.meta.taal?.variation : void 0;
|
|
655
677
|
}
|
|
656
|
-
/** 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. */
|
|
657
680
|
#taalId() {
|
|
658
|
-
|
|
659
|
-
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);
|
|
660
682
|
return id !== void 0 && id in TAALS ? id : void 0;
|
|
661
683
|
}
|
|
662
684
|
/** Resolve an instrument id to its def (custom overrides built-ins; the
|
|
@@ -713,6 +735,7 @@ var SwaralipiPlayer = class {
|
|
|
713
735
|
/** Build the melody instrument(s)/rhythm/drone for the current settings and
|
|
714
736
|
* wait for their buffers, then schedule everything on the Transport. */
|
|
715
737
|
async #arrange(Tone) {
|
|
738
|
+
if (this.#taal !== void 0) return this.#arrangeTaal(Tone);
|
|
716
739
|
if (this.#doc === void 0) return;
|
|
717
740
|
const base = this.#opts.soundsBaseUrl;
|
|
718
741
|
const transport = Tone.getTransport();
|
|
@@ -758,6 +781,40 @@ var SwaralipiPlayer = class {
|
|
|
758
781
|
}, schedule.totalBeats * spb);
|
|
759
782
|
transport.scheduleOnce(() => this.stop(), endAt);
|
|
760
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
|
+
}
|
|
761
818
|
/** Build (or reuse) the melody sampler for `id`, loading only the samples
|
|
762
819
|
* covering `range`. A cached sampler is reused while it still covers the
|
|
763
820
|
* range; otherwise it's rebuilt (so changing songs/tonic widens it lazily). */
|
|
@@ -788,7 +845,7 @@ var SwaralipiPlayer = class {
|
|
|
788
845
|
if (this.#opts.rhythm === "drums") {
|
|
789
846
|
this.#drums ??= createDrumKit(Tone).connect(master);
|
|
790
847
|
const drums = this.#drums;
|
|
791
|
-
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 });
|
|
792
849
|
const pattern = drumPattern(taal);
|
|
793
850
|
let beat2 = 0;
|
|
794
851
|
const id2 = transport.scheduleRepeat((time) => {
|
|
@@ -802,7 +859,7 @@ var SwaralipiPlayer = class {
|
|
|
802
859
|
if (this.#opts.rhythm === "none" || base === void 0) return;
|
|
803
860
|
this.#metronome ??= createMetronome(Tone, base).connect(master);
|
|
804
861
|
const metro = this.#metronome;
|
|
805
|
-
const cycle = taalId !== void 0 ? TAALS[taalId].numBeats : 4;
|
|
862
|
+
const cycle = this.#taal?.numBeats ?? (taalId !== void 0 ? TAALS[taalId].numBeats : 4);
|
|
806
863
|
let beat = 0;
|
|
807
864
|
const id = transport.scheduleRepeat((time) => {
|
|
808
865
|
metro.volume.setValueAtTime(beat % cycle === 0 ? 0 : -8, time);
|