@ugfoundation/swaralipi-js 0.8.1 → 0.9.0
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-NDL6CW7Q.js → batch-PYBXQ4OM.js} +5 -5
- package/dist/{batch-NDL6CW7Q.js.map → batch-PYBXQ4OM.js.map} +1 -1
- package/dist/{chunk-LPCKL3AM.js → chunk-3ZQPM2CE.js} +28 -19
- package/dist/chunk-3ZQPM2CE.js.map +1 -0
- package/dist/{chunk-4IVUPMRK.js → chunk-7SMRG4IS.js} +14 -9
- package/dist/chunk-7SMRG4IS.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-Z42M5JAA.js → chunk-RT4SVJMK.js} +5 -4
- package/dist/chunk-RT4SVJMK.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 +80 -48
- 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 +68 -46
- package/dist/player/index.js.map +1 -1
- package/dist/{schedule-B_UaluBi.d.cts → schedule-9uvjnCG_.d.ts} +15 -10
- package/dist/{schedule-CdILTNsk.d.ts → schedule-TxSfHL-T.d.cts} +15 -10
- 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 +306 -178
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +36 -12
- package/dist/viewer/index.d.ts +36 -12
- package/dist/viewer/index.js +234 -135
- 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-LPCKL3AM.js.map +0 -1
- package/dist/chunk-Z42M5JAA.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 GlideLeg, d as INSTRUMENTS, M as MEEND_HOLD, P as PlayEvent, e as SALAMANDER_BASE, f as SAMPLED_TAALS, g as ScheduleOptions,
|
|
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-TxSfHL-T.cjs';
|
|
5
|
+
export { A as ARC_RAW_RE, b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, G as GlideLeg, d as INSTRUMENTS, M as MEEND_HOLD, P as PlayEvent, e as SALAMANDER_BASE, f as SAMPLED_TAALS, g as ScheduleOptions, h as TABLA_BPMS, i as TABLA_VARIATIONS, j as TONEJS_INSTRUMENTS_BASE, k as ToneModule, l as buildSchedule, m as createBuffers, n as drumPattern, o as glideTargets, p as instrumentSampleUrl, q as isArcRaw, r as meendContinuations, s as nearestSampleKey, t as nearestTablaBpm, u as normalizeBase, v as probeUrl, w as quantizeLoopEnd, x as santoorUrls, y as subsetUrls, z as tablaBpms, B as tablaUrl, C as triggerGlide } from '../schedule-TxSfHL-T.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 GlideLeg, d as INSTRUMENTS, M as MEEND_HOLD, P as PlayEvent, e as SALAMANDER_BASE, f as SAMPLED_TAALS, g as ScheduleOptions,
|
|
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-9uvjnCG_.js';
|
|
5
|
+
export { A as ARC_RAW_RE, b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, G as GlideLeg, d as INSTRUMENTS, M as MEEND_HOLD, P as PlayEvent, e as SALAMANDER_BASE, f as SAMPLED_TAALS, g as ScheduleOptions, h as TABLA_BPMS, i as TABLA_VARIATIONS, j as TONEJS_INSTRUMENTS_BASE, k as ToneModule, l as buildSchedule, m as createBuffers, n as drumPattern, o as glideTargets, p as instrumentSampleUrl, q as isArcRaw, r as meendContinuations, s as nearestSampleKey, t as nearestTablaBpm, u as normalizeBase, v as probeUrl, w as quantizeLoopEnd, x as santoorUrls, y as subsetUrls, z as tablaBpms, B as tablaUrl, C as triggerGlide } from '../schedule-9uvjnCG_.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, midiToSampleName, glideTargets, triggerGlide, createSampler, createBuffers, tablaShiftSemitones, tablaUrl, TABLA_GRAIN_OVERLAP_SEC, TABLA_GRAIN_SEC, createDrumKit, drumPattern, createMetronome, TANPURA_PCS, createTanpura, parseTonic, MEEND_HOLD, sCurve } from '../chunk-7SMRG4IS.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-7SMRG4IS.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;
|
|
@@ -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
|
|
@@ -561,34 +571,35 @@ var SwaralipiPlayer = class {
|
|
|
561
571
|
return entry;
|
|
562
572
|
}
|
|
563
573
|
/**
|
|
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
|
|
574
|
+
* Accompaniment, one লয় / তাল segment at a time. A tempo change under the
|
|
575
|
+
* melody is a real tempo change under the drum: the tabla loop is rebuilt at
|
|
576
|
+
* the segment's own bpm — its own recorded file when the set has one at that
|
|
567
577
|
* tempo, else the nearest file time-stretched by `GrainPlayer` (which
|
|
568
578
|
* stretches *without* transposing, unlike a plain playbackRate) — and the
|
|
569
|
-
* click / drum / drone patterns re-space their interval. A
|
|
570
|
-
*
|
|
579
|
+
* click / drum / drone patterns re-space their interval. A তালফেরতা swaps the
|
|
580
|
+
* theka the same way: each segment loops its own taal's file (or pattern, or
|
|
581
|
+
* click cycle), and a মুক্তছন্দ segment rests. A document with neither mark
|
|
582
|
+
* has exactly one segment, so this is the old single-loop path.
|
|
571
583
|
*/
|
|
572
584
|
#buildRhythm(Tone, transport, base, spb, segments, shift) {
|
|
573
585
|
this.#disposeTabla();
|
|
574
586
|
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;
|
|
587
|
+
const rhythm = this.#opts.rhythm;
|
|
588
|
+
if (rhythm === "none" || base === void 0 && rhythm !== "drums") return;
|
|
581
589
|
segments.forEach((seg, i) => {
|
|
590
|
+
const own = this.#segmentTaal(seg);
|
|
591
|
+
if (own === null) return;
|
|
592
|
+
const taalId = own !== void 0 && own.id in TAALS ? own.id : void 0;
|
|
582
593
|
const from = i === 0 ? 0 : seg.beat * spb + shift;
|
|
583
594
|
const to = i === segments.length - 1 ? Infinity : seg.endBeat * spb + shift;
|
|
584
595
|
const beatSec = spb / seg.scale;
|
|
585
596
|
const span = to === Infinity ? void 0 : to - from;
|
|
586
|
-
if (
|
|
597
|
+
if (rhythm === "tabla" && taalId !== void 0 && SAMPLED_TAALS.has(taalId) && base !== void 0) {
|
|
587
598
|
const bpm = 60 / beatSec;
|
|
588
599
|
const fileBpm = nearestTablaBpm(bpm, tablaBpms(taalId));
|
|
589
600
|
const rate = bpm / fileBpm;
|
|
590
601
|
const semis = tablaShiftSemitones(this.#tonicSemitone());
|
|
591
|
-
const url = tablaUrl(base, taalId, fileBpm, this.#variation());
|
|
602
|
+
const url = tablaUrl(base, taalId, fileBpm, this.#variation(own));
|
|
592
603
|
const loop = (rate === 1 && semis === 0 ? new Tone.Player({ url, loop: true }) : new Tone.GrainPlayer({
|
|
593
604
|
url,
|
|
594
605
|
loop: true,
|
|
@@ -610,9 +621,10 @@ var SwaralipiPlayer = class {
|
|
|
610
621
|
this.#tabla.push({ loop, fileSpb: 60 / fileBpm });
|
|
611
622
|
return;
|
|
612
623
|
}
|
|
613
|
-
if (
|
|
624
|
+
if (rhythm === "drums") {
|
|
614
625
|
this.#drums ??= createDrumKit(Tone).connect(master);
|
|
615
626
|
const drums = this.#drums;
|
|
627
|
+
const pattern = drumPattern(this.#taal ?? (taalId !== void 0 ? TAALS[taalId] : own) ?? { numBeats: 4, sam: 0 });
|
|
616
628
|
let beat2 = 0;
|
|
617
629
|
this.#scheduleIds.push(
|
|
618
630
|
transport.scheduleRepeat(
|
|
@@ -630,6 +642,7 @@ var SwaralipiPlayer = class {
|
|
|
630
642
|
}
|
|
631
643
|
this.#metronome ??= createMetronome(Tone, base).connect(master);
|
|
632
644
|
const metro = this.#metronome;
|
|
645
|
+
const cycle = (this.#taal ?? seg.taal)?.numBeats ?? 4;
|
|
633
646
|
let beat = 0;
|
|
634
647
|
this.#scheduleIds.push(
|
|
635
648
|
transport.scheduleRepeat(
|
|
@@ -705,7 +718,7 @@ function pickDef(id, o) {
|
|
|
705
718
|
return def;
|
|
706
719
|
}
|
|
707
720
|
function resolveTaal(doc, taal) {
|
|
708
|
-
const id = taal !== void 0 && taal !== "auto" ? taal : doc.meta.taal?.id;
|
|
721
|
+
const id = taal !== void 0 && taal !== "auto" ? taal : (doc.parts[0]?.rows[0]?.taal || doc.meta.taal)?.id;
|
|
709
722
|
return id !== void 0 && id in TAALS ? id : void 0;
|
|
710
723
|
}
|
|
711
724
|
function safeName(title) {
|
|
@@ -728,7 +741,7 @@ async function exportAudio(doc, options = {}) {
|
|
|
728
741
|
});
|
|
729
742
|
const range = midiRange2(schedule);
|
|
730
743
|
const taalId = resolveTaal(doc, options.taal);
|
|
731
|
-
const
|
|
744
|
+
const pinned = options.taal !== void 0 && options.taal !== "auto" && taalId !== void 0 ? TAALS[taalId] : void 0;
|
|
732
745
|
const usesTabla = rhythm === "tabla" && taalId !== void 0 && SAMPLED_TAALS.has(taalId) && !!base;
|
|
733
746
|
const reqBpm = options.bpm ?? doc.meta.bpm ?? 90;
|
|
734
747
|
const bpm = usesTabla && taalId ? nearestTablaBpm(reqBpm, tablaBpms(taalId)) : reqBpm;
|
|
@@ -780,22 +793,22 @@ async function exportAudio(doc, options = {}) {
|
|
|
780
793
|
}
|
|
781
794
|
const tablas = [];
|
|
782
795
|
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
796
|
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;
|
|
797
|
+
let metro;
|
|
788
798
|
const semis = tablaShiftSemitones(parseTonic(options.tonic ?? doc.meta.tonic));
|
|
789
799
|
schedule.tempo.forEach((seg, i) => {
|
|
800
|
+
const own = pinned ?? seg.taal;
|
|
801
|
+
if (own === null) return;
|
|
802
|
+
const segId = own !== void 0 && own.id in TAALS ? own.id : void 0;
|
|
790
803
|
const from = i === 0 ? 0 : seg.beat * spb + shift;
|
|
791
804
|
const to = i === schedule.tempo.length - 1 ? Infinity : seg.endBeat * spb + shift;
|
|
792
805
|
const beatSec = spb / seg.scale;
|
|
793
806
|
const span = to === Infinity ? void 0 : to - from;
|
|
794
|
-
if (
|
|
807
|
+
if (rhythm === "tabla" && segId !== void 0 && SAMPLED_TAALS.has(segId)) {
|
|
795
808
|
const segBpm = 60 / beatSec;
|
|
796
|
-
const fileBpm = nearestTablaBpm(segBpm, tablaBpms(
|
|
809
|
+
const fileBpm = nearestTablaBpm(segBpm, tablaBpms(segId));
|
|
797
810
|
const rate = segBpm / fileBpm;
|
|
798
|
-
const url = tablaUrl(base,
|
|
811
|
+
const url = tablaUrl(base, segId, fileBpm, pinned === void 0 ? own?.variation : void 0);
|
|
799
812
|
const loop = (rate === 1 && semis === 0 ? new Tone.Player({ url, loop: true }) : new Tone.GrainPlayer({
|
|
800
813
|
url,
|
|
801
814
|
loop: true,
|
|
@@ -814,6 +827,7 @@ async function exportAudio(doc, options = {}) {
|
|
|
814
827
|
}
|
|
815
828
|
tablas.push({ loop, fileSpb: 60 / fileBpm });
|
|
816
829
|
} else if (drums !== void 0) {
|
|
830
|
+
const pattern = drumPattern(segId !== void 0 ? TAALS[segId] : own ?? { numBeats: 4, sam: 0 });
|
|
817
831
|
let beat = 0;
|
|
818
832
|
transport.scheduleRepeat(
|
|
819
833
|
(time) => {
|
|
@@ -825,12 +839,14 @@ async function exportAudio(doc, options = {}) {
|
|
|
825
839
|
from,
|
|
826
840
|
span
|
|
827
841
|
);
|
|
828
|
-
} else
|
|
842
|
+
} else {
|
|
843
|
+
const click = metro ??= createMetronome(Tone, base).connect(master);
|
|
844
|
+
const cycle = own?.numBeats ?? 4;
|
|
829
845
|
let beat = 0;
|
|
830
846
|
transport.scheduleRepeat(
|
|
831
847
|
(time) => {
|
|
832
|
-
|
|
833
|
-
|
|
848
|
+
click.volume.setValueAtTime(beat % cycle === 0 ? 0 : -8, time);
|
|
849
|
+
click.start(time);
|
|
834
850
|
beat += 1;
|
|
835
851
|
},
|
|
836
852
|
beatSec,
|
|
@@ -1056,14 +1072,18 @@ function encodeMidi(schedule, opts) {
|
|
|
1056
1072
|
if (opts.name) head.push(...vlq(0), 255, 3, ...vlq(utf8(opts.name).length), ...utf8(opts.name));
|
|
1057
1073
|
head.push(...vlq(0), 255, 81, 3, usPerBeat >> 16 & 255, usPerBeat >> 8 & 255, usPerBeat & 255);
|
|
1058
1074
|
const chunks = [trackChunk(melody, head)];
|
|
1059
|
-
if (opts.drums && opts.drums.length > 0) {
|
|
1075
|
+
if (typeof opts.drums === "function" || opts.drums && opts.drums.length > 0) {
|
|
1060
1076
|
const drum = [];
|
|
1061
|
-
const
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1077
|
+
for (const seg of schedule.tempo) {
|
|
1078
|
+
const pattern = typeof opts.drums === "function" ? opts.drums(seg) : opts.drums;
|
|
1079
|
+
if (!pattern?.length) continue;
|
|
1080
|
+
const end = seg === schedule.tempo[schedule.tempo.length - 1] ? Math.ceil(schedule.totalBeats) : seg.endBeat;
|
|
1081
|
+
for (let k = 0; seg.beat + k / seg.scale < end - 1e-6; k++) {
|
|
1082
|
+
const note = DRUM_NOTE[pattern[k % pattern.length]];
|
|
1083
|
+
const t = Math.round((seg.beat + k / seg.scale) * PPQ);
|
|
1084
|
+
drum.push({ tick: t, on: true, note, vel: 100, ch: 9 });
|
|
1085
|
+
drum.push({ tick: t + Math.round(PPQ / 4), on: false, note, vel: 0, ch: 9 });
|
|
1086
|
+
}
|
|
1067
1087
|
}
|
|
1068
1088
|
chunks.push(trackChunk(drum, [...vlq(0), 255, 3, ...vlq(5), 68, 114, 117, 109, 115]));
|
|
1069
1089
|
}
|
|
@@ -1093,9 +1113,11 @@ function exportMidi(doc, options = {}) {
|
|
|
1093
1113
|
laySpeeds: options.laySpeeds
|
|
1094
1114
|
});
|
|
1095
1115
|
const bpm = options.bpm ?? doc.meta.bpm ?? 90;
|
|
1096
|
-
const
|
|
1097
|
-
|
|
1098
|
-
|
|
1116
|
+
const drums = options.drums ? (seg) => {
|
|
1117
|
+
const id = seg.taal?.id;
|
|
1118
|
+
if (seg.taal === null) return void 0;
|
|
1119
|
+
return drumPattern(id !== void 0 && id in TAALS ? TAALS[id] : { numBeats: 4, sam: 0 });
|
|
1120
|
+
} : void 0;
|
|
1099
1121
|
const bytes = encodeMidi(schedule, { bpm, name: options.name ?? doc.meta.title, drums });
|
|
1100
1122
|
return {
|
|
1101
1123
|
blob: new Blob([bytes], { type: "audio/midi" }),
|