@onjmin/koe 1.0.4 → 1.0.6

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/index.js CHANGED
@@ -1,12 +1,50 @@
1
1
  // src/converter/frq.ts
2
- function parseFrqAverageF0(buffer) {
3
- if (buffer.byteLength < 20) return null;
2
+ var HEADER_SIZE = 40;
3
+ function parseFrq(buffer) {
4
+ if (buffer.byteLength < HEADER_SIZE) return null;
4
5
  const view = new DataView(buffer);
5
6
  let header = "";
6
7
  for (let i = 0; i < 8; i++) header += String.fromCharCode(view.getUint8(i));
7
8
  if (header !== "FREQ0003") return null;
8
- const avg = view.getFloat64(12, true);
9
- return Number.isFinite(avg) && avg > 0 ? avg : null;
9
+ const hopSize = view.getInt32(8, true);
10
+ const averageF0 = view.getFloat64(12, true);
11
+ const declared = view.getInt32(36, true);
12
+ const available = Math.floor((buffer.byteLength - HEADER_SIZE) / 16);
13
+ const length = Math.max(0, Math.min(declared, available));
14
+ const f0 = new Float64Array(length);
15
+ const amp = new Float64Array(length);
16
+ for (let i = 0; i < length; i++) {
17
+ const p = HEADER_SIZE + i * 16;
18
+ f0[i] = view.getFloat64(p, true);
19
+ amp[i] = view.getFloat64(p + 8, true);
20
+ }
21
+ return {
22
+ hopSize: hopSize > 0 ? hopSize : 256,
23
+ averageF0: Number.isFinite(averageF0) && averageF0 > 0 ? averageF0 : 0,
24
+ f0,
25
+ amp
26
+ };
27
+ }
28
+ function frqAverageF0InRange(frq, startMs, endMs, sourceRate) {
29
+ if (!(sourceRate > 0) || frq.f0.length === 0) return 0;
30
+ const perFrameMs = frq.hopSize / sourceRate * 1e3;
31
+ if (!(perFrameMs > 0)) return 0;
32
+ const first = Math.max(0, Math.floor(startMs / perFrameMs));
33
+ const last = Math.min(frq.f0.length - 1, Math.ceil(endMs / perFrameMs));
34
+ let num = 0;
35
+ let den = 0;
36
+ for (let i = first; i <= last; i++) {
37
+ const hz = frq.f0[i];
38
+ if (!(hz > 0)) continue;
39
+ const w = frq.amp[i] > 0 ? frq.amp[i] : 1;
40
+ num += hz * w;
41
+ den += w;
42
+ }
43
+ return den > 0 ? num / den : 0;
44
+ }
45
+ function parseFrqAverageF0(buffer) {
46
+ const frq = parseFrq(buffer);
47
+ return frq && frq.averageF0 > 0 ? frq.averageF0 : null;
10
48
  }
11
49
  function frqFileName(wavName) {
12
50
  const dot = wavName.lastIndexOf(".");
@@ -94,11 +132,25 @@ function msToSamples(ms) {
94
132
  return Math.round(ms / 1e3 * TARGET_RATE);
95
133
  }
96
134
  var clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
135
+ function otoRegion(pcmLength, oto) {
136
+ const start = clamp(msToSamples(oto.offset), 0, pcmLength);
137
+ const end = oto.cutoff < 0 ? clamp(start + msToSamples(-oto.cutoff), start, pcmLength) : clamp(pcmLength - msToSamples(oto.cutoff), start, pcmLength);
138
+ return { start, end };
139
+ }
140
+ function centerSlice(slice) {
141
+ const out = new Int16Array(slice.length);
142
+ if (slice.length === 0) return out;
143
+ let sum = 0;
144
+ for (let i = 0; i < slice.length; i++) sum += slice[i];
145
+ const dc = Math.round(sum / slice.length);
146
+ for (let i = 0; i < slice.length; i++) {
147
+ out[i] = clamp(slice[i] - dc, -32768, 32767);
148
+ }
149
+ return out;
150
+ }
97
151
  function trimToOto(pcm, oto, recordedPitch = 0) {
98
- const full = pcm.length;
99
- const start = clamp(msToSamples(oto.offset), 0, full);
100
- const end = oto.cutoff < 0 ? clamp(start + msToSamples(-oto.cutoff), start, full) : clamp(full - msToSamples(oto.cutoff), start, full);
101
- const slice = pcm.subarray(start, end);
152
+ const { start, end } = otoRegion(pcm.length, oto);
153
+ const slice = centerSlice(pcm.subarray(start, end));
102
154
  const length = slice.length;
103
155
  const pre = clamp(msToSamples(oto.pre), 0, length);
104
156
  const overlap = clamp(msToSamples(oto.overlap), 0, length);
@@ -262,11 +314,14 @@ function toInt16(samples) {
262
314
  }
263
315
  return out;
264
316
  }
265
- function normalizePcm(buf) {
317
+ function readWavPcm48k(buf) {
266
318
  const wav = parseWav(buf);
267
319
  const mono = toMono(wav);
268
320
  const resampled = resample(mono, 48e3);
269
- return toInt16(resampled.samples);
321
+ return { pcm: toInt16(resampled.samples), sourceRate: wav.sampleRate };
322
+ }
323
+ function normalizePcm(buf) {
324
+ return readWavPcm48k(buf).pcm;
270
325
  }
271
326
  function readFourCC(view, pos) {
272
327
  return String.fromCharCode(
@@ -277,6 +332,529 @@ function readFourCC(view, pos) {
277
332
  );
278
333
  }
279
334
 
335
+ // node_modules/.pnpm/fflate@0.8.3/node_modules/fflate/esm/browser.js
336
+ var u8 = Uint8Array;
337
+ var u16 = Uint16Array;
338
+ var i32 = Int32Array;
339
+ var fleb = new u8([
340
+ 0,
341
+ 0,
342
+ 0,
343
+ 0,
344
+ 0,
345
+ 0,
346
+ 0,
347
+ 0,
348
+ 1,
349
+ 1,
350
+ 1,
351
+ 1,
352
+ 2,
353
+ 2,
354
+ 2,
355
+ 2,
356
+ 3,
357
+ 3,
358
+ 3,
359
+ 3,
360
+ 4,
361
+ 4,
362
+ 4,
363
+ 4,
364
+ 5,
365
+ 5,
366
+ 5,
367
+ 5,
368
+ 0,
369
+ /* unused */
370
+ 0,
371
+ 0,
372
+ /* impossible */
373
+ 0
374
+ ]);
375
+ var fdeb = new u8([
376
+ 0,
377
+ 0,
378
+ 0,
379
+ 0,
380
+ 1,
381
+ 1,
382
+ 2,
383
+ 2,
384
+ 3,
385
+ 3,
386
+ 4,
387
+ 4,
388
+ 5,
389
+ 5,
390
+ 6,
391
+ 6,
392
+ 7,
393
+ 7,
394
+ 8,
395
+ 8,
396
+ 9,
397
+ 9,
398
+ 10,
399
+ 10,
400
+ 11,
401
+ 11,
402
+ 12,
403
+ 12,
404
+ 13,
405
+ 13,
406
+ /* unused */
407
+ 0,
408
+ 0
409
+ ]);
410
+ var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
411
+ var freb = function(eb, start) {
412
+ var b = new u16(31);
413
+ for (var i = 0; i < 31; ++i) {
414
+ b[i] = start += 1 << eb[i - 1];
415
+ }
416
+ var r = new i32(b[30]);
417
+ for (var i = 1; i < 30; ++i) {
418
+ for (var j = b[i]; j < b[i + 1]; ++j) {
419
+ r[j] = j - b[i] << 5 | i;
420
+ }
421
+ }
422
+ return { b, r };
423
+ };
424
+ var _a = freb(fleb, 2);
425
+ var fl = _a.b;
426
+ var revfl = _a.r;
427
+ fl[28] = 258, revfl[258] = 28;
428
+ var _b = freb(fdeb, 0);
429
+ var fd = _b.b;
430
+ var revfd = _b.r;
431
+ var rev = new u16(32768);
432
+ for (i = 0; i < 32768; ++i) {
433
+ x = (i & 43690) >> 1 | (i & 21845) << 1;
434
+ x = (x & 52428) >> 2 | (x & 13107) << 2;
435
+ x = (x & 61680) >> 4 | (x & 3855) << 4;
436
+ rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
437
+ }
438
+ var x;
439
+ var i;
440
+ var hMap = (function(cd, mb, r) {
441
+ var s = cd.length;
442
+ var i = 0;
443
+ var l = new u16(mb);
444
+ for (; i < s; ++i) {
445
+ if (cd[i])
446
+ ++l[cd[i] - 1];
447
+ }
448
+ var le = new u16(mb);
449
+ for (i = 1; i < mb; ++i) {
450
+ le[i] = le[i - 1] + l[i - 1] << 1;
451
+ }
452
+ var co;
453
+ if (r) {
454
+ co = new u16(1 << mb);
455
+ var rvb = 15 - mb;
456
+ for (i = 0; i < s; ++i) {
457
+ if (cd[i]) {
458
+ var sv = i << 4 | cd[i];
459
+ var r_1 = mb - cd[i];
460
+ var v = le[cd[i] - 1]++ << r_1;
461
+ for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
462
+ co[rev[v] >> rvb] = sv;
463
+ }
464
+ }
465
+ }
466
+ } else {
467
+ co = new u16(s);
468
+ for (i = 0; i < s; ++i) {
469
+ if (cd[i]) {
470
+ co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
471
+ }
472
+ }
473
+ }
474
+ return co;
475
+ });
476
+ var flt = new u8(288);
477
+ for (i = 0; i < 144; ++i)
478
+ flt[i] = 8;
479
+ var i;
480
+ for (i = 144; i < 256; ++i)
481
+ flt[i] = 9;
482
+ var i;
483
+ for (i = 256; i < 280; ++i)
484
+ flt[i] = 7;
485
+ var i;
486
+ for (i = 280; i < 288; ++i)
487
+ flt[i] = 8;
488
+ var i;
489
+ var fdt = new u8(32);
490
+ for (i = 0; i < 32; ++i)
491
+ fdt[i] = 5;
492
+ var i;
493
+ var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
494
+ var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
495
+ var max = function(a) {
496
+ var m = a[0];
497
+ for (var i = 1; i < a.length; ++i) {
498
+ if (a[i] > m)
499
+ m = a[i];
500
+ }
501
+ return m;
502
+ };
503
+ var bits = function(d, p, m) {
504
+ var o = p / 8 | 0;
505
+ return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
506
+ };
507
+ var bits16 = function(d, p) {
508
+ var o = p / 8 | 0;
509
+ return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
510
+ };
511
+ var shft = function(p) {
512
+ return (p + 7) / 8 | 0;
513
+ };
514
+ var slc = function(v, s, e) {
515
+ if (s == null || s < 0)
516
+ s = 0;
517
+ if (e == null || e > v.length)
518
+ e = v.length;
519
+ return new u8(v.subarray(s, e));
520
+ };
521
+ var ec = [
522
+ "unexpected EOF",
523
+ "invalid block type",
524
+ "invalid length/literal",
525
+ "invalid distance",
526
+ "stream finished",
527
+ "no stream handler",
528
+ ,
529
+ // determined by compression function
530
+ "no callback",
531
+ "invalid UTF-8 data",
532
+ "extra field too long",
533
+ "date not in range 1980-2099",
534
+ "filename too long",
535
+ "stream finishing",
536
+ "invalid zip data"
537
+ // determined by unknown compression method
538
+ ];
539
+ var err = function(ind, msg, nt) {
540
+ var e = new Error(msg || ec[ind]);
541
+ e.code = ind;
542
+ if (Error.captureStackTrace)
543
+ Error.captureStackTrace(e, err);
544
+ if (!nt)
545
+ throw e;
546
+ return e;
547
+ };
548
+ var inflt = function(dat, st, buf, dict) {
549
+ var sl = dat.length, dl = dict ? dict.length : 0;
550
+ if (!sl || st.f && !st.l)
551
+ return buf || new u8(0);
552
+ var noBuf = !buf;
553
+ var resize = noBuf || st.i != 2;
554
+ var noSt = st.i;
555
+ if (noBuf)
556
+ buf = new u8(sl * 3);
557
+ var cbuf = function(l2) {
558
+ var bl = buf.length;
559
+ if (l2 > bl) {
560
+ var nbuf = new u8(Math.max(bl * 2, l2));
561
+ nbuf.set(buf);
562
+ buf = nbuf;
563
+ }
564
+ };
565
+ var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
566
+ var tbts = sl * 8;
567
+ do {
568
+ if (!lm) {
569
+ final = bits(dat, pos, 1);
570
+ var type = bits(dat, pos + 1, 3);
571
+ pos += 3;
572
+ if (!type) {
573
+ var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
574
+ if (t > sl) {
575
+ if (noSt)
576
+ err(0);
577
+ break;
578
+ }
579
+ if (resize)
580
+ cbuf(bt + l);
581
+ buf.set(dat.subarray(s, t), bt);
582
+ st.b = bt += l, st.p = pos = t * 8, st.f = final;
583
+ continue;
584
+ } else if (type == 1)
585
+ lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
586
+ else if (type == 2) {
587
+ var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
588
+ var tl = hLit + bits(dat, pos + 5, 31) + 1;
589
+ pos += 14;
590
+ var ldt = new u8(tl);
591
+ var clt = new u8(19);
592
+ for (var i = 0; i < hcLen; ++i) {
593
+ clt[clim[i]] = bits(dat, pos + i * 3, 7);
594
+ }
595
+ pos += hcLen * 3;
596
+ var clb = max(clt), clbmsk = (1 << clb) - 1;
597
+ var clm = hMap(clt, clb, 1);
598
+ for (var i = 0; i < tl; ) {
599
+ var r = clm[bits(dat, pos, clbmsk)];
600
+ pos += r & 15;
601
+ var s = r >> 4;
602
+ if (s < 16) {
603
+ ldt[i++] = s;
604
+ } else {
605
+ var c = 0, n = 0;
606
+ if (s == 16)
607
+ n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
608
+ else if (s == 17)
609
+ n = 3 + bits(dat, pos, 7), pos += 3;
610
+ else if (s == 18)
611
+ n = 11 + bits(dat, pos, 127), pos += 7;
612
+ while (n--)
613
+ ldt[i++] = c;
614
+ }
615
+ }
616
+ var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
617
+ lbt = max(lt);
618
+ dbt = max(dt);
619
+ lm = hMap(lt, lbt, 1);
620
+ dm = hMap(dt, dbt, 1);
621
+ } else
622
+ err(1);
623
+ if (pos > tbts) {
624
+ if (noSt)
625
+ err(0);
626
+ break;
627
+ }
628
+ }
629
+ if (resize)
630
+ cbuf(bt + 131072);
631
+ var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
632
+ var lpos = pos;
633
+ for (; ; lpos = pos) {
634
+ var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
635
+ pos += c & 15;
636
+ if (pos > tbts) {
637
+ if (noSt)
638
+ err(0);
639
+ break;
640
+ }
641
+ if (!c)
642
+ err(2);
643
+ if (sym < 256)
644
+ buf[bt++] = sym;
645
+ else if (sym == 256) {
646
+ lpos = pos, lm = null;
647
+ break;
648
+ } else {
649
+ var add = sym - 254;
650
+ if (sym > 264) {
651
+ var i = sym - 257, b = fleb[i];
652
+ add = bits(dat, pos, (1 << b) - 1) + fl[i];
653
+ pos += b;
654
+ }
655
+ var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
656
+ if (!d)
657
+ err(3);
658
+ pos += d & 15;
659
+ var dt = fd[dsym];
660
+ if (dsym > 3) {
661
+ var b = fdeb[dsym];
662
+ dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
663
+ }
664
+ if (pos > tbts) {
665
+ if (noSt)
666
+ err(0);
667
+ break;
668
+ }
669
+ if (resize)
670
+ cbuf(bt + 131072);
671
+ var end = bt + add;
672
+ if (bt < dt) {
673
+ var shift = dl - dt, dend = Math.min(dt, end);
674
+ if (shift + bt < 0)
675
+ err(3);
676
+ for (; bt < dend; ++bt)
677
+ buf[bt] = dict[shift + bt];
678
+ }
679
+ for (; bt < end; ++bt)
680
+ buf[bt] = buf[bt - dt];
681
+ }
682
+ }
683
+ st.l = lm, st.p = lpos, st.b = bt, st.f = final;
684
+ if (lm)
685
+ final = 1, st.m = lbt, st.d = dm, st.n = dbt;
686
+ } while (!final);
687
+ return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
688
+ };
689
+ var et = /* @__PURE__ */ new u8(0);
690
+ var b2 = function(d, b) {
691
+ return d[b] | d[b + 1] << 8;
692
+ };
693
+ var b4 = function(d, b) {
694
+ return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
695
+ };
696
+ var b8 = function(d, b) {
697
+ return b4(d, b) + b4(d, b + 4) * 4294967296;
698
+ };
699
+ function inflateSync(data, opts) {
700
+ return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
701
+ }
702
+ var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
703
+ var tds = 0;
704
+ try {
705
+ td.decode(et, { stream: true });
706
+ tds = 1;
707
+ } catch (e) {
708
+ }
709
+ var dutf8 = function(d) {
710
+ for (var r = "", i = 0; ; ) {
711
+ var c = d[i++];
712
+ var eb = (c > 127) + (c > 223) + (c > 239);
713
+ if (i + eb > d.length)
714
+ return { s: r, r: slc(d, i - 1) };
715
+ if (!eb)
716
+ r += String.fromCharCode(c);
717
+ else if (eb == 3) {
718
+ c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
719
+ } else if (eb & 1)
720
+ r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
721
+ else
722
+ r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
723
+ }
724
+ };
725
+ function strFromU8(dat, latin1) {
726
+ if (latin1) {
727
+ var r = "";
728
+ for (var i = 0; i < dat.length; i += 16384)
729
+ r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
730
+ return r;
731
+ } else if (td) {
732
+ return td.decode(dat);
733
+ } else {
734
+ var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
735
+ if (r.length)
736
+ err(8);
737
+ return s;
738
+ }
739
+ }
740
+ var slzh = function(d, b) {
741
+ return b + 30 + b2(d, b + 26) + b2(d, b + 28);
742
+ };
743
+ var zh = function(d, b, z) {
744
+ var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl;
745
+ var _a2 = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2];
746
+ return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
747
+ };
748
+ var z64hs = function(d, b, l, z, sc, su, off) {
749
+ var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
750
+ var nf = nsc + nsu + noff;
751
+ if (z && nf) {
752
+ for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
753
+ if (b2(d, b) == 1) {
754
+ return [
755
+ nsc ? b8(d, b + 4 + 8 * nsu) : sc,
756
+ nsu ? b8(d, b + 4) : su,
757
+ noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
758
+ 1
759
+ ];
760
+ }
761
+ }
762
+ if (z < 2)
763
+ err(13);
764
+ }
765
+ return [sc, su, off, 0];
766
+ };
767
+ function unzipSync(data, opts) {
768
+ var files = {};
769
+ var e = data.length - 22;
770
+ for (; b4(data, e) != 101010256; --e) {
771
+ if (!e || data.length - e > 65558)
772
+ err(13);
773
+ }
774
+ ;
775
+ var c = b2(data, e + 8);
776
+ if (!c)
777
+ return {};
778
+ var o = b4(data, e + 16);
779
+ var z = b4(data, e - 20) == 117853008;
780
+ if (z) {
781
+ var ze = b4(data, e - 12);
782
+ z = b4(data, ze) == 101075792;
783
+ if (z) {
784
+ c = b4(data, ze + 32);
785
+ o = b4(data, ze + 48);
786
+ }
787
+ }
788
+ var fltr = opts && opts.filter;
789
+ for (var i = 0; i < c; ++i) {
790
+ var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
791
+ o = no;
792
+ if (!fltr || fltr({
793
+ name: fn,
794
+ size: sc,
795
+ originalSize: su,
796
+ compression: c_2
797
+ })) {
798
+ if (!c_2)
799
+ files[fn] = slc(data, b, b + sc);
800
+ else if (c_2 == 8)
801
+ files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
802
+ else
803
+ err(14, "unknown compression type " + c_2);
804
+ }
805
+ }
806
+ return files;
807
+ }
808
+
809
+ // src/converter/zip.ts
810
+ function unzipToFileMap(data) {
811
+ const bytes = new Uint8Array(data);
812
+ const unzipped = unzipSync(bytes);
813
+ const isUtf8ByIndex = readUtf8Flags(bytes);
814
+ const sjisDecoder = new TextDecoder("shift_jis");
815
+ const fileMap = {};
816
+ Object.keys(unzipped).forEach((rawName, i) => {
817
+ const fileBytes = unzipped[rawName];
818
+ const name = isUtf8ByIndex[i] ? rawName : sjisDecoder.decode(Uint8Array.from(rawName, (c) => c.charCodeAt(0)));
819
+ const path = name.replace(/\\/g, "/");
820
+ if (path.endsWith("/")) return;
821
+ fileMap[path] = {
822
+ arrayBuffer: () => Promise.resolve(
823
+ fileBytes.buffer.slice(
824
+ fileBytes.byteOffset,
825
+ fileBytes.byteOffset + fileBytes.byteLength
826
+ )
827
+ )
828
+ };
829
+ });
830
+ return Promise.resolve(fileMap);
831
+ }
832
+ function readUtf8Flags(buf) {
833
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
834
+ let eocd = -1;
835
+ const maxBack = Math.min(buf.length, 65557);
836
+ for (let i = buf.length - 22; i >= buf.length - maxBack && i >= 0; i--) {
837
+ if (view.getUint32(i, true) === 101010256) {
838
+ eocd = i;
839
+ break;
840
+ }
841
+ }
842
+ if (eocd < 0) return [];
843
+ const entryCount = view.getUint16(eocd + 10, true);
844
+ let cdOffset = view.getUint32(eocd + 16, true);
845
+ const flags = [];
846
+ for (let i = 0; i < entryCount; i++) {
847
+ if (view.getUint32(cdOffset, true) !== 33639248) break;
848
+ const flag = view.getUint16(cdOffset + 8, true);
849
+ const nameLen = view.getUint16(cdOffset + 28, true);
850
+ const extraLen = view.getUint16(cdOffset + 30, true);
851
+ const commentLen = view.getUint16(cdOffset + 32, true);
852
+ flags.push((flag & 2048) !== 0);
853
+ cdOffset += 46 + nameLen + extraLen + commentLen;
854
+ }
855
+ return flags;
856
+ }
857
+
280
858
  // src/koe.ts
281
859
  var MAGIC = 1263486208;
282
860
  function packKoe(manifest, pcmParts) {
@@ -522,13 +1100,34 @@ var KoeEngine = class {
522
1100
  this.pending.set(name, load);
523
1101
  return load;
524
1102
  }
525
- /** Stop current playback, preload the phonemes for `notes`, then queue them. */
526
- async play(notes) {
1103
+ /**
1104
+ * Stop current playback, preload the phonemes for `notes`, then queue them.
1105
+ *
1106
+ * @returns the lead-in offset in samples — how far the first note's audio
1107
+ * starts ahead of its beat. 0 unless {@link PlayOptions.leadIn}.
1108
+ */
1109
+ async play(notes, options = {}) {
527
1110
  if (!this.node) throw new Error("KoeEngine: call load() before play()");
528
1111
  this.node.port.postMessage({ type: "stop" });
529
1112
  const names = [...new Set(notes.map((n) => n.phoneme))].filter(Boolean);
530
1113
  await Promise.all(names.map((n) => this.ensurePhoneme(n)));
531
- this.node.port.postMessage({ type: "play", notes });
1114
+ const leadIn = options.leadIn === true;
1115
+ this.node.port.postMessage({ type: "play", notes, leadIn });
1116
+ return leadIn ? this.leadInSamples(notes) : 0;
1117
+ }
1118
+ /**
1119
+ * Output samples the first note's lead-in occupies ahead of its beat —
1120
+ * mirrors what the worklet does with `leadIn`, so callers can compensate.
1121
+ */
1122
+ leadInSamples(notes) {
1123
+ const first = notes[0];
1124
+ const m = this.bank?.manifest;
1125
+ if (!first || !m || first.phoneme === "") return 0;
1126
+ const entry = Object.hasOwn(m.phonemes, first.phoneme) ? m.phonemes[first.phoneme] : void 0;
1127
+ if (!entry || entry.length <= 0) return 0;
1128
+ const recorded = entry.pitch || m.referencePitch || first.pitch || 1;
1129
+ const stepRate = first.pitch / recorded;
1130
+ return stepRate > 0 ? entry.pre / stepRate : 0;
532
1131
  }
533
1132
  /** Stop playback and clear the queue. */
534
1133
  stop() {
@@ -565,6 +1164,7 @@ var WORLDLINE_SAMPLE_RATE = 48e3;
565
1164
  var MIN_WORLDLINE_SAMPLES = 4096;
566
1165
  var SYNTH_REQ_SIZE = 120;
567
1166
  var WL_FRAME_MS = 10;
1167
+ var sampleCurve = (input, curve, totalMs) => typeof curve === "function" ? curve(input, totalMs) : curve;
568
1168
  var samplesToMs = (samples) => samples / WORLDLINE_SAMPLE_RATE * 1e3;
569
1169
  function leadInFromEntry(entry) {
570
1170
  return {
@@ -650,11 +1250,23 @@ var Worldline = class _Worldline {
650
1250
  * {@link MIN_WORLDLINE_SAMPLES} (too short for stable F0 analysis).
651
1251
  */
652
1252
  renderNote(params) {
653
- const { pcm, pitch, durationMs, preMs, consonantMs, tempo = 120 } = params;
1253
+ const {
1254
+ pcm,
1255
+ pitch,
1256
+ durationMs,
1257
+ preMs,
1258
+ consonantMs,
1259
+ tempo = 120,
1260
+ gender = 0.5,
1261
+ tension = 0.5,
1262
+ breathiness = 0.5,
1263
+ voicing = 1
1264
+ } = params;
654
1265
  if (!pcm || pcm.length < MIN_WORLDLINE_SAMPLES) return null;
655
1266
  const WL = this.wasm;
656
1267
  const FS = WORLDLINE_SAMPLE_RATE;
657
- const midiNote = Math.round(69 + 12 * Math.log2(pitch / 440));
1268
+ const basePitch = sampleCurve(preMs + durationMs / 2, pitch, preMs + durationMs);
1269
+ const midiNote = Math.round(69 + 12 * Math.log2(basePitch / 440));
658
1270
  const posMs = 0;
659
1271
  const reqLen = preMs + durationMs;
660
1272
  const cutMs = WL_FRAME_MS * 2;
@@ -700,11 +1312,19 @@ var Worldline = class _Worldline {
700
1312
  WL._free(reqPtr);
701
1313
  const totalMs = posMs + reqLen + WL_FRAME_MS * 2;
702
1314
  const nFrames = Math.ceil(totalMs / WL_FRAME_MS) + 4;
703
- const f0Arr = new Float64Array(nFrames).fill(pitch);
704
- const gArr = new Float64Array(nFrames).fill(0.5);
705
- const tArr = new Float64Array(nFrames).fill(0.5);
706
- const bArr = new Float64Array(nFrames).fill(0.5);
707
- const vArr = new Float64Array(nFrames).fill(1);
1315
+ const f0Arr = new Float64Array(nFrames);
1316
+ const gArr = new Float64Array(nFrames);
1317
+ const tArr = new Float64Array(nFrames);
1318
+ const bArr = new Float64Array(nFrames);
1319
+ const vArr = new Float64Array(nFrames);
1320
+ for (let i = 0; i < nFrames; i++) {
1321
+ const tMs = i * WL_FRAME_MS;
1322
+ f0Arr[i] = sampleCurve(tMs, pitch, totalMs);
1323
+ gArr[i] = sampleCurve(tMs, gender, totalMs);
1324
+ tArr[i] = sampleCurve(tMs, tension, totalMs);
1325
+ bArr[i] = sampleCurve(tMs, breathiness, totalMs);
1326
+ vArr[i] = sampleCurve(tMs, voicing, totalMs);
1327
+ }
708
1328
  const f0Ptr = WL._malloc(nFrames * 8);
709
1329
  const gPtr = WL._malloc(nFrames * 8);
710
1330
  const tPtr = WL._malloc(nFrames * 8);
@@ -760,22 +1380,27 @@ export {
760
1380
  WORLDLINE_SAMPLE_RATE,
761
1381
  Worldline,
762
1382
  detectF0,
1383
+ frqAverageF0InRange,
763
1384
  frqFileName,
764
1385
  leadInFromEntry,
765
1386
  normalizePcm,
766
1387
  noteNameToHz,
1388
+ otoRegion,
767
1389
  pack,
768
1390
  packKoe,
1391
+ parseFrq,
769
1392
  parseFrqAverageF0,
770
1393
  parseKoeHeader,
771
1394
  parseOto,
772
1395
  parseWav,
773
1396
  pcmBase,
774
1397
  pitchFromAliasSuffix,
1398
+ readWavPcm48k,
775
1399
  resample,
776
1400
  samplesToMs,
777
1401
  toInt16,
778
1402
  toMono,
779
- trimToOto
1403
+ trimToOto,
1404
+ unzipToFileMap
780
1405
  };
781
1406
  //# sourceMappingURL=index.js.map