@ugfoundation/swaralipi-js 0.8.2 → 0.9.1
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/README.md +1 -1
- package/dist/{batch-6FPBT5DP.js → batch-NEM7JXHV.js} +5 -5
- package/dist/{batch-6FPBT5DP.js.map → batch-NEM7JXHV.js.map} +1 -1
- package/dist/{chunk-UMBKIGVQ.js → chunk-DOEFSS66.js} +5 -4
- package/dist/chunk-DOEFSS66.js.map +1 -0
- package/dist/{chunk-4HNT6OAT.js → chunk-MYVIQU4O.js} +12 -3
- package/dist/chunk-MYVIQU4O.js.map +1 -0
- package/dist/{chunk-4IVUPMRK.js → chunk-SEN266BY.js} +28 -13
- package/dist/chunk-SEN266BY.js.map +1 -0
- package/dist/{chunk-FULC22MN.js → chunk-Z6A3CP5V.js} +28 -19
- package/dist/chunk-Z6A3CP5V.js.map +1 -0
- package/dist/cli.cjs +33 -19
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/convert/index.cjs +31 -17
- package/dist/convert/index.cjs.map +1 -1
- package/dist/convert/index.d.cts +1 -1
- package/dist/convert/index.d.ts +1 -1
- package/dist/convert/index.js +3 -3
- package/dist/index.cjs +38 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{lay-Csa4CD46.d.cts → lay-CZIzR9cM.d.ts} +16 -2
- package/dist/{lay-Ct9ky_EE.d.ts → lay-CfDlPhH2.d.cts} +16 -2
- package/dist/player/index.cjs +116 -71
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +11 -9
- package/dist/player/index.d.ts +11 -9
- package/dist/player/index.js +89 -66
- package/dist/player/index.js.map +1 -1
- package/dist/{schedule-B_UaluBi.d.cts → schedule-BaovCtmf.d.ts} +31 -12
- package/dist/{schedule-CdILTNsk.d.ts → schedule-CU-VECDH.d.cts} +31 -12
- package/dist/{schema-DGA_bNVZ.d.ts → schema-Cf_epUIC.d.cts} +333 -63
- package/dist/{schema-DGA_bNVZ.d.cts → schema-Cf_epUIC.d.ts} +333 -63
- package/dist/spec/index.cjs +38 -17
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.d.cts +26 -8
- package/dist/spec/index.d.ts +26 -8
- package/dist/spec/index.js +2 -2
- package/dist/viewer/index.cjs +156 -73
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +25 -7
- package/dist/viewer/index.d.ts +25 -7
- package/dist/viewer/index.js +78 -27
- package/dist/viewer/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-4HNT6OAT.js.map +0 -1
- package/dist/chunk-4IVUPMRK.js.map +0 -1
- package/dist/chunk-FULC22MN.js.map +0 -1
- package/dist/chunk-UMBKIGVQ.js.map +0 -1
package/dist/player/index.d.cts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as Swaralipi, T as Taal, O as Octave, a as SvaraLetter, N as Note } from '../schema-
|
|
2
|
-
import { a as LaySpeeds, T as TaalId } from '../lay-
|
|
3
|
-
export { b as LAYS, c as LAY_SPEEDS, L as Lay, p as printedLay, r as resolveLaySpeeds, d as rowLay } from '../lay-
|
|
4
|
-
import { I as InstrumentId, a as InstrumentDef, S as Schedule, D as DrumVoice } from '../schedule-
|
|
5
|
-
export { A as ARC_RAW_RE, b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, G as
|
|
1
|
+
import { S as Swaralipi, T as Taal, O as Octave, a as SvaraLetter, N as Note } from '../schema-Cf_epUIC.cjs';
|
|
2
|
+
import { a as LaySpeeds, T as TaalId } from '../lay-CfDlPhH2.cjs';
|
|
3
|
+
export { b as LAYS, c as LAY_SPEEDS, L as Lay, p as printedLay, r as resolveLaySpeeds, d as rowLay } from '../lay-CfDlPhH2.cjs';
|
|
4
|
+
import { I as InstrumentId, a as InstrumentDef, S as Schedule, D as DrumVoice, T as TempoSegment } from '../schedule-CU-VECDH.cjs';
|
|
5
|
+
export { A as ARC_RAW_RE, b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, G as GRACE_STEP, d as GlideLeg, e as INSTRUMENTS, M as MEEND_HOLD, P as PlayEvent, f as SALAMANDER_BASE, g as SAMPLED_TAALS, h as ScheduleOptions, i as TABLA_BPMS, j as TABLA_VARIATIONS, k as TONEJS_INSTRUMENTS_BASE, l as ToneModule, m as buildSchedule, n as createBuffers, o as drumPattern, p as glideTargets, q as graceTouches, r as instrumentSampleUrl, s as isArcRaw, t as meendContinuations, u as nearestSampleKey, v as nearestTablaBpm, w as normalizeBase, x as probeUrl, y as quantizeLoopEnd, z as santoorUrls, B as subsetUrls, C as tablaBpms, E as tablaUrl, F as triggerGlide } from '../schedule-CU-VECDH.cjs';
|
|
6
6
|
import 'zod';
|
|
7
7
|
import 'tone';
|
|
8
8
|
|
|
@@ -280,13 +280,15 @@ interface MidiExportResult {
|
|
|
280
280
|
}
|
|
281
281
|
/**
|
|
282
282
|
* Encode a schedule to a Standard MIDI File. Melody rides channel 0; when
|
|
283
|
-
* `drums` is given, its per-
|
|
284
|
-
* (the file becomes format 1).
|
|
283
|
+
* `drums` is given, its per-matra voices ride a second GM channel-10 track
|
|
284
|
+
* (the file becomes format 1). `drums` is one pattern for the whole song, or a
|
|
285
|
+
* function picking each লয় / তাল segment's own (তালফেরতা; `undefined` = rest).
|
|
286
|
+
* Pure — no Tone, no browser — directly testable.
|
|
285
287
|
*/
|
|
286
288
|
declare function encodeMidi(schedule: Schedule, opts: {
|
|
287
289
|
bpm: number;
|
|
288
290
|
name?: string;
|
|
289
|
-
drums?: DrumVoice[];
|
|
291
|
+
drums?: DrumVoice[] | ((seg: TempoSegment) => DrumVoice[] | undefined);
|
|
290
292
|
}): Uint8Array;
|
|
291
293
|
/**
|
|
292
294
|
* Export a swaralipi doc to a `.mid` Blob (melody voice only). No browser APIs
|
|
@@ -340,4 +342,4 @@ declare function sampleFileName(midi: number): string;
|
|
|
340
342
|
*/
|
|
341
343
|
declare function sCurve(x: number, steepness?: number): number;
|
|
342
344
|
|
|
343
|
-
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, DrumVoice, InstrumentDef, InstrumentId, LaySpeeds, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sCurve, sampleFileName, svaraSemitone, svaraToMidi };
|
|
345
|
+
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, DrumVoice, InstrumentDef, InstrumentId, LaySpeeds, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, TempoSegment, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sCurve, sampleFileName, svaraSemitone, svaraToMidi };
|
package/dist/player/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { S as Swaralipi, T as Taal, O as Octave, a as SvaraLetter, N as Note } from '../schema-
|
|
2
|
-
import { a as LaySpeeds, T as TaalId } from '../lay-
|
|
3
|
-
export { b as LAYS, c as LAY_SPEEDS, L as Lay, p as printedLay, r as resolveLaySpeeds, d as rowLay } from '../lay-
|
|
4
|
-
import { I as InstrumentId, a as InstrumentDef, S as Schedule, D as DrumVoice } from '../schedule-
|
|
5
|
-
export { A as ARC_RAW_RE, b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, G as
|
|
1
|
+
import { S as Swaralipi, T as Taal, O as Octave, a as SvaraLetter, N as Note } from '../schema-Cf_epUIC.js';
|
|
2
|
+
import { a as LaySpeeds, T as TaalId } from '../lay-CZIzR9cM.js';
|
|
3
|
+
export { b as LAYS, c as LAY_SPEEDS, L as Lay, p as printedLay, r as resolveLaySpeeds, d as rowLay } from '../lay-CZIzR9cM.js';
|
|
4
|
+
import { I as InstrumentId, a as InstrumentDef, S as Schedule, D as DrumVoice, T as TempoSegment } from '../schedule-BaovCtmf.js';
|
|
5
|
+
export { A as ARC_RAW_RE, b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, G as GRACE_STEP, d as GlideLeg, e as INSTRUMENTS, M as MEEND_HOLD, P as PlayEvent, f as SALAMANDER_BASE, g as SAMPLED_TAALS, h as ScheduleOptions, i as TABLA_BPMS, j as TABLA_VARIATIONS, k as TONEJS_INSTRUMENTS_BASE, l as ToneModule, m as buildSchedule, n as createBuffers, o as drumPattern, p as glideTargets, q as graceTouches, r as instrumentSampleUrl, s as isArcRaw, t as meendContinuations, u as nearestSampleKey, v as nearestTablaBpm, w as normalizeBase, x as probeUrl, y as quantizeLoopEnd, z as santoorUrls, B as subsetUrls, C as tablaBpms, E as tablaUrl, F as triggerGlide } from '../schedule-BaovCtmf.js';
|
|
6
6
|
import 'zod';
|
|
7
7
|
import 'tone';
|
|
8
8
|
|
|
@@ -280,13 +280,15 @@ interface MidiExportResult {
|
|
|
280
280
|
}
|
|
281
281
|
/**
|
|
282
282
|
* Encode a schedule to a Standard MIDI File. Melody rides channel 0; when
|
|
283
|
-
* `drums` is given, its per-
|
|
284
|
-
* (the file becomes format 1).
|
|
283
|
+
* `drums` is given, its per-matra voices ride a second GM channel-10 track
|
|
284
|
+
* (the file becomes format 1). `drums` is one pattern for the whole song, or a
|
|
285
|
+
* function picking each লয় / তাল segment's own (তালফেরতা; `undefined` = rest).
|
|
286
|
+
* Pure — no Tone, no browser — directly testable.
|
|
285
287
|
*/
|
|
286
288
|
declare function encodeMidi(schedule: Schedule, opts: {
|
|
287
289
|
bpm: number;
|
|
288
290
|
name?: string;
|
|
289
|
-
drums?: DrumVoice[];
|
|
291
|
+
drums?: DrumVoice[] | ((seg: TempoSegment) => DrumVoice[] | undefined);
|
|
290
292
|
}): Uint8Array;
|
|
291
293
|
/**
|
|
292
294
|
* Export a swaralipi doc to a `.mid` Blob (melody voice only). No browser APIs
|
|
@@ -340,4 +342,4 @@ declare function sampleFileName(midi: number): string;
|
|
|
340
342
|
*/
|
|
341
343
|
declare function sCurve(x: number, steepness?: number): number;
|
|
342
344
|
|
|
343
|
-
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, DrumVoice, InstrumentDef, InstrumentId, LaySpeeds, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sCurve, sampleFileName, svaraSemitone, svaraToMidi };
|
|
345
|
+
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, DrumVoice, InstrumentDef, InstrumentId, LaySpeeds, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, TempoSegment, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sCurve, sampleFileName, svaraSemitone, svaraToMidi };
|
package/dist/player/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DEFAULT_SOUNDS_BASE, INSTRUMENTS, SAMPLED_TAALS, buildSchedule, quantizeLoopEnd, instrumentSampleUrl, probeUrl, normalizeBase, nearestTablaBpm, tablaBpms, midiToSampleName, glideTargets, triggerGlide, createSampler, createBuffers,
|
|
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-
|
|
3
|
-
import { TAALS } from '../chunk-
|
|
4
|
-
export { LAYS, LAY_SPEEDS, printedLay, resolveLaySpeeds, rowLay } from '../chunk-
|
|
1
|
+
import { DEFAULT_SOUNDS_BASE, INSTRUMENTS, SAMPLED_TAALS, buildSchedule, quantizeLoopEnd, instrumentSampleUrl, probeUrl, normalizeBase, nearestTablaBpm, tablaBpms, graceTouches, midiToSampleName, glideTargets, triggerGlide, createSampler, createBuffers, tablaShiftSemitones, tablaUrl, TABLA_GRAIN_OVERLAP_SEC, TABLA_GRAIN_SEC, createDrumKit, drumPattern, createMetronome, TANPURA_PCS, createTanpura, parseTonic, GRACE_STEP, MEEND_HOLD, sCurve } from '../chunk-SEN266BY.js';
|
|
2
|
+
export { ARC_RAW_RE, DEFAULT_SOUNDS_BASE, DRUM_KIT_BASE, GRACE_STEP, INSTRUMENTS, MEEND_HOLD, OCTAVE_OFFSET, SALAMANDER_BASE, SAMPLED_TAALS, SHUDDHA, TABLA_BPMS, TABLA_VARIATIONS, TONEJS_INSTRUMENTS_BASE, buildSchedule, createBuffers, drumPattern, glideTargets, graceTouches, instrumentSampleUrl, isArcRaw, meendContinuations, midiToSampleName, nearestSampleKey, nearestTablaBpm, normalizeBase, parseTonic, probeUrl, quantizeLoopEnd, sCurve, sampleFileName, santoorUrls, subsetUrls, svaraSemitone, svaraToMidi, tablaBpms, tablaUrl, triggerGlide } from '../chunk-SEN266BY.js';
|
|
3
|
+
import { TAALS } from '../chunk-MYVIQU4O.js';
|
|
4
|
+
export { LAYS, LAY_SPEEDS, printedLay, resolveLaySpeeds, rowLay } from '../chunk-MYVIQU4O.js';
|
|
5
5
|
|
|
6
6
|
// src/player/player.ts
|
|
7
7
|
var STOP_FADE_SEC = 0.5;
|
|
@@ -14,7 +14,7 @@ function midiRange(schedule) {
|
|
|
14
14
|
let lo = Infinity;
|
|
15
15
|
let hi = -Infinity;
|
|
16
16
|
for (const ev of schedule.events) {
|
|
17
|
-
for (const m of [ev.midi, ...ev.kan]) {
|
|
17
|
+
for (const m of [ev.midi, ...ev.kan, ...ev.resh]) {
|
|
18
18
|
if (m !== null) {
|
|
19
19
|
if (m < lo) lo = m;
|
|
20
20
|
if (m > hi) hi = m;
|
|
@@ -357,16 +357,26 @@ var SwaralipiPlayer = class {
|
|
|
357
357
|
#emitHighlight(path) {
|
|
358
358
|
this.#opts.onHighlight?.(path);
|
|
359
359
|
}
|
|
360
|
-
/** The
|
|
361
|
-
*
|
|
362
|
-
|
|
360
|
+
/** The taal one accompaniment segment plays: taal mode's, an explicit
|
|
361
|
+
* setTaal override (pinned across the whole song, তালফেরতা included), else
|
|
362
|
+
* the segment's own. `null` = a মুক্তছন্দ passage. */
|
|
363
|
+
#segmentTaal(seg) {
|
|
364
|
+
if (this.#taal !== void 0) return this.#taal;
|
|
365
|
+
if (!this.#taalAuto && this.#taalOverride !== void 0) return TAALS[this.#taalOverride];
|
|
366
|
+
return seg.taal;
|
|
367
|
+
}
|
|
368
|
+
/** The tabla variation to play: taal-mode taal's, the segment's own (auto
|
|
369
|
+
* mode), else none — an explicit setTaal override plays the default variation. */
|
|
370
|
+
#variation(taal) {
|
|
363
371
|
if (this.#taal !== void 0) return this.#taal.variation;
|
|
364
|
-
return this.#taalAuto ?
|
|
372
|
+
return this.#taalAuto ? taal?.variation : void 0;
|
|
365
373
|
}
|
|
366
374
|
/** Resolve the active taal id: taal mode's taal, an explicit override, else
|
|
367
|
-
* the doc's
|
|
375
|
+
* the doc's opening one (a তালফেরতা doc may carry it on its first row) — but
|
|
376
|
+
* only when it names a sampled taal. */
|
|
368
377
|
#taalId() {
|
|
369
|
-
const
|
|
378
|
+
const opening = this.#doc?.parts[0]?.rows[0]?.taal || this.#doc?.meta.taal;
|
|
379
|
+
const id = this.#taal?.id ?? (!this.#taalAuto && this.#taalOverride !== void 0 ? this.#taalOverride : opening?.id);
|
|
370
380
|
return id !== void 0 && id in TAALS ? id : void 0;
|
|
371
381
|
}
|
|
372
382
|
/** Resolve an instrument id to its def (custom overrides built-ins; the
|
|
@@ -457,14 +467,15 @@ var SwaralipiPlayer = class {
|
|
|
457
467
|
const mediaLead = Math.min(MEDIA_LEAD_SEC, spb);
|
|
458
468
|
schedule.events.forEach((ev, i) => {
|
|
459
469
|
const at = ev.beat * spb + shift;
|
|
470
|
+
if (ev.glide !== true) {
|
|
471
|
+
for (const g of graceTouches(ev)) {
|
|
472
|
+
const graceName = midiToSampleName(g.midi);
|
|
473
|
+
transport.scheduleOnce((time) => melody.triggerAttackRelease(graceName, spb * 0.4, time), Math.max(g.beat * spb + shift, 0));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
460
476
|
if (ev.midi !== null && ev.glide !== true) {
|
|
461
477
|
const name = midiToSampleName(ev.midi);
|
|
462
478
|
const dur = Math.max(ev.durationBeats * spb, 0.05);
|
|
463
|
-
ev.kan.forEach((k, gi) => {
|
|
464
|
-
const kanName = midiToSampleName(k);
|
|
465
|
-
const lead = spb * 0.12 * (ev.kan.length - gi);
|
|
466
|
-
transport.scheduleOnce((time) => melody.triggerAttackRelease(kanName, spb * 0.4, time), Math.max(at - lead, 0));
|
|
467
|
-
});
|
|
468
479
|
const targets = glide !== void 0 ? glideTargets(schedule.events, i) : [];
|
|
469
480
|
if (targets.length > 0 && glide !== void 0) {
|
|
470
481
|
const last = targets[targets.length - 1];
|
|
@@ -561,34 +572,35 @@ var SwaralipiPlayer = class {
|
|
|
561
572
|
return entry;
|
|
562
573
|
}
|
|
563
574
|
/**
|
|
564
|
-
* Accompaniment, one লয় segment at a time. A tempo change under the
|
|
565
|
-
* is a real tempo change under the drum: the tabla loop is rebuilt at
|
|
566
|
-
* segment's own bpm — its own recorded file when the set has one at that
|
|
575
|
+
* Accompaniment, one লয় / তাল segment at a time. A tempo change under the
|
|
576
|
+
* melody is a real tempo change under the drum: the tabla loop is rebuilt at
|
|
577
|
+
* the segment's own bpm — its own recorded file when the set has one at that
|
|
567
578
|
* tempo, else the nearest file time-stretched by `GrainPlayer` (which
|
|
568
579
|
* stretches *without* transposing, unlike a plain playbackRate) — and the
|
|
569
|
-
* click / drum / drone patterns re-space their interval. A
|
|
570
|
-
*
|
|
580
|
+
* click / drum / drone patterns re-space their interval. A তালফেরতা swaps the
|
|
581
|
+
* theka the same way: each segment loops its own taal's file (or pattern, or
|
|
582
|
+
* click cycle), and a মুক্তছন্দ segment rests. A document with neither mark
|
|
583
|
+
* has exactly one segment, so this is the old single-loop path.
|
|
571
584
|
*/
|
|
572
585
|
#buildRhythm(Tone, transport, base, spb, segments, shift) {
|
|
573
586
|
this.#disposeTabla();
|
|
574
587
|
const master = this.#ensureMaster(Tone);
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
if (!wantsTabla && this.#opts.rhythm !== "drums" && (this.#opts.rhythm === "none" || base === void 0)) return;
|
|
578
|
-
const taal = this.#taal ?? (taalId !== void 0 ? TAALS[taalId] : this.#doc?.meta.taal) ?? { numBeats: 4, sam: 0 };
|
|
579
|
-
const pattern = this.#opts.rhythm === "drums" ? drumPattern(taal) : [];
|
|
580
|
-
const cycle = this.#taal?.numBeats ?? this.#doc?.meta.taal?.numBeats ?? 4;
|
|
588
|
+
const rhythm = this.#opts.rhythm;
|
|
589
|
+
if (rhythm === "none" || base === void 0 && rhythm !== "drums") return;
|
|
581
590
|
segments.forEach((seg, i) => {
|
|
591
|
+
const own = this.#segmentTaal(seg);
|
|
592
|
+
if (own === null) return;
|
|
593
|
+
const taalId = own !== void 0 && own.id in TAALS ? own.id : void 0;
|
|
582
594
|
const from = i === 0 ? 0 : seg.beat * spb + shift;
|
|
583
595
|
const to = i === segments.length - 1 ? Infinity : seg.endBeat * spb + shift;
|
|
584
596
|
const beatSec = spb / seg.scale;
|
|
585
597
|
const span = to === Infinity ? void 0 : to - from;
|
|
586
|
-
if (
|
|
598
|
+
if (rhythm === "tabla" && taalId !== void 0 && SAMPLED_TAALS.has(taalId) && base !== void 0) {
|
|
587
599
|
const bpm = 60 / beatSec;
|
|
588
600
|
const fileBpm = nearestTablaBpm(bpm, tablaBpms(taalId));
|
|
589
601
|
const rate = bpm / fileBpm;
|
|
590
602
|
const semis = tablaShiftSemitones(this.#tonicSemitone());
|
|
591
|
-
const url = tablaUrl(base, taalId, fileBpm, this.#variation());
|
|
603
|
+
const url = tablaUrl(base, taalId, fileBpm, this.#variation(own));
|
|
592
604
|
const loop = (rate === 1 && semis === 0 ? new Tone.Player({ url, loop: true }) : new Tone.GrainPlayer({
|
|
593
605
|
url,
|
|
594
606
|
loop: true,
|
|
@@ -610,9 +622,10 @@ var SwaralipiPlayer = class {
|
|
|
610
622
|
this.#tabla.push({ loop, fileSpb: 60 / fileBpm });
|
|
611
623
|
return;
|
|
612
624
|
}
|
|
613
|
-
if (
|
|
625
|
+
if (rhythm === "drums") {
|
|
614
626
|
this.#drums ??= createDrumKit(Tone).connect(master);
|
|
615
627
|
const drums = this.#drums;
|
|
628
|
+
const pattern = drumPattern(this.#taal ?? (taalId !== void 0 ? TAALS[taalId] : own) ?? { numBeats: 4, sam: 0 });
|
|
616
629
|
let beat2 = 0;
|
|
617
630
|
this.#scheduleIds.push(
|
|
618
631
|
transport.scheduleRepeat(
|
|
@@ -630,6 +643,7 @@ var SwaralipiPlayer = class {
|
|
|
630
643
|
}
|
|
631
644
|
this.#metronome ??= createMetronome(Tone, base).connect(master);
|
|
632
645
|
const metro = this.#metronome;
|
|
646
|
+
const cycle = (this.#taal ?? seg.taal)?.numBeats ?? 4;
|
|
633
647
|
let beat = 0;
|
|
634
648
|
this.#scheduleIds.push(
|
|
635
649
|
transport.scheduleRepeat(
|
|
@@ -688,7 +702,7 @@ function midiRange2(schedule) {
|
|
|
688
702
|
let lo = Infinity;
|
|
689
703
|
let hi = -Infinity;
|
|
690
704
|
for (const ev of schedule.events) {
|
|
691
|
-
for (const m of [ev.midi, ...ev.kan]) {
|
|
705
|
+
for (const m of [ev.midi, ...ev.kan, ...ev.resh]) {
|
|
692
706
|
if (m !== null) {
|
|
693
707
|
if (m < lo) lo = m;
|
|
694
708
|
if (m > hi) hi = m;
|
|
@@ -705,7 +719,7 @@ function pickDef(id, o) {
|
|
|
705
719
|
return def;
|
|
706
720
|
}
|
|
707
721
|
function resolveTaal(doc, taal) {
|
|
708
|
-
const id = taal !== void 0 && taal !== "auto" ? taal : doc.meta.taal?.id;
|
|
722
|
+
const id = taal !== void 0 && taal !== "auto" ? taal : (doc.parts[0]?.rows[0]?.taal || doc.meta.taal)?.id;
|
|
709
723
|
return id !== void 0 && id in TAALS ? id : void 0;
|
|
710
724
|
}
|
|
711
725
|
function safeName(title) {
|
|
@@ -728,7 +742,7 @@ async function exportAudio(doc, options = {}) {
|
|
|
728
742
|
});
|
|
729
743
|
const range = midiRange2(schedule);
|
|
730
744
|
const taalId = resolveTaal(doc, options.taal);
|
|
731
|
-
const
|
|
745
|
+
const pinned = options.taal !== void 0 && options.taal !== "auto" && taalId !== void 0 ? TAALS[taalId] : void 0;
|
|
732
746
|
const usesTabla = rhythm === "tabla" && taalId !== void 0 && SAMPLED_TAALS.has(taalId) && !!base;
|
|
733
747
|
const reqBpm = options.bpm ?? doc.meta.bpm ?? 90;
|
|
734
748
|
const bpm = usesTabla && taalId ? nearestTablaBpm(reqBpm, tablaBpms(taalId)) : reqBpm;
|
|
@@ -745,14 +759,14 @@ async function exportAudio(doc, options = {}) {
|
|
|
745
759
|
const sampler = createSampler(Tone, def, base, range).connect(master);
|
|
746
760
|
const glide = schedule.events.some((ev) => ev.glide === true) ? createBuffers(Tone, def, base, range) : void 0;
|
|
747
761
|
schedule.events.forEach((ev, i) => {
|
|
748
|
-
if (ev.
|
|
762
|
+
if (ev.glide === true) return;
|
|
763
|
+
for (const g of graceTouches(ev)) {
|
|
764
|
+
const name = midiToSampleName(g.midi);
|
|
765
|
+
transport.scheduleOnce((t) => sampler.triggerAttackRelease(name, spb * 0.4, t), Math.max(g.beat * spb + shift, 0));
|
|
766
|
+
}
|
|
767
|
+
if (ev.midi === null) return;
|
|
749
768
|
const at = ev.beat * spb + shift;
|
|
750
769
|
const dur = Math.max(ev.durationBeats * spb, 0.05);
|
|
751
|
-
ev.kan.forEach((k, gi) => {
|
|
752
|
-
const name = midiToSampleName(k);
|
|
753
|
-
const lead = spb * 0.12 * (ev.kan.length - gi);
|
|
754
|
-
transport.scheduleOnce((t) => sampler.triggerAttackRelease(name, spb * 0.4, t), Math.max(at - lead, 0));
|
|
755
|
-
});
|
|
756
770
|
const targets = glide !== void 0 ? glideTargets(schedule.events, i) : [];
|
|
757
771
|
if (targets.length > 0 && glide !== void 0) {
|
|
758
772
|
const last = targets[targets.length - 1];
|
|
@@ -780,22 +794,22 @@ async function exportAudio(doc, options = {}) {
|
|
|
780
794
|
}
|
|
781
795
|
const tablas = [];
|
|
782
796
|
if (rhythm !== "none" && base) {
|
|
783
|
-
const taal = taalId !== void 0 ? TAALS[taalId] : doc.meta.taal ?? { numBeats: 4, sam: 0 };
|
|
784
|
-
const pattern = rhythm === "drums" ? drumPattern(taal) : [];
|
|
785
797
|
const drums = rhythm === "drums" ? createDrumKit(Tone).connect(master) : void 0;
|
|
786
|
-
|
|
787
|
-
const cycle = taalId !== void 0 ? TAALS[taalId].numBeats : doc.meta.taal?.numBeats ?? 4;
|
|
798
|
+
let metro;
|
|
788
799
|
const semis = tablaShiftSemitones(parseTonic(options.tonic ?? doc.meta.tonic));
|
|
789
800
|
schedule.tempo.forEach((seg, i) => {
|
|
801
|
+
const own = pinned ?? seg.taal;
|
|
802
|
+
if (own === null) return;
|
|
803
|
+
const segId = own !== void 0 && own.id in TAALS ? own.id : void 0;
|
|
790
804
|
const from = i === 0 ? 0 : seg.beat * spb + shift;
|
|
791
805
|
const to = i === schedule.tempo.length - 1 ? Infinity : seg.endBeat * spb + shift;
|
|
792
806
|
const beatSec = spb / seg.scale;
|
|
793
807
|
const span = to === Infinity ? void 0 : to - from;
|
|
794
|
-
if (
|
|
808
|
+
if (rhythm === "tabla" && segId !== void 0 && SAMPLED_TAALS.has(segId)) {
|
|
795
809
|
const segBpm = 60 / beatSec;
|
|
796
|
-
const fileBpm = nearestTablaBpm(segBpm, tablaBpms(
|
|
810
|
+
const fileBpm = nearestTablaBpm(segBpm, tablaBpms(segId));
|
|
797
811
|
const rate = segBpm / fileBpm;
|
|
798
|
-
const url = tablaUrl(base,
|
|
812
|
+
const url = tablaUrl(base, segId, fileBpm, pinned === void 0 ? own?.variation : void 0);
|
|
799
813
|
const loop = (rate === 1 && semis === 0 ? new Tone.Player({ url, loop: true }) : new Tone.GrainPlayer({
|
|
800
814
|
url,
|
|
801
815
|
loop: true,
|
|
@@ -814,6 +828,7 @@ async function exportAudio(doc, options = {}) {
|
|
|
814
828
|
}
|
|
815
829
|
tablas.push({ loop, fileSpb: 60 / fileBpm });
|
|
816
830
|
} else if (drums !== void 0) {
|
|
831
|
+
const pattern = drumPattern(segId !== void 0 ? TAALS[segId] : own ?? { numBeats: 4, sam: 0 });
|
|
817
832
|
let beat = 0;
|
|
818
833
|
transport.scheduleRepeat(
|
|
819
834
|
(time) => {
|
|
@@ -825,12 +840,14 @@ async function exportAudio(doc, options = {}) {
|
|
|
825
840
|
from,
|
|
826
841
|
span
|
|
827
842
|
);
|
|
828
|
-
} else
|
|
843
|
+
} else {
|
|
844
|
+
const click = metro ??= createMetronome(Tone, base).connect(master);
|
|
845
|
+
const cycle = own?.numBeats ?? 4;
|
|
829
846
|
let beat = 0;
|
|
830
847
|
transport.scheduleRepeat(
|
|
831
848
|
(time) => {
|
|
832
|
-
|
|
833
|
-
|
|
849
|
+
click.volume.setValueAtTime(beat % cycle === 0 ? 0 : -8, time);
|
|
850
|
+
click.start(time);
|
|
834
851
|
beat += 1;
|
|
835
852
|
},
|
|
836
853
|
beatSec,
|
|
@@ -1025,17 +1042,17 @@ function encodeMidi(schedule, opts) {
|
|
|
1025
1042
|
const hasGlide = schedule.events.some((ev) => ev.glide === true);
|
|
1026
1043
|
if (hasGlide) melody.push(...bendRangeSetup());
|
|
1027
1044
|
schedule.events.forEach((ev, i) => {
|
|
1028
|
-
if (ev.
|
|
1045
|
+
if (ev.glide === true) return;
|
|
1046
|
+
for (const g of graceTouches(ev)) {
|
|
1047
|
+
const on = Math.max(Math.round(g.beat * PPQ), 0);
|
|
1048
|
+
melody.push({ tick: on, on: true, note: g.midi, vel: 70, ch: 0 });
|
|
1049
|
+
melody.push({ tick: Math.max(on + 1, Math.round((g.beat + GRACE_STEP) * PPQ)), on: false, note: g.midi, vel: 0, ch: 0 });
|
|
1050
|
+
}
|
|
1051
|
+
if (ev.midi === null) return;
|
|
1029
1052
|
const start = Math.round(ev.beat * PPQ);
|
|
1030
1053
|
const targets = glideTargets(schedule.events, i);
|
|
1031
1054
|
const last = targets[targets.length - 1] ?? ev;
|
|
1032
1055
|
const end = Math.max(Math.round((last.beat + last.durationBeats) * PPQ), start + 1);
|
|
1033
|
-
ev.kan.forEach((k, gi) => {
|
|
1034
|
-
const gap = Math.round(0.12 * PPQ);
|
|
1035
|
-
const kOn = Math.max(start - gap * (ev.kan.length - gi), 0);
|
|
1036
|
-
melody.push({ tick: kOn, on: true, note: k, vel: 70, ch: 0 });
|
|
1037
|
-
melody.push({ tick: Math.max(kOn + 1, start - gap * (ev.kan.length - gi - 1)), on: false, note: k, vel: 0, ch: 0 });
|
|
1038
|
-
});
|
|
1039
1056
|
melody.push({ tick: start, on: true, note: ev.midi, vel: 100, ch: 0 });
|
|
1040
1057
|
melody.push({ tick: end, on: false, note: ev.midi, vel: 0, ch: 0 });
|
|
1041
1058
|
let from = ev;
|
|
@@ -1056,14 +1073,18 @@ function encodeMidi(schedule, opts) {
|
|
|
1056
1073
|
if (opts.name) head.push(...vlq(0), 255, 3, ...vlq(utf8(opts.name).length), ...utf8(opts.name));
|
|
1057
1074
|
head.push(...vlq(0), 255, 81, 3, usPerBeat >> 16 & 255, usPerBeat >> 8 & 255, usPerBeat & 255);
|
|
1058
1075
|
const chunks = [trackChunk(melody, head)];
|
|
1059
|
-
if (opts.drums && opts.drums.length > 0) {
|
|
1076
|
+
if (typeof opts.drums === "function" || opts.drums && opts.drums.length > 0) {
|
|
1060
1077
|
const drum = [];
|
|
1061
|
-
const
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1078
|
+
for (const seg of schedule.tempo) {
|
|
1079
|
+
const pattern = typeof opts.drums === "function" ? opts.drums(seg) : opts.drums;
|
|
1080
|
+
if (!pattern?.length) continue;
|
|
1081
|
+
const end = seg === schedule.tempo[schedule.tempo.length - 1] ? Math.ceil(schedule.totalBeats) : seg.endBeat;
|
|
1082
|
+
for (let k = 0; seg.beat + k / seg.scale < end - 1e-6; k++) {
|
|
1083
|
+
const note = DRUM_NOTE[pattern[k % pattern.length]];
|
|
1084
|
+
const t = Math.round((seg.beat + k / seg.scale) * PPQ);
|
|
1085
|
+
drum.push({ tick: t, on: true, note, vel: 100, ch: 9 });
|
|
1086
|
+
drum.push({ tick: t + Math.round(PPQ / 4), on: false, note, vel: 0, ch: 9 });
|
|
1087
|
+
}
|
|
1067
1088
|
}
|
|
1068
1089
|
chunks.push(trackChunk(drum, [...vlq(0), 255, 3, ...vlq(5), 68, 114, 117, 109, 115]));
|
|
1069
1090
|
}
|
|
@@ -1093,9 +1114,11 @@ function exportMidi(doc, options = {}) {
|
|
|
1093
1114
|
laySpeeds: options.laySpeeds
|
|
1094
1115
|
});
|
|
1095
1116
|
const bpm = options.bpm ?? doc.meta.bpm ?? 90;
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1117
|
+
const drums = options.drums ? (seg) => {
|
|
1118
|
+
const id = seg.taal?.id;
|
|
1119
|
+
if (seg.taal === null) return void 0;
|
|
1120
|
+
return drumPattern(id !== void 0 && id in TAALS ? TAALS[id] : { numBeats: 4, sam: 0 });
|
|
1121
|
+
} : void 0;
|
|
1099
1122
|
const bytes = encodeMidi(schedule, { bpm, name: options.name ?? doc.meta.title, drums });
|
|
1100
1123
|
return {
|
|
1101
1124
|
blob: new Blob([bytes], { type: "audio/midi" }),
|