@ugfoundation/swaralipi-js 0.3.0 → 0.3.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/dist/{batch-QPSHVNDS.js → batch-TVEIT2OJ.js} +4 -4
- package/dist/{batch-QPSHVNDS.js.map → batch-TVEIT2OJ.js.map} +1 -1
- package/dist/{chunk-VCRWS3F3.js → chunk-HDN3YZ6K.js} +3 -3
- package/dist/{chunk-VCRWS3F3.js.map → chunk-HDN3YZ6K.js.map} +1 -1
- package/dist/{chunk-4YTOLN3C.js → chunk-WBSIKYWB.js} +3 -3
- package/dist/{chunk-4YTOLN3C.js.map → chunk-WBSIKYWB.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 +59 -18
- package/dist/player/index.cjs.map +1 -1
- package/dist/player/index.d.cts +15 -9
- package/dist/player/index.d.ts +15 -9
- package/dist/player/index.js +60 -19
- package/dist/player/index.js.map +1 -1
- package/dist/{schedule-PTHUONrA.d.ts → schedule-BhiP_maG.d.ts} +1 -1
- package/dist/{schedule-DhO_Xzz4.d.cts → schedule-Dsb2paUE.d.cts} +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 +1 -1
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +1 -1
- package/dist/viewer/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/player/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S as Swaralipi, O as Octave, a as SvaraLetter, N as Note } from '../schema-D3wyNRqM.cjs';
|
|
2
2
|
import { T as TaalId } from '../taals-FmEulsjY.cjs';
|
|
3
|
-
import { I as InstrumentId, a as InstrumentDef, S as Schedule } from '../schedule-
|
|
4
|
-
export {
|
|
3
|
+
import { I as InstrumentId, a as InstrumentDef, S as Schedule, D as DrumVoice } from '../schedule-Dsb2paUE.cjs';
|
|
4
|
+
export { b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, d as INSTRUMENTS, P as PlayEvent, e as SALAMANDER_BASE, f as SAMPLED_TAALS, g as ScheduleOptions, T as TABLA_BPMS, h as TABLA_VARIATIONS, i as TONEJS_INSTRUMENTS_BASE, j as ToneModule, k as buildSchedule, l as drumPattern, m as instrumentSampleUrl, n as nearestTablaBpm, o as normalizeBase, p as probeUrl, q as quantizeLoopEnd, s as santoorUrls, r as subsetUrls, t as tablaBpms, u as tablaUrl } from '../schedule-Dsb2paUE.cjs';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import 'tone';
|
|
7
7
|
|
|
@@ -204,10 +204,12 @@ declare function encodeMp3(channels: Float32Array[], sampleRate: number, kbps?:
|
|
|
204
204
|
* tests) in plain Node, and carries no dependency (the SMF format is trivial),
|
|
205
205
|
* which keeps it clear of any redistribution/license question.
|
|
206
206
|
*
|
|
207
|
-
* Scope = the **melody voice
|
|
208
|
-
*
|
|
209
|
-
* a
|
|
210
|
-
*
|
|
207
|
+
* Scope = the **melody voice**, plus — when `drums` is on — the Western-drumset
|
|
208
|
+
* translation of the taal (the same `drumPattern` the player sequences) written
|
|
209
|
+
* as a **separate GM channel-10 track**. Tabla is prerecorded audio loops with
|
|
210
|
+
* no per-stroke note data, so there's nothing to turn into MIDI notes; tanpura
|
|
211
|
+
* is a fixed background drone. A `.mid` here is the notation line (+ optional
|
|
212
|
+
* drums) — the user opens it in any DAW and assigns instruments.
|
|
211
213
|
*/
|
|
212
214
|
|
|
213
215
|
interface MidiExportOptions {
|
|
@@ -219,6 +221,8 @@ interface MidiExportOptions {
|
|
|
219
221
|
bpm?: number;
|
|
220
222
|
/** Track name meta-event. Default the song title. */
|
|
221
223
|
name?: string;
|
|
224
|
+
/** Also export the taal's drumset pattern as a separate GM channel-10 track. */
|
|
225
|
+
drums?: boolean;
|
|
222
226
|
}
|
|
223
227
|
interface MidiExportResult {
|
|
224
228
|
blob: Blob;
|
|
@@ -227,12 +231,14 @@ interface MidiExportResult {
|
|
|
227
231
|
mimeType: string;
|
|
228
232
|
}
|
|
229
233
|
/**
|
|
230
|
-
* Encode a schedule to a
|
|
231
|
-
*
|
|
234
|
+
* Encode a schedule to a Standard MIDI File. Melody rides channel 0; when
|
|
235
|
+
* `drums` is given, its per-beat voices ride a second GM channel-10 track
|
|
236
|
+
* (the file becomes format 1). Pure — no Tone, no browser — directly testable.
|
|
232
237
|
*/
|
|
233
238
|
declare function encodeMidi(schedule: Schedule, opts: {
|
|
234
239
|
bpm: number;
|
|
235
240
|
name?: string;
|
|
241
|
+
drums?: DrumVoice[];
|
|
236
242
|
}): Uint8Array;
|
|
237
243
|
/**
|
|
238
244
|
* Export a swaralipi doc to a `.mid` Blob (melody voice only). No browser APIs
|
|
@@ -283,4 +289,4 @@ declare function midiToSampleName(midi: number): string;
|
|
|
283
289
|
/** MIDI → santoor sample filename stem (`cs4`): lowercase, `#` → `s`. */
|
|
284
290
|
declare function sampleFileName(midi: number): string;
|
|
285
291
|
|
|
286
|
-
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, InstrumentDef, InstrumentId, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sampleFileName, svaraSemitone, svaraToMidi };
|
|
292
|
+
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, DrumVoice, InstrumentDef, InstrumentId, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sampleFileName, svaraSemitone, svaraToMidi };
|
package/dist/player/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S as Swaralipi, O as Octave, a as SvaraLetter, N as Note } from '../schema-D3wyNRqM.js';
|
|
2
2
|
import { T as TaalId } from '../taals-FmEulsjY.js';
|
|
3
|
-
import { I as InstrumentId, a as InstrumentDef, S as Schedule } from '../schedule-
|
|
4
|
-
export {
|
|
3
|
+
import { I as InstrumentId, a as InstrumentDef, S as Schedule, D as DrumVoice } from '../schedule-BhiP_maG.js';
|
|
4
|
+
export { b as DEFAULT_SOUNDS_BASE, c as DRUM_KIT_BASE, d as INSTRUMENTS, P as PlayEvent, e as SALAMANDER_BASE, f as SAMPLED_TAALS, g as ScheduleOptions, T as TABLA_BPMS, h as TABLA_VARIATIONS, i as TONEJS_INSTRUMENTS_BASE, j as ToneModule, k as buildSchedule, l as drumPattern, m as instrumentSampleUrl, n as nearestTablaBpm, o as normalizeBase, p as probeUrl, q as quantizeLoopEnd, s as santoorUrls, r as subsetUrls, t as tablaBpms, u as tablaUrl } from '../schedule-BhiP_maG.js';
|
|
5
5
|
import 'zod';
|
|
6
6
|
import 'tone';
|
|
7
7
|
|
|
@@ -204,10 +204,12 @@ declare function encodeMp3(channels: Float32Array[], sampleRate: number, kbps?:
|
|
|
204
204
|
* tests) in plain Node, and carries no dependency (the SMF format is trivial),
|
|
205
205
|
* which keeps it clear of any redistribution/license question.
|
|
206
206
|
*
|
|
207
|
-
* Scope = the **melody voice
|
|
208
|
-
*
|
|
209
|
-
* a
|
|
210
|
-
*
|
|
207
|
+
* Scope = the **melody voice**, plus — when `drums` is on — the Western-drumset
|
|
208
|
+
* translation of the taal (the same `drumPattern` the player sequences) written
|
|
209
|
+
* as a **separate GM channel-10 track**. Tabla is prerecorded audio loops with
|
|
210
|
+
* no per-stroke note data, so there's nothing to turn into MIDI notes; tanpura
|
|
211
|
+
* is a fixed background drone. A `.mid` here is the notation line (+ optional
|
|
212
|
+
* drums) — the user opens it in any DAW and assigns instruments.
|
|
211
213
|
*/
|
|
212
214
|
|
|
213
215
|
interface MidiExportOptions {
|
|
@@ -219,6 +221,8 @@ interface MidiExportOptions {
|
|
|
219
221
|
bpm?: number;
|
|
220
222
|
/** Track name meta-event. Default the song title. */
|
|
221
223
|
name?: string;
|
|
224
|
+
/** Also export the taal's drumset pattern as a separate GM channel-10 track. */
|
|
225
|
+
drums?: boolean;
|
|
222
226
|
}
|
|
223
227
|
interface MidiExportResult {
|
|
224
228
|
blob: Blob;
|
|
@@ -227,12 +231,14 @@ interface MidiExportResult {
|
|
|
227
231
|
mimeType: string;
|
|
228
232
|
}
|
|
229
233
|
/**
|
|
230
|
-
* Encode a schedule to a
|
|
231
|
-
*
|
|
234
|
+
* Encode a schedule to a Standard MIDI File. Melody rides channel 0; when
|
|
235
|
+
* `drums` is given, its per-beat voices ride a second GM channel-10 track
|
|
236
|
+
* (the file becomes format 1). Pure — no Tone, no browser — directly testable.
|
|
232
237
|
*/
|
|
233
238
|
declare function encodeMidi(schedule: Schedule, opts: {
|
|
234
239
|
bpm: number;
|
|
235
240
|
name?: string;
|
|
241
|
+
drums?: DrumVoice[];
|
|
236
242
|
}): Uint8Array;
|
|
237
243
|
/**
|
|
238
244
|
* Export a swaralipi doc to a `.mid` Blob (melody voice only). No browser APIs
|
|
@@ -283,4 +289,4 @@ declare function midiToSampleName(midi: number): string;
|
|
|
283
289
|
/** MIDI → santoor sample filename stem (`cs4`): lowercase, `#` → `s`. */
|
|
284
290
|
declare function sampleFileName(midi: number): string;
|
|
285
291
|
|
|
286
|
-
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, InstrumentDef, InstrumentId, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sampleFileName, svaraSemitone, svaraToMidi };
|
|
292
|
+
export { type AudioExportOptions, type AudioExportResult, type AudioFormat, type BindSheetOptions, DrumVoice, InstrumentDef, InstrumentId, type MidiExportOptions, type MidiExportResult, OCTAVE_OFFSET, type PlayerOptions, type PlayerState, type RhythmMode, SHUDDHA, Schedule, SwaralipiPlayer, encodeMidi, encodeMp3, encodeWav, exportAudio, exportMidi, midiToSampleName, parseTonic, sampleFileName, svaraSemitone, svaraToMidi };
|
package/dist/player/index.js
CHANGED
|
@@ -700,34 +700,72 @@ function utf8(s) {
|
|
|
700
700
|
function u32be(n) {
|
|
701
701
|
return [n >>> 24 & 255, n >>> 16 & 255, n >>> 8 & 255, n & 255];
|
|
702
702
|
}
|
|
703
|
+
var DRUM_NOTE = {
|
|
704
|
+
kick: 36,
|
|
705
|
+
snare: 38,
|
|
706
|
+
hihat: 42,
|
|
707
|
+
// closed hi-hat
|
|
708
|
+
tom1: 48,
|
|
709
|
+
tom2: 45,
|
|
710
|
+
tom3: 41
|
|
711
|
+
};
|
|
712
|
+
function trackChunk(raw, head) {
|
|
713
|
+
raw.sort((a, b) => a.tick - b.tick || Number(a.on) - Number(b.on));
|
|
714
|
+
const track = [...head];
|
|
715
|
+
let last = 0;
|
|
716
|
+
for (const e of raw) {
|
|
717
|
+
const status = (e.on ? 144 : 128) | e.ch & 15;
|
|
718
|
+
track.push(...vlq(e.tick - last), status, e.note & 127, e.vel & 127);
|
|
719
|
+
last = e.tick;
|
|
720
|
+
}
|
|
721
|
+
track.push(...vlq(0), 255, 47, 0);
|
|
722
|
+
return [77, 84, 114, 107, ...u32be(track.length), ...track];
|
|
723
|
+
}
|
|
703
724
|
function encodeMidi(schedule, opts) {
|
|
704
|
-
const
|
|
725
|
+
const melody = [];
|
|
705
726
|
for (const ev of schedule.events) {
|
|
706
727
|
if (ev.midi === null) continue;
|
|
707
728
|
const start = Math.round(ev.beat * PPQ);
|
|
708
729
|
const end = Math.max(Math.round((ev.beat + ev.durationBeats) * PPQ), start + 1);
|
|
709
730
|
if (ev.kan !== null) {
|
|
710
731
|
const kOn = Math.max(start - Math.round(0.12 * PPQ), 0);
|
|
711
|
-
|
|
712
|
-
|
|
732
|
+
melody.push({ tick: kOn, on: true, note: ev.kan, vel: 70, ch: 0 });
|
|
733
|
+
melody.push({ tick: start, on: false, note: ev.kan, vel: 0, ch: 0 });
|
|
713
734
|
}
|
|
714
|
-
|
|
715
|
-
|
|
735
|
+
melody.push({ tick: start, on: true, note: ev.midi, vel: 100, ch: 0 });
|
|
736
|
+
melody.push({ tick: end, on: false, note: ev.midi, vel: 0, ch: 0 });
|
|
716
737
|
}
|
|
717
|
-
raw.sort((a, b) => a.tick - b.tick || Number(a.on) - Number(b.on));
|
|
718
|
-
const track = [];
|
|
719
|
-
if (opts.name) track.push(...vlq(0), 255, 3, ...vlq(utf8(opts.name).length), ...utf8(opts.name));
|
|
720
738
|
const usPerBeat = Math.round(6e7 / opts.bpm);
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
739
|
+
const head = [];
|
|
740
|
+
if (opts.name) head.push(...vlq(0), 255, 3, ...vlq(utf8(opts.name).length), ...utf8(opts.name));
|
|
741
|
+
head.push(...vlq(0), 255, 81, 3, usPerBeat >> 16 & 255, usPerBeat >> 8 & 255, usPerBeat & 255);
|
|
742
|
+
const chunks = [trackChunk(melody, head)];
|
|
743
|
+
if (opts.drums && opts.drums.length > 0) {
|
|
744
|
+
const drum = [];
|
|
745
|
+
const totalBeats = Math.ceil(schedule.totalBeats);
|
|
746
|
+
for (let beat = 0; beat < totalBeats; beat++) {
|
|
747
|
+
const note = DRUM_NOTE[opts.drums[beat % opts.drums.length]];
|
|
748
|
+
const t = beat * PPQ;
|
|
749
|
+
drum.push({ tick: t, on: true, note, vel: 100, ch: 9 });
|
|
750
|
+
drum.push({ tick: t + Math.round(PPQ / 4), on: false, note, vel: 0, ch: 9 });
|
|
751
|
+
}
|
|
752
|
+
chunks.push(trackChunk(drum, [...vlq(0), 255, 3, ...vlq(5), 68, 114, 117, 109, 115]));
|
|
753
|
+
}
|
|
754
|
+
const format = chunks.length > 1 ? 1 : 0;
|
|
755
|
+
const header = [
|
|
756
|
+
77,
|
|
757
|
+
84,
|
|
758
|
+
104,
|
|
759
|
+
100,
|
|
760
|
+
...u32be(6),
|
|
761
|
+
0,
|
|
762
|
+
format,
|
|
763
|
+
chunks.length >> 8 & 255,
|
|
764
|
+
chunks.length & 255,
|
|
765
|
+
PPQ >> 8 & 255,
|
|
766
|
+
PPQ & 255
|
|
767
|
+
];
|
|
768
|
+
return new Uint8Array([...header, ...chunks.flat()]);
|
|
731
769
|
}
|
|
732
770
|
function safeName2(title) {
|
|
733
771
|
return (title ?? "").replace(/[\\/:*?"<>|]+/g, "").trim() || "swaralipi";
|
|
@@ -735,7 +773,10 @@ function safeName2(title) {
|
|
|
735
773
|
function exportMidi(doc, options = {}) {
|
|
736
774
|
const schedule = buildSchedule(doc, { tonic: options.tonic, baseOctave: options.baseOctave });
|
|
737
775
|
const bpm = options.bpm ?? doc.meta.bpm ?? 90;
|
|
738
|
-
const
|
|
776
|
+
const taalId = doc.meta.taal?.id;
|
|
777
|
+
const taal = taalId !== void 0 && taalId in TAALS ? TAALS[taalId] : { numBeats: 4, sam: 0 };
|
|
778
|
+
const drums = options.drums ? drumPattern(taal) : void 0;
|
|
779
|
+
const bytes = encodeMidi(schedule, { bpm, name: options.name ?? doc.meta.title, drums });
|
|
739
780
|
return {
|
|
740
781
|
blob: new Blob([bytes], { type: "audio/midi" }),
|
|
741
782
|
filename: `${safeName2(doc.meta.title)}.mid`,
|