@onjmin/dtm 0.1.83 → 0.1.84
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/index.d.mts +80 -4
- package/dist/index.d.ts +80 -4
- package/dist/index.js +696 -296
- package/dist/index.mjs +695 -296
- package/dist/voice-worker.js +175 -13
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -219,8 +219,8 @@ var Input = class _Input {
|
|
|
219
219
|
}
|
|
220
220
|
return str.length ? Number(str) : null;
|
|
221
221
|
}
|
|
222
|
-
slice(
|
|
223
|
-
return this.str.slice(this.idx, this.idx +
|
|
222
|
+
slice(i2) {
|
|
223
|
+
return this.str.slice(this.idx, this.idx + i2);
|
|
224
224
|
}
|
|
225
225
|
};
|
|
226
226
|
var Output = class {
|
|
@@ -256,8 +256,8 @@ var Matcher = class {
|
|
|
256
256
|
else this._set(key, value);
|
|
257
257
|
}
|
|
258
258
|
parse(input) {
|
|
259
|
-
for (const
|
|
260
|
-
const s = input.slice(
|
|
259
|
+
for (const i2 of this.lengths) {
|
|
260
|
+
const s = input.slice(i2);
|
|
261
261
|
if (this.map.has(s)) {
|
|
262
262
|
input.idx += s.length;
|
|
263
263
|
return this.map.get(s);
|
|
@@ -311,7 +311,7 @@ var parseFormula = (input, output = new Output(), nest = 0) => {
|
|
|
311
311
|
if (o.isChord) {
|
|
312
312
|
output.value = [...o.value].concat(v);
|
|
313
313
|
} else {
|
|
314
|
-
const a = v.sort((
|
|
314
|
+
const a = v.sort((x2, y) => x2 - y);
|
|
315
315
|
const pitch = (o.pitch + 3) % 12 - 3;
|
|
316
316
|
if (a[0] < pitch) {
|
|
317
317
|
while (a[0] < pitch) a.push(a.shift() + 12);
|
|
@@ -348,16 +348,16 @@ halfMatcher.set("+", 1);
|
|
|
348
348
|
halfMatcher.set("-", -1);
|
|
349
349
|
var parseHalf = (input, isPitch = false) => (isPitch ? halfMatcherStrict : halfMatcher).parse(input);
|
|
350
350
|
var idx2pitch = [0, 2, 4, 5, 7, 9, 11];
|
|
351
|
-
for (const
|
|
351
|
+
for (const i2 of [...idx2pitch.keys()]) idx2pitch.push(idx2pitch[i2] + 12);
|
|
352
352
|
var deg2pitch = (deg) => idx2pitch[deg - 1];
|
|
353
353
|
var pitchMatcher = new Matcher();
|
|
354
|
-
for (const [
|
|
355
|
-
pitchMatcher.set(v, idx2pitch[
|
|
354
|
+
for (const [i2, v] of [..."CDEFGAB"].entries())
|
|
355
|
+
pitchMatcher.set(v, idx2pitch[i2]);
|
|
356
356
|
var parsePitch = (input, output) => {
|
|
357
357
|
const pitch = pitchMatcher.parse(input);
|
|
358
358
|
if (pitch === null) err(input, "Not found pitch");
|
|
359
359
|
output.pitch = pitch;
|
|
360
|
-
for (let
|
|
360
|
+
for (let i2 = 0; i2 < 2; i2++) {
|
|
361
361
|
const half = parseHalf(input, true);
|
|
362
362
|
if (half === null) break;
|
|
363
363
|
output.pitch += half;
|
|
@@ -563,11 +563,11 @@ var pearson = (a, b) => {
|
|
|
563
563
|
let num = 0;
|
|
564
564
|
let da = 0;
|
|
565
565
|
let db = 0;
|
|
566
|
-
for (let
|
|
567
|
-
const
|
|
568
|
-
const y = b[
|
|
569
|
-
num +=
|
|
570
|
-
da +=
|
|
566
|
+
for (let i2 = 0; i2 < a.length; i2++) {
|
|
567
|
+
const x2 = a[i2] - ma;
|
|
568
|
+
const y = b[i2] - mb;
|
|
569
|
+
num += x2 * y;
|
|
570
|
+
da += x2 * x2;
|
|
571
571
|
db += y * y;
|
|
572
572
|
}
|
|
573
573
|
const den = Math.sqrt(da * db);
|
|
@@ -643,19 +643,19 @@ var coalesce = (segments) => {
|
|
|
643
643
|
var mergeShortSegments = (segments, min) => {
|
|
644
644
|
if (min <= 0) return segments;
|
|
645
645
|
const result = segments.map((s) => ({ ...s }));
|
|
646
|
-
let
|
|
647
|
-
while (
|
|
648
|
-
if (result[
|
|
649
|
-
|
|
646
|
+
let i2 = 0;
|
|
647
|
+
while (i2 < result.length && result.length > 1) {
|
|
648
|
+
if (result[i2].duration >= min) {
|
|
649
|
+
i2++;
|
|
650
650
|
continue;
|
|
651
651
|
}
|
|
652
|
-
if (
|
|
653
|
-
result[
|
|
654
|
-
result.splice(
|
|
652
|
+
if (i2 > 0) {
|
|
653
|
+
result[i2 - 1].duration += result[i2].duration;
|
|
654
|
+
result.splice(i2, 1);
|
|
655
655
|
} else {
|
|
656
|
-
result[
|
|
657
|
-
result[
|
|
658
|
-
result.splice(
|
|
656
|
+
result[i2 + 1].when = result[i2].when;
|
|
657
|
+
result[i2 + 1].duration += result[i2].duration;
|
|
658
|
+
result.splice(i2, 1);
|
|
659
659
|
}
|
|
660
660
|
}
|
|
661
661
|
return coalesce(result);
|
|
@@ -874,19 +874,19 @@ var viterbi = (emissions, changePenalty) => {
|
|
|
874
874
|
const curr = new Array(N).fill(0);
|
|
875
875
|
const em = emissions[t];
|
|
876
876
|
const switchVal = bestPrevVal - changePenalty;
|
|
877
|
-
for (let
|
|
878
|
-
if (prev[
|
|
879
|
-
curr[
|
|
880
|
-
back[t][
|
|
877
|
+
for (let i2 = 0; i2 < N; i2++) {
|
|
878
|
+
if (prev[i2] >= switchVal) {
|
|
879
|
+
curr[i2] = em[i2] + prev[i2];
|
|
880
|
+
back[t][i2] = i2;
|
|
881
881
|
} else {
|
|
882
|
-
curr[
|
|
883
|
-
back[t][
|
|
882
|
+
curr[i2] = em[i2] + switchVal;
|
|
883
|
+
back[t][i2] = bestPrevIdx;
|
|
884
884
|
}
|
|
885
885
|
}
|
|
886
886
|
prev = curr;
|
|
887
887
|
}
|
|
888
888
|
let bestIdx = 0;
|
|
889
|
-
for (let
|
|
889
|
+
for (let i2 = 1; i2 < N; i2++) if (prev[i2] > prev[bestIdx]) bestIdx = i2;
|
|
890
890
|
const path = new Array(T).fill(0);
|
|
891
891
|
path[T - 1] = bestIdx;
|
|
892
892
|
for (let t = T - 1; t > 0; t--) path[t - 1] = back[t][path[t]];
|
|
@@ -983,20 +983,20 @@ var parseChords = (str, bpm = 120) => {
|
|
|
983
983
|
if (!str2.length) continue;
|
|
984
984
|
const when = idx++ * secBar;
|
|
985
985
|
const a = [];
|
|
986
|
-
for (let
|
|
987
|
-
const char = str2[
|
|
988
|
-
const prev = str2[
|
|
989
|
-
const prev2 = str2.slice(
|
|
986
|
+
for (let i2 = 0; i2 < str2.length; i2++) {
|
|
987
|
+
const char = str2[i2];
|
|
988
|
+
const prev = str2[i2 - 1];
|
|
989
|
+
const prev2 = str2.slice(i2 - 2, i2);
|
|
990
990
|
if (!frontChars.has(char)) continue;
|
|
991
991
|
if (prev === "/" || prev2 === "on") continue;
|
|
992
992
|
if (prev2 === "N." && char === "C") continue;
|
|
993
|
-
a.push(
|
|
993
|
+
a.push(i2);
|
|
994
994
|
}
|
|
995
995
|
if (!a.length) continue;
|
|
996
996
|
const divide = 2 ** Math.ceil(Math.log2(a.length));
|
|
997
997
|
const unitTime = secBar / divide;
|
|
998
|
-
for (const [
|
|
999
|
-
const s = str2.slice(v,
|
|
998
|
+
for (const [i2, v] of a.entries()) {
|
|
999
|
+
const s = str2.slice(v, i2 === a.length - 1 ? str2.length : a[i2 + 1]).replace(/\s+/g, "");
|
|
1000
1000
|
const c = s[0];
|
|
1001
1001
|
if (c === "_" || c === "N") {
|
|
1002
1002
|
last = null;
|
|
@@ -1006,7 +1006,7 @@ var parseChords = (str, bpm = 120) => {
|
|
|
1006
1006
|
if (last) last.duration += unitTime;
|
|
1007
1007
|
continue;
|
|
1008
1008
|
}
|
|
1009
|
-
const _when = when +
|
|
1009
|
+
const _when = when + i2 * unitTime;
|
|
1010
1010
|
if (c === "%") {
|
|
1011
1011
|
if (last === null) continue;
|
|
1012
1012
|
const base = last;
|
|
@@ -1171,19 +1171,19 @@ var resolveDrumPattern = (name, dict, currentBar) => {
|
|
|
1171
1171
|
if (Array.isArray(patternObj) && patternObj.length > 0 && "ranges" in patternObj[0]) {
|
|
1172
1172
|
const songDef = patternObj;
|
|
1173
1173
|
const instructions = songDef.filter(
|
|
1174
|
-
(
|
|
1174
|
+
(i2) => i2.ranges.some(([s, e]) => currentBar >= s && currentBar <= e)
|
|
1175
1175
|
);
|
|
1176
1176
|
if (instructions.length > 0) {
|
|
1177
|
-
return instructions.flatMap((
|
|
1178
|
-
const maxStep = Math.max(...
|
|
1179
|
-
const loopLengthBars =
|
|
1180
|
-
const range =
|
|
1177
|
+
return instructions.flatMap((i2) => {
|
|
1178
|
+
const maxStep = Math.max(...i2.pattern.map((p) => p.step), 0);
|
|
1179
|
+
const loopLengthBars = i2.patternBars ?? Math.max(1, Math.ceil((maxStep + 1) / 192));
|
|
1180
|
+
const range = i2.ranges.find(
|
|
1181
1181
|
([s, e]) => currentBar >= s && currentBar <= e
|
|
1182
1182
|
);
|
|
1183
1183
|
const startBar = range ? range[0] : 1;
|
|
1184
1184
|
const barInLoop = (currentBar - startBar) % loopLengthBars;
|
|
1185
1185
|
const stepOffset = barInLoop * 192;
|
|
1186
|
-
return
|
|
1186
|
+
return i2.pattern.filter((p) => p.step >= stepOffset && p.step < stepOffset + 192).map((p) => ({ ...p, step: p.step - stepOffset }));
|
|
1187
1187
|
});
|
|
1188
1188
|
}
|
|
1189
1189
|
}
|
|
@@ -1326,8 +1326,8 @@ var getDrumPatternKeys = (name, dict) => {
|
|
|
1326
1326
|
const keys = /* @__PURE__ */ new Set();
|
|
1327
1327
|
if (Array.isArray(patternObj) && patternObj.length > 0 && "ranges" in patternObj[0]) {
|
|
1328
1328
|
const songDef = patternObj;
|
|
1329
|
-
for (const
|
|
1330
|
-
for (const p of
|
|
1329
|
+
for (const i2 of songDef) {
|
|
1330
|
+
for (const p of i2.pattern) keys.add(p.pitch);
|
|
1331
1331
|
}
|
|
1332
1332
|
} else if (Array.isArray(patternObj)) {
|
|
1333
1333
|
for (const p of patternObj) keys.add(p.pitch);
|
|
@@ -1384,21 +1384,21 @@ var buildChordPlacements = (options) => {
|
|
|
1384
1384
|
}
|
|
1385
1385
|
} else if (patternType === "arpeggio") {
|
|
1386
1386
|
const arpInterval = Math.floor(noteLength / notes.length);
|
|
1387
|
-
notes.forEach((noteOffset,
|
|
1387
|
+
notes.forEach((noteOffset, i2) => {
|
|
1388
1388
|
placements.push({
|
|
1389
|
-
startStep: chord.whenStep +
|
|
1389
|
+
startStep: chord.whenStep + i2 * arpInterval,
|
|
1390
1390
|
pitch: C3 + noteOffset + offset,
|
|
1391
|
-
durationSteps: noteLength -
|
|
1391
|
+
durationSteps: noteLength - i2 * arpInterval,
|
|
1392
1392
|
velocity: 100
|
|
1393
1393
|
});
|
|
1394
1394
|
});
|
|
1395
1395
|
} else if (patternType === "arpeggio-fast") {
|
|
1396
1396
|
const arpInterval = 6;
|
|
1397
|
-
notes.forEach((noteOffset,
|
|
1397
|
+
notes.forEach((noteOffset, i2) => {
|
|
1398
1398
|
placements.push({
|
|
1399
|
-
startStep: chord.whenStep +
|
|
1399
|
+
startStep: chord.whenStep + i2 * arpInterval,
|
|
1400
1400
|
pitch: C3 + noteOffset + offset,
|
|
1401
|
-
durationSteps: Math.max(12, noteLength -
|
|
1401
|
+
durationSteps: Math.max(12, noteLength - i2 * arpInterval),
|
|
1402
1402
|
velocity: 100
|
|
1403
1403
|
});
|
|
1404
1404
|
});
|
|
@@ -1438,8 +1438,8 @@ var buildChordPlacements = (options) => {
|
|
|
1438
1438
|
}
|
|
1439
1439
|
}
|
|
1440
1440
|
} else if (patternType === "alternating") {
|
|
1441
|
-
notes.forEach((noteOffset,
|
|
1442
|
-
const stepOffset =
|
|
1441
|
+
notes.forEach((noteOffset, i2) => {
|
|
1442
|
+
const stepOffset = i2 * Math.floor(stepsPerBar / 4);
|
|
1443
1443
|
placements.push({
|
|
1444
1444
|
startStep: chord.whenStep + stepOffset,
|
|
1445
1445
|
pitch: C3 + noteOffset + offset,
|
|
@@ -1461,8 +1461,8 @@ var buildChordPlacements = (options) => {
|
|
|
1461
1461
|
}
|
|
1462
1462
|
if (notes.length === 0) return;
|
|
1463
1463
|
const startStep = barIndex * chordLength;
|
|
1464
|
-
notes.forEach((noteOffset,
|
|
1465
|
-
const stepOffset =
|
|
1464
|
+
notes.forEach((noteOffset, i2) => {
|
|
1465
|
+
const stepOffset = i2 * 3;
|
|
1466
1466
|
placements.push({
|
|
1467
1467
|
startStep: startStep + stepOffset,
|
|
1468
1468
|
pitch: C3 + noteOffset + offset,
|
|
@@ -1475,7 +1475,136 @@ var buildChordPlacements = (options) => {
|
|
|
1475
1475
|
return placements;
|
|
1476
1476
|
};
|
|
1477
1477
|
|
|
1478
|
-
// node_modules/.pnpm/@onjmin+koe@1.0.
|
|
1478
|
+
// node_modules/.pnpm/@onjmin+koe@1.0.5/node_modules/@onjmin/koe/dist/index.js
|
|
1479
|
+
var u8 = Uint8Array;
|
|
1480
|
+
var u16 = Uint16Array;
|
|
1481
|
+
var i32 = Int32Array;
|
|
1482
|
+
var fleb = new u8([
|
|
1483
|
+
0,
|
|
1484
|
+
0,
|
|
1485
|
+
0,
|
|
1486
|
+
0,
|
|
1487
|
+
0,
|
|
1488
|
+
0,
|
|
1489
|
+
0,
|
|
1490
|
+
0,
|
|
1491
|
+
1,
|
|
1492
|
+
1,
|
|
1493
|
+
1,
|
|
1494
|
+
1,
|
|
1495
|
+
2,
|
|
1496
|
+
2,
|
|
1497
|
+
2,
|
|
1498
|
+
2,
|
|
1499
|
+
3,
|
|
1500
|
+
3,
|
|
1501
|
+
3,
|
|
1502
|
+
3,
|
|
1503
|
+
4,
|
|
1504
|
+
4,
|
|
1505
|
+
4,
|
|
1506
|
+
4,
|
|
1507
|
+
5,
|
|
1508
|
+
5,
|
|
1509
|
+
5,
|
|
1510
|
+
5,
|
|
1511
|
+
0,
|
|
1512
|
+
/* unused */
|
|
1513
|
+
0,
|
|
1514
|
+
0,
|
|
1515
|
+
/* impossible */
|
|
1516
|
+
0
|
|
1517
|
+
]);
|
|
1518
|
+
var fdeb = new u8([
|
|
1519
|
+
0,
|
|
1520
|
+
0,
|
|
1521
|
+
0,
|
|
1522
|
+
0,
|
|
1523
|
+
1,
|
|
1524
|
+
1,
|
|
1525
|
+
2,
|
|
1526
|
+
2,
|
|
1527
|
+
3,
|
|
1528
|
+
3,
|
|
1529
|
+
4,
|
|
1530
|
+
4,
|
|
1531
|
+
5,
|
|
1532
|
+
5,
|
|
1533
|
+
6,
|
|
1534
|
+
6,
|
|
1535
|
+
7,
|
|
1536
|
+
7,
|
|
1537
|
+
8,
|
|
1538
|
+
8,
|
|
1539
|
+
9,
|
|
1540
|
+
9,
|
|
1541
|
+
10,
|
|
1542
|
+
10,
|
|
1543
|
+
11,
|
|
1544
|
+
11,
|
|
1545
|
+
12,
|
|
1546
|
+
12,
|
|
1547
|
+
13,
|
|
1548
|
+
13,
|
|
1549
|
+
/* unused */
|
|
1550
|
+
0,
|
|
1551
|
+
0
|
|
1552
|
+
]);
|
|
1553
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
1554
|
+
var freb = function(eb, start) {
|
|
1555
|
+
var b = new u16(31);
|
|
1556
|
+
for (var i2 = 0; i2 < 31; ++i2) {
|
|
1557
|
+
b[i2] = start += 1 << eb[i2 - 1];
|
|
1558
|
+
}
|
|
1559
|
+
var r = new i32(b[30]);
|
|
1560
|
+
for (var i2 = 1; i2 < 30; ++i2) {
|
|
1561
|
+
for (var j = b[i2]; j < b[i2 + 1]; ++j) {
|
|
1562
|
+
r[j] = j - b[i2] << 5 | i2;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
return { b, r };
|
|
1566
|
+
};
|
|
1567
|
+
var _a = freb(fleb, 2);
|
|
1568
|
+
var fl = _a.b;
|
|
1569
|
+
var revfl = _a.r;
|
|
1570
|
+
fl[28] = 258, revfl[258] = 28;
|
|
1571
|
+
var _b = freb(fdeb, 0);
|
|
1572
|
+
var fd = _b.b;
|
|
1573
|
+
var revfd = _b.r;
|
|
1574
|
+
var rev = new u16(32768);
|
|
1575
|
+
for (i = 0; i < 32768; ++i) {
|
|
1576
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
1577
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
1578
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
1579
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
1580
|
+
}
|
|
1581
|
+
var x;
|
|
1582
|
+
var i;
|
|
1583
|
+
var flt = new u8(288);
|
|
1584
|
+
for (i = 0; i < 144; ++i)
|
|
1585
|
+
flt[i] = 8;
|
|
1586
|
+
var i;
|
|
1587
|
+
for (i = 144; i < 256; ++i)
|
|
1588
|
+
flt[i] = 9;
|
|
1589
|
+
var i;
|
|
1590
|
+
for (i = 256; i < 280; ++i)
|
|
1591
|
+
flt[i] = 7;
|
|
1592
|
+
var i;
|
|
1593
|
+
for (i = 280; i < 288; ++i)
|
|
1594
|
+
flt[i] = 8;
|
|
1595
|
+
var i;
|
|
1596
|
+
var fdt = new u8(32);
|
|
1597
|
+
for (i = 0; i < 32; ++i)
|
|
1598
|
+
fdt[i] = 5;
|
|
1599
|
+
var i;
|
|
1600
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
1601
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
1602
|
+
var tds = 0;
|
|
1603
|
+
try {
|
|
1604
|
+
td.decode(et, { stream: true });
|
|
1605
|
+
tds = 1;
|
|
1606
|
+
} catch (e) {
|
|
1607
|
+
}
|
|
1479
1608
|
var MAGIC = 1263486208;
|
|
1480
1609
|
function parseKoeHeader(headerBytes) {
|
|
1481
1610
|
const view = new DataView(headerBytes);
|
|
@@ -1641,7 +1770,7 @@ var VoiceBank = class _VoiceBank {
|
|
|
1641
1770
|
if (!buf) return null;
|
|
1642
1771
|
const int16 = new Int16Array(buf, 0, Math.floor(buf.byteLength / 2));
|
|
1643
1772
|
const f64 = new Float64Array(int16.length);
|
|
1644
|
-
for (let
|
|
1773
|
+
for (let i2 = 0; i2 < int16.length; i2++) f64[i2] = int16[i2] / 32768;
|
|
1645
1774
|
return f64;
|
|
1646
1775
|
}
|
|
1647
1776
|
};
|
|
@@ -1649,6 +1778,7 @@ var WORLDLINE_SAMPLE_RATE = 48e3;
|
|
|
1649
1778
|
var MIN_WORLDLINE_SAMPLES = 4096;
|
|
1650
1779
|
var SYNTH_REQ_SIZE = 120;
|
|
1651
1780
|
var WL_FRAME_MS = 10;
|
|
1781
|
+
var sampleCurve = (input, curve, totalMs) => typeof curve === "function" ? curve(input, totalMs) : curve;
|
|
1652
1782
|
var samplesToMs = (samples) => samples / WORLDLINE_SAMPLE_RATE * 1e3;
|
|
1653
1783
|
function leadInFromEntry(entry) {
|
|
1654
1784
|
return {
|
|
@@ -1734,11 +1864,23 @@ var Worldline = class _Worldline {
|
|
|
1734
1864
|
* {@link MIN_WORLDLINE_SAMPLES} (too short for stable F0 analysis).
|
|
1735
1865
|
*/
|
|
1736
1866
|
renderNote(params) {
|
|
1737
|
-
const {
|
|
1867
|
+
const {
|
|
1868
|
+
pcm,
|
|
1869
|
+
pitch,
|
|
1870
|
+
durationMs,
|
|
1871
|
+
preMs,
|
|
1872
|
+
consonantMs,
|
|
1873
|
+
tempo = 120,
|
|
1874
|
+
gender = 0.5,
|
|
1875
|
+
tension = 0.5,
|
|
1876
|
+
breathiness = 0.5,
|
|
1877
|
+
voicing = 1
|
|
1878
|
+
} = params;
|
|
1738
1879
|
if (!pcm || pcm.length < MIN_WORLDLINE_SAMPLES) return null;
|
|
1739
1880
|
const WL = this.wasm;
|
|
1740
1881
|
const FS = WORLDLINE_SAMPLE_RATE;
|
|
1741
|
-
const
|
|
1882
|
+
const basePitch = sampleCurve(preMs + durationMs / 2, pitch, preMs + durationMs);
|
|
1883
|
+
const midiNote = Math.round(69 + 12 * Math.log2(basePitch / 440));
|
|
1742
1884
|
const posMs = 0;
|
|
1743
1885
|
const reqLen = preMs + durationMs;
|
|
1744
1886
|
const cutMs = WL_FRAME_MS * 2;
|
|
@@ -1784,11 +1926,19 @@ var Worldline = class _Worldline {
|
|
|
1784
1926
|
WL._free(reqPtr);
|
|
1785
1927
|
const totalMs = posMs + reqLen + WL_FRAME_MS * 2;
|
|
1786
1928
|
const nFrames = Math.ceil(totalMs / WL_FRAME_MS) + 4;
|
|
1787
|
-
const f0Arr = new Float64Array(nFrames)
|
|
1788
|
-
const gArr = new Float64Array(nFrames)
|
|
1789
|
-
const tArr = new Float64Array(nFrames)
|
|
1790
|
-
const bArr = new Float64Array(nFrames)
|
|
1791
|
-
const vArr = new Float64Array(nFrames)
|
|
1929
|
+
const f0Arr = new Float64Array(nFrames);
|
|
1930
|
+
const gArr = new Float64Array(nFrames);
|
|
1931
|
+
const tArr = new Float64Array(nFrames);
|
|
1932
|
+
const bArr = new Float64Array(nFrames);
|
|
1933
|
+
const vArr = new Float64Array(nFrames);
|
|
1934
|
+
for (let i2 = 0; i2 < nFrames; i2++) {
|
|
1935
|
+
const tMs = i2 * WL_FRAME_MS;
|
|
1936
|
+
f0Arr[i2] = sampleCurve(tMs, pitch, totalMs);
|
|
1937
|
+
gArr[i2] = sampleCurve(tMs, gender, totalMs);
|
|
1938
|
+
tArr[i2] = sampleCurve(tMs, tension, totalMs);
|
|
1939
|
+
bArr[i2] = sampleCurve(tMs, breathiness, totalMs);
|
|
1940
|
+
vArr[i2] = sampleCurve(tMs, voicing, totalMs);
|
|
1941
|
+
}
|
|
1792
1942
|
const f0Ptr = WL._malloc(nFrames * 8);
|
|
1793
1943
|
const gPtr = WL._malloc(nFrames * 8);
|
|
1794
1944
|
const tPtr = WL._malloc(nFrames * 8);
|
|
@@ -1848,6 +1998,19 @@ var DEFAULT_PLAYBACK_VELOCITY = 127;
|
|
|
1848
1998
|
var DEFAULT_STEPS_PER_BAR = 192;
|
|
1849
1999
|
var MML_END_MARKER = "#end;";
|
|
1850
2000
|
|
|
2001
|
+
// src/vibrato.ts
|
|
2002
|
+
var VIBRATO_MIN_SEC = 0.35;
|
|
2003
|
+
var VIBRATO_RATE_HZ = 5.5;
|
|
2004
|
+
var VIBRATO_DEPTH_CENTS = 35;
|
|
2005
|
+
var VIBRATO_FADE_MS = 150;
|
|
2006
|
+
var vibratoPitchCurve = (baseHz, preMs) => (tMs) => {
|
|
2007
|
+
const sinceOnset = tMs - preMs;
|
|
2008
|
+
if (sinceOnset <= 0) return baseHz;
|
|
2009
|
+
const depth = VIBRATO_DEPTH_CENTS * Math.min(1, sinceOnset / VIBRATO_FADE_MS);
|
|
2010
|
+
const cents = depth * Math.sin(2 * Math.PI * VIBRATO_RATE_HZ * sinceOnset / 1e3);
|
|
2011
|
+
return baseHz * 2 ** (cents / 1200);
|
|
2012
|
+
};
|
|
2013
|
+
|
|
1851
2014
|
// src/lyrics.ts
|
|
1852
2015
|
var kanaTable = {
|
|
1853
2016
|
\u3042: ["", "a"],
|
|
@@ -2012,8 +2175,8 @@ var vocalVolumeToGain = (v) => {
|
|
|
2012
2175
|
var parseLyrics = (mml) => {
|
|
2013
2176
|
const tracks = /* @__PURE__ */ new Map();
|
|
2014
2177
|
const segments = splitSegments(mml);
|
|
2015
|
-
for (let
|
|
2016
|
-
const m = segments[
|
|
2178
|
+
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
2179
|
+
const m = segments[i2].match(LYRIC_LINE);
|
|
2017
2180
|
if (!m) continue;
|
|
2018
2181
|
const trackId = Number.parseInt(m[1], 10);
|
|
2019
2182
|
let rest = m[2].trim();
|
|
@@ -2021,8 +2184,10 @@ var parseLyrics = (mml) => {
|
|
|
2021
2184
|
let gate = 100;
|
|
2022
2185
|
let pan = 64;
|
|
2023
2186
|
let octave = 0;
|
|
2187
|
+
let vibrato = false;
|
|
2188
|
+
let reverb = 0;
|
|
2024
2189
|
const modelMatch = rest.match(
|
|
2025
|
-
/^([a-z_][a-z0-9_]*?)(?=(?:[
|
|
2190
|
+
/^([a-z_][a-z0-9_]*?)(?=(?:[vqpobr]-?\d)|[^a-z0-9_]|$)(?::(\d+))?/i
|
|
2026
2191
|
);
|
|
2027
2192
|
let model = "";
|
|
2028
2193
|
const metaTokens = [];
|
|
@@ -2063,11 +2228,25 @@ var parseLyrics = (mml) => {
|
|
|
2063
2228
|
rest = rest.substring(oMatch[0].length).trim();
|
|
2064
2229
|
continue;
|
|
2065
2230
|
}
|
|
2231
|
+
const bMatch = rest.match(/^b([01])/i);
|
|
2232
|
+
if (bMatch) {
|
|
2233
|
+
vibrato = bMatch[1] === "1";
|
|
2234
|
+
metaTokens.push(bMatch[0]);
|
|
2235
|
+
rest = rest.substring(bMatch[0].length).trim();
|
|
2236
|
+
continue;
|
|
2237
|
+
}
|
|
2238
|
+
const rMatch = rest.match(/^r(\d+)/i);
|
|
2239
|
+
if (rMatch) {
|
|
2240
|
+
reverb = clamp(Number.parseInt(rMatch[1], 10), 0, 100);
|
|
2241
|
+
metaTokens.push(rMatch[0]);
|
|
2242
|
+
rest = rest.substring(rMatch[0].length).trim();
|
|
2243
|
+
continue;
|
|
2244
|
+
}
|
|
2066
2245
|
break;
|
|
2067
2246
|
}
|
|
2068
2247
|
const lyricLines = [rest];
|
|
2069
|
-
while (
|
|
2070
|
-
lyricLines.push(segments[++
|
|
2248
|
+
while (i2 + 1 < segments.length && isLyricContinuation(segments[i2 + 1])) {
|
|
2249
|
+
lyricLines.push(segments[++i2]);
|
|
2071
2250
|
}
|
|
2072
2251
|
const { syllables, lineBreaks } = normalizeLyricLines(lyricLines);
|
|
2073
2252
|
tracks.set(trackId, {
|
|
@@ -2077,6 +2256,8 @@ var parseLyrics = (mml) => {
|
|
|
2077
2256
|
gate,
|
|
2078
2257
|
pan,
|
|
2079
2258
|
octave,
|
|
2259
|
+
vibrato,
|
|
2260
|
+
reverb,
|
|
2080
2261
|
syllables,
|
|
2081
2262
|
metaText: metaTokens.join(" "),
|
|
2082
2263
|
...lineBreaks.length > 0 ? { lineBreaks } : {}
|
|
@@ -2087,13 +2268,13 @@ var parseLyrics = (mml) => {
|
|
|
2087
2268
|
var stripLyrics = (mml) => {
|
|
2088
2269
|
const segments = splitSegments(mml);
|
|
2089
2270
|
const kept = [];
|
|
2090
|
-
for (let
|
|
2091
|
-
if (LYRIC_LINE.test(segments[
|
|
2092
|
-
while (
|
|
2093
|
-
|
|
2271
|
+
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
2272
|
+
if (LYRIC_LINE.test(segments[i2])) {
|
|
2273
|
+
while (i2 + 1 < segments.length && isLyricContinuation(segments[i2 + 1]))
|
|
2274
|
+
i2++;
|
|
2094
2275
|
continue;
|
|
2095
2276
|
}
|
|
2096
|
-
kept.push(segments[
|
|
2277
|
+
kept.push(segments[i2]);
|
|
2097
2278
|
}
|
|
2098
2279
|
return kept.join("\n");
|
|
2099
2280
|
};
|
|
@@ -2162,7 +2343,7 @@ var FORMANTS = {
|
|
|
2162
2343
|
N: [250, 1e3]
|
|
2163
2344
|
};
|
|
2164
2345
|
var midiToFreq = (m) => 440 * 2 ** ((m - 69) / 12);
|
|
2165
|
-
var createKlattVoice = (ctx, destination) => {
|
|
2346
|
+
var createKlattVoice = (ctx, destination, reverbBus) => {
|
|
2166
2347
|
const active = /* @__PURE__ */ new Set();
|
|
2167
2348
|
const voice = (syllable, e) => {
|
|
2168
2349
|
const t0 = ctx.currentTime + e.when;
|
|
@@ -2180,6 +2361,12 @@ var createKlattVoice = (ctx, destination) => {
|
|
|
2180
2361
|
panner.connect(destination);
|
|
2181
2362
|
out = panner;
|
|
2182
2363
|
}
|
|
2364
|
+
let sendGain = null;
|
|
2365
|
+
if (reverbBus && e.reverbSend && e.reverbSend > 0 && panner) {
|
|
2366
|
+
sendGain = ctx.createGain();
|
|
2367
|
+
sendGain.gain.value = Math.max(0, Math.min(1, e.reverbSend));
|
|
2368
|
+
panner.connect(sendGain).connect(reverbBus);
|
|
2369
|
+
}
|
|
2183
2370
|
const osc = ctx.createOscillator();
|
|
2184
2371
|
osc.type = "sawtooth";
|
|
2185
2372
|
osc.frequency.value = midiToFreq(e.pitch);
|
|
@@ -2208,7 +2395,7 @@ var createKlattVoice = (ctx, destination) => {
|
|
|
2208
2395
|
const length = Math.max(1, Math.floor(ctx.sampleRate * dur));
|
|
2209
2396
|
const buffer = ctx.createBuffer(1, length, ctx.sampleRate);
|
|
2210
2397
|
const data = buffer.getChannelData(0);
|
|
2211
|
-
for (let
|
|
2398
|
+
for (let i2 = 0; i2 < length; i2++) data[i2] = Math.random() * 2 - 1;
|
|
2212
2399
|
const src = ctx.createBufferSource();
|
|
2213
2400
|
src.buffer = buffer;
|
|
2214
2401
|
const hp = ctx.createBiquadFilter();
|
|
@@ -2235,6 +2422,7 @@ var createKlattVoice = (ctx, destination) => {
|
|
|
2235
2422
|
active.delete(osc);
|
|
2236
2423
|
osc.disconnect();
|
|
2237
2424
|
panner?.disconnect();
|
|
2425
|
+
sendGain?.disconnect();
|
|
2238
2426
|
};
|
|
2239
2427
|
};
|
|
2240
2428
|
voice.stopAll = () => {
|
|
@@ -2253,6 +2441,7 @@ var KOE_BASE_URL = "https://pub-12482a6b5cbc4c9e906b2e1904cabae5.r2.dev";
|
|
|
2253
2441
|
var KOE_VOICEBANKS = {
|
|
2254
2442
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093.koe",
|
|
2255
2443
|
rino: "\u6625\u97F3\u30EA\u30CEver0.3.koe",
|
|
2444
|
+
rino121: "\u6625\u97F3\u30EA\u30CEver.1.1(226).koe",
|
|
2256
2445
|
roze: "\u675F\u97F3\u30ED\u30BCver0.\uFF151(\u591A\u97F3\u968E).koe",
|
|
2257
2446
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642\u9023\u7D9A\u97F3Ver.1.03.koe",
|
|
2258
2447
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640\u6B4C\u9023\u7D9A\u97F3\u666E1.00.koe",
|
|
@@ -2261,11 +2450,13 @@ var KOE_VOICEBANKS = {
|
|
|
2261
2450
|
rei: "\u8DB3\u7ACB\u30EC\u30A4ver3.5.0.koe",
|
|
2262
2451
|
mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
|
|
2263
2452
|
motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
|
|
2264
|
-
nynroid: "NYNRoidver1.4.koe"
|
|
2453
|
+
nynroid: "NYNRoidver1.4.koe",
|
|
2454
|
+
uc: "\u84C4\u97F3\u30AD\u30EA\u30B3\u97F3\u6E90.koe"
|
|
2265
2455
|
};
|
|
2266
2456
|
var KOE_VOICEBANK_LABELS = {
|
|
2267
2457
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
|
|
2268
2458
|
rino: "\u6625\u97F3\u30EA\u30CE",
|
|
2459
|
+
rino121: "\u6625\u97F3\u30EA\u30CEv1.2.1",
|
|
2269
2460
|
roze: "\u675F\u97F3\u30ED\u30BC",
|
|
2270
2461
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642",
|
|
2271
2462
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640",
|
|
@@ -2274,12 +2465,14 @@ var KOE_VOICEBANK_LABELS = {
|
|
|
2274
2465
|
rei: "\u8DB3\u7ACB\u30EC\u30A4",
|
|
2275
2466
|
mgroid: "MGRoid",
|
|
2276
2467
|
motroid: "MOTRoid",
|
|
2277
|
-
nynroid: "NYNRoid"
|
|
2468
|
+
nynroid: "NYNRoid",
|
|
2469
|
+
uc: "\u84C4\u97F3\u30AD\u30EA\u30B3"
|
|
2278
2470
|
};
|
|
2279
2471
|
var VOICE_IMAGE_KEY = {
|
|
2280
2472
|
klatt: "puyuyu",
|
|
2281
2473
|
tsukuyomi: "tsukuyomi",
|
|
2282
2474
|
rino: "rino",
|
|
2475
|
+
rino121: "rino",
|
|
2283
2476
|
roze: "roze",
|
|
2284
2477
|
ruko_male: "ruko",
|
|
2285
2478
|
ruko_female: "ruko",
|
|
@@ -2288,11 +2481,13 @@ var VOICE_IMAGE_KEY = {
|
|
|
2288
2481
|
rei: "rei",
|
|
2289
2482
|
mgroid: "MGRoid",
|
|
2290
2483
|
motroid: "MOTRoid",
|
|
2291
|
-
nynroid: "NYNRoid"
|
|
2484
|
+
nynroid: "NYNRoid",
|
|
2485
|
+
uc: "uc"
|
|
2292
2486
|
};
|
|
2293
2487
|
var KOE_VOICEBANK_TERMS = {
|
|
2294
2488
|
tsukuyomi: "https://tyc.rei-yumesaki.net/material/utau/terms/",
|
|
2295
2489
|
rino: "https://hatenakun1.github.io/halunelino/",
|
|
2490
|
+
rino121: "https://harunerino.vercel.app/",
|
|
2296
2491
|
roze: "https://tabaneroze.ninja-web.net/terms-of-use.html",
|
|
2297
2492
|
ruko_male: "https://long-sleeper.net/index.php?id=22",
|
|
2298
2493
|
ruko_female: "https://long-sleeper.net/index.php?id=22",
|
|
@@ -2301,7 +2496,8 @@ var KOE_VOICEBANK_TERMS = {
|
|
|
2301
2496
|
rei: "https://mechanicalgirl.jp/guidelines/",
|
|
2302
2497
|
mgroid: "https://x.com/nisusansu/status/1048825378188353536",
|
|
2303
2498
|
motroid: "https://www.nicovideo.jp/watch/sm40031282",
|
|
2304
|
-
nynroid: "https://www.bilibili.com/video/BV1V24y1a7qs"
|
|
2499
|
+
nynroid: "https://www.bilibili.com/video/BV1V24y1a7qs",
|
|
2500
|
+
uc: "https://chi9nekiriko.wixsite.com/home/%E5%88%A9%E7%94%A8%E8%A6%8F%E7%B4%84"
|
|
2305
2501
|
};
|
|
2306
2502
|
var koeUrl = (name, base = KOE_BASE_URL) => `${base}/${encodeURIComponent(name)}`;
|
|
2307
2503
|
var DEFAULT_WORLDLINE_SCRIPT = "https://onjmin.github.io/koe/demo/world/worldline.js";
|
|
@@ -2390,7 +2586,7 @@ var createLocalBackend = async (options) => {
|
|
|
2390
2586
|
}
|
|
2391
2587
|
return p;
|
|
2392
2588
|
};
|
|
2393
|
-
const renderAlias = async (alias, pitch, durationMs) => {
|
|
2589
|
+
const renderAlias = async (alias, pitch, durationMs, vibrato) => {
|
|
2394
2590
|
const pcm = await getPcm(alias);
|
|
2395
2591
|
if (!pcm || pcm.length === 0) return null;
|
|
2396
2592
|
const entry = bank.manifest.phonemes[alias];
|
|
@@ -2399,7 +2595,7 @@ var createLocalBackend = async (options) => {
|
|
|
2399
2595
|
if (worldline) {
|
|
2400
2596
|
const audio = worldline.renderNote({
|
|
2401
2597
|
pcm,
|
|
2402
|
-
pitch: targetHz,
|
|
2598
|
+
pitch: vibrato ? vibratoPitchCurve(targetHz, lead.preMs) : targetHz,
|
|
2403
2599
|
durationMs,
|
|
2404
2600
|
...lead
|
|
2405
2601
|
});
|
|
@@ -2466,7 +2662,7 @@ var createWorkerBackend = async (workerUrl, options) => {
|
|
|
2466
2662
|
});
|
|
2467
2663
|
onReady = null;
|
|
2468
2664
|
onFail = null;
|
|
2469
|
-
const renderAlias = (alias, pitch, durationMs) => new Promise((resolve) => {
|
|
2665
|
+
const renderAlias = (alias, pitch, durationMs, vibrato) => new Promise((resolve) => {
|
|
2470
2666
|
const id = ++reqId;
|
|
2471
2667
|
pending.set(
|
|
2472
2668
|
id,
|
|
@@ -2479,7 +2675,8 @@ var createWorkerBackend = async (workerUrl, options) => {
|
|
|
2479
2675
|
id,
|
|
2480
2676
|
alias,
|
|
2481
2677
|
pitch,
|
|
2482
|
-
durationMs
|
|
2678
|
+
durationMs,
|
|
2679
|
+
vibrato
|
|
2483
2680
|
});
|
|
2484
2681
|
});
|
|
2485
2682
|
return {
|
|
@@ -2508,15 +2705,15 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2508
2705
|
const inflight = /* @__PURE__ */ new Map();
|
|
2509
2706
|
const active = /* @__PURE__ */ new Set();
|
|
2510
2707
|
let prevVowel = "";
|
|
2511
|
-
const keyOf = (alias, pitch, durationMs) => `${alias}|${pitch}|${Math.round(durationMs / 10) * 10}`;
|
|
2512
|
-
const renderInto = (alias, pitch, durationMs) => {
|
|
2513
|
-
const key = keyOf(alias, pitch, durationMs);
|
|
2708
|
+
const keyOf = (alias, pitch, durationMs, vibrato) => `${alias}|${pitch}|${Math.round(durationMs / 10) * 10}${vibrato ? "|vib" : ""}`;
|
|
2709
|
+
const renderInto = (alias, pitch, durationMs, vibrato) => {
|
|
2710
|
+
const key = keyOf(alias, pitch, durationMs, vibrato);
|
|
2514
2711
|
const existing = renderCache.get(key);
|
|
2515
2712
|
if (existing !== void 0) return Promise.resolve(existing);
|
|
2516
2713
|
const flying = inflight.get(key);
|
|
2517
2714
|
if (flying) return flying;
|
|
2518
2715
|
const p = (async () => {
|
|
2519
|
-
const out = await backend.renderAlias(alias, pitch, durationMs);
|
|
2716
|
+
const out = await backend.renderAlias(alias, pitch, durationMs, vibrato);
|
|
2520
2717
|
let rendered = null;
|
|
2521
2718
|
if (out) {
|
|
2522
2719
|
const buf = ctx.createBuffer(1, out.pcm.length, KOE_SAMPLE_RATE);
|
|
@@ -2531,7 +2728,7 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2531
2728
|
return p;
|
|
2532
2729
|
};
|
|
2533
2730
|
const LEADCAP_S = 0.09;
|
|
2534
|
-
const schedule = (r, t0, peak, pan) => {
|
|
2731
|
+
const schedule = (r, t0, peak, pan, reverbSend = 0) => {
|
|
2535
2732
|
let out = destination;
|
|
2536
2733
|
let panner = null;
|
|
2537
2734
|
if (typeof ctx.createStereoPanner === "function") {
|
|
@@ -2540,6 +2737,12 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2540
2737
|
panner.connect(destination);
|
|
2541
2738
|
out = panner;
|
|
2542
2739
|
}
|
|
2740
|
+
let sendGain = null;
|
|
2741
|
+
if (options.reverbBus && reverbSend > 0 && panner) {
|
|
2742
|
+
sendGain = ctx.createGain();
|
|
2743
|
+
sendGain.gain.value = Math.max(0, Math.min(1, reverbSend));
|
|
2744
|
+
panner.connect(sendGain).connect(options.reverbBus);
|
|
2745
|
+
}
|
|
2543
2746
|
const src = ctx.createBufferSource();
|
|
2544
2747
|
src.buffer = r.audio;
|
|
2545
2748
|
src.playbackRate.value = r.rate;
|
|
@@ -2565,6 +2768,7 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2565
2768
|
src.disconnect();
|
|
2566
2769
|
env.disconnect();
|
|
2567
2770
|
panner?.disconnect();
|
|
2771
|
+
sendGain?.disconnect();
|
|
2568
2772
|
};
|
|
2569
2773
|
};
|
|
2570
2774
|
const model = (syllable, e) => {
|
|
@@ -2583,10 +2787,10 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2583
2787
|
const pan = e.pan ?? 0;
|
|
2584
2788
|
const durationMs = Math.max(60, e.duration * 1e3);
|
|
2585
2789
|
void renderInto(alias, e.pitch, durationMs).then((r) => {
|
|
2586
|
-
if (r) schedule(r, t0, peak, pan);
|
|
2790
|
+
if (r) schedule(r, t0, peak, pan, e.reverbSend);
|
|
2587
2791
|
});
|
|
2588
2792
|
};
|
|
2589
|
-
model.renderToCache = async (syllable, prevVowelArg, pitch, durationMs) => {
|
|
2793
|
+
model.renderToCache = async (syllable, prevVowelArg, pitch, durationMs, vibrato) => {
|
|
2590
2794
|
if (syllable.consonant === "Q" || syllable.vowel === "") return null;
|
|
2591
2795
|
const alias = resolveKoeAlias(
|
|
2592
2796
|
backend.hasAlias,
|
|
@@ -2597,12 +2801,13 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2597
2801
|
);
|
|
2598
2802
|
if (!alias) return null;
|
|
2599
2803
|
const dMs = Math.max(60, durationMs);
|
|
2600
|
-
const
|
|
2601
|
-
|
|
2804
|
+
const vib = !!vibrato && dMs / 1e3 >= VIBRATO_MIN_SEC;
|
|
2805
|
+
const r = await renderInto(alias, pitch, dMs, vib);
|
|
2806
|
+
return r ? keyOf(alias, pitch, dMs, vib) : null;
|
|
2602
2807
|
};
|
|
2603
|
-
model.scheduleCached = (key, t0, peak, pan) => {
|
|
2808
|
+
model.scheduleCached = (key, t0, peak, pan, reverbSend) => {
|
|
2604
2809
|
const r = renderCache.get(key);
|
|
2605
|
-
if (r) schedule(r, t0, peak, pan);
|
|
2810
|
+
if (r) schedule(r, t0, peak, pan, reverbSend);
|
|
2606
2811
|
};
|
|
2607
2812
|
model.stopAll = () => {
|
|
2608
2813
|
for (const src of active) {
|
|
@@ -2633,7 +2838,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2633
2838
|
const masterGain = ctx.createGain();
|
|
2634
2839
|
masterGain.connect(destination);
|
|
2635
2840
|
const loaded = /* @__PURE__ */ new Map([
|
|
2636
|
-
[FALLBACK_MODEL, createKlattVoice(ctx, masterGain)]
|
|
2841
|
+
[FALLBACK_MODEL, createKlattVoice(ctx, masterGain, options.reverbBus)]
|
|
2637
2842
|
]);
|
|
2638
2843
|
const loading = /* @__PURE__ */ new Map();
|
|
2639
2844
|
const load2 = (model) => {
|
|
@@ -2653,7 +2858,8 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2653
2858
|
koe,
|
|
2654
2859
|
worldlineScriptUrl: options.worldlineScriptUrl,
|
|
2655
2860
|
lightweight: options.lightweight,
|
|
2656
|
-
voiceWorkerUrl: options.voiceWorkerUrl
|
|
2861
|
+
voiceWorkerUrl: options.voiceWorkerUrl,
|
|
2862
|
+
reverbBus: options.reverbBus
|
|
2657
2863
|
})
|
|
2658
2864
|
))().then((v) => {
|
|
2659
2865
|
loaded.set(m, v);
|
|
@@ -2698,7 +2904,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2698
2904
|
forEachSungNote(track, (note, prevVowel) => {
|
|
2699
2905
|
if (n >= count && note.startSec >= STREAM_LOOKAHEAD_SEC) return;
|
|
2700
2906
|
n++;
|
|
2701
|
-
tasks.push({ model: m, note, prevVowel });
|
|
2907
|
+
tasks.push({ model: m, note, prevVowel, vibrato: track.vibrato });
|
|
2702
2908
|
});
|
|
2703
2909
|
}
|
|
2704
2910
|
const total = tasks.length;
|
|
@@ -2713,7 +2919,8 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2713
2919
|
task.note.syllable,
|
|
2714
2920
|
task.prevVowel,
|
|
2715
2921
|
task.note.pitch,
|
|
2716
|
-
task.note.durationSec * 1e3
|
|
2922
|
+
task.note.durationSec * 1e3,
|
|
2923
|
+
task.vibrato
|
|
2717
2924
|
) ?? Promise.resolve(null));
|
|
2718
2925
|
done++;
|
|
2719
2926
|
onProgress?.(done, total);
|
|
@@ -2758,13 +2965,14 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2758
2965
|
note.syllable,
|
|
2759
2966
|
prevVowel,
|
|
2760
2967
|
note.pitch,
|
|
2761
|
-
note.durationSec * 1e3
|
|
2968
|
+
note.durationSec * 1e3,
|
|
2969
|
+
track.vibrato
|
|
2762
2970
|
);
|
|
2763
2971
|
if (session !== streamSession) return;
|
|
2764
2972
|
if (key) {
|
|
2765
2973
|
const delay = ctx.currentTime - t0;
|
|
2766
2974
|
if (delay < 0.05) {
|
|
2767
|
-
scheduleCached(key, t0, peak, track.pan);
|
|
2975
|
+
scheduleCached(key, t0, peak, track.pan, track.reverbSend);
|
|
2768
2976
|
opts?.onScheduled?.(track, note, t0);
|
|
2769
2977
|
} else {
|
|
2770
2978
|
console.warn(
|
|
@@ -2783,7 +2991,8 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2783
2991
|
volume: peak,
|
|
2784
2992
|
when,
|
|
2785
2993
|
duration: note.durationSec,
|
|
2786
|
-
pan: track.pan
|
|
2994
|
+
pan: track.pan,
|
|
2995
|
+
reverbSend: track.reverbSend
|
|
2787
2996
|
});
|
|
2788
2997
|
opts?.onScheduled?.(track, note, t0);
|
|
2789
2998
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
@@ -5644,7 +5853,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
5644
5853
|
const length = Math.max(1, Math.floor(ctx.sampleRate * dur));
|
|
5645
5854
|
const buffer = ctx.createBuffer(1, length, ctx.sampleRate);
|
|
5646
5855
|
const data = buffer.getChannelData(0);
|
|
5647
|
-
for (let
|
|
5856
|
+
for (let i2 = 0; i2 < length; i2++) data[i2] = Math.random() * 2 - 1;
|
|
5648
5857
|
const src = ctx.createBufferSource();
|
|
5649
5858
|
src.buffer = buffer;
|
|
5650
5859
|
const filter = ctx.createBiquadFilter();
|
|
@@ -7565,6 +7774,9 @@ var teto_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAA
|
|
|
7565
7774
|
// assets/tsukuyomi.png
|
|
7566
7775
|
var tsukuyomi_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB3UlEQVR42tWXPUsDQRCGnwuijYIoFqKmEDSCxIgIgqnsogbsrC3ERiwN4g8Ikk6sFH+BnYofvcTKxoigBCzEYGGjWIiCOYvNBHe5TdQUt051czc3e++zO7tzHnUst7vn04BlFue9Ws8jhGxN9ZTPzU43NkIlj41E6AQ8m/JYfByAoWgXAPtHJzRCRN43SbizBkzlv1X2VzLuVoHYzf0TAMnys+aLCTGThMTJGnKfQOpyWF1cvgHQsh4FYPDzRd3vmQHgoPShJbi9uqhJyPk1UK3Jwsq1/115rLst8AX/4UFP0NsbGHf7+Kr579l7zR/ZGvbcrAJR7vvqEOwcTdZMYIuTPCYJUS7Ewydgzn2Bay2gdWzqR4nMuMPlhcC5l/HcWQOnCaU4lVU3xI9tnwFQnOgDoDmdDs5QKmlxYhdGmBA2ibhTBfKFHCkCm00dAKymJn+USAidHx8DkI+0q7PBUC7j5BJ7jlSB7RyXziVT8fM7Oz7AeLmsz3VEaWi7UvtAcmvJC+qmq4T/XT8gdTsw2692to07AF7jeU35wFq/7COqzhdVnVOnu3aHgNm1VpVXlImJX9zQffO5kDg1dlb3CNj6dZsVK2vAVP7Xf8bwCfxWuc23Eanmt/xlh07gC6oBviFE8rZHAAAAAElFTkSuQmCC";
|
|
7567
7776
|
|
|
7777
|
+
// assets/uc.png
|
|
7778
|
+
var uc_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB/ElEQVR42s2WPUhbURTHfxHniEEIVdvFmDaTiIJjBpcuGQrFr2JDaoeCkxRdAg6WVPAD20FwqEoUQUs7hdAuDaSbYNpGF6VxiaLooCCdREyHlxs4z/deEhG8Zwn/m8d57/+759x7XEAB53BxuyhU8lAN9xyusLfe8UvTrT4ALhr3q0ocSjsDiJ+c60Gg9q6dq1jYbATgTdeR3jVQW63z5t6nABxufBd6syMLQFemDYDA0jEA829nAPg8O6ApAVWNYW99RU7tQjkvkcDQw9kpAILa14B579203iqhmURqv1gDDIj+Vyesfl1Qbq/NNRFJ7gDwsblBPthh/AxuvQDgzORc33PgImv0r7vtgeV6icTkFQDvCBgL26ZEr04r+oD7J6D6P21DoqR3s0LnIntC+5YfC900ViT5xOiKkPeP6oKC3l1A6p+QblqE/tV/aZnoBpG09QsVcUVCHwLBvznxRyJotGsu+FCsj0zkLRPNjT8qOj9wrB39ZsJEIiGGt/Bq2HqPy5CwI2CeDZ9/WjHWQyFNCJjn9+TUN3GGr3auAXAdME6+TCYjEtTlv8rqf/Ze6C+vXwrnJTLaEfD0eBxvRXUL+vN+x4TRaFTon2sfAJhe/6H5bThU0w7A4vXvqmZBO+fmGO3rViQ0vwvsSMQH4wDEYrGKnKu9134e+A/zObZWSEHtdQAAAABJRU5ErkJggg==";
|
|
7779
|
+
|
|
7568
7780
|
// src/voice-images.ts
|
|
7569
7781
|
var VOICE_IMAGES = {
|
|
7570
7782
|
puyuyu: puyuyu_default,
|
|
@@ -7577,7 +7789,8 @@ var VOICE_IMAGES = {
|
|
|
7577
7789
|
rei: rei_default,
|
|
7578
7790
|
MGRoid: MGRoid_default,
|
|
7579
7791
|
MOTRoid: MOTRoid_default,
|
|
7580
|
-
NYNRoid: NYNRoid_default
|
|
7792
|
+
NYNRoid: NYNRoid_default,
|
|
7793
|
+
uc: uc_default
|
|
7581
7794
|
};
|
|
7582
7795
|
var FALLBACK_VOCAL_ICON = Chip_default;
|
|
7583
7796
|
|
|
@@ -7639,8 +7852,8 @@ var copyToClipboard = async (doc, text) => {
|
|
|
7639
7852
|
};
|
|
7640
7853
|
var toBase64Url = (bytes) => {
|
|
7641
7854
|
let bin = "";
|
|
7642
|
-
for (let
|
|
7643
|
-
bin += String.fromCharCode(bytes[
|
|
7855
|
+
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
7856
|
+
bin += String.fromCharCode(bytes[i2]);
|
|
7644
7857
|
}
|
|
7645
7858
|
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
7646
7859
|
};
|
|
@@ -7653,8 +7866,8 @@ var SHIFT_KATAKANA = 255;
|
|
|
7653
7866
|
var VALUE_PROLONGED = 223;
|
|
7654
7867
|
var customEncode = (str) => {
|
|
7655
7868
|
const bytes = [];
|
|
7656
|
-
for (let
|
|
7657
|
-
const code = str.charCodeAt(
|
|
7869
|
+
for (let i2 = 0; i2 < str.length; i2++) {
|
|
7870
|
+
const code = str.charCodeAt(i2);
|
|
7658
7871
|
if (code === 32) {
|
|
7659
7872
|
continue;
|
|
7660
7873
|
}
|
|
@@ -7696,37 +7909,37 @@ var fromBase64Url = (s) => {
|
|
|
7696
7909
|
}
|
|
7697
7910
|
const bin = atob(normalized);
|
|
7698
7911
|
const bytes = new Uint8Array(bin.length);
|
|
7699
|
-
for (let
|
|
7700
|
-
bytes[
|
|
7912
|
+
for (let i2 = 0; i2 < bin.length; i2++) {
|
|
7913
|
+
bytes[i2] = bin.charCodeAt(i2);
|
|
7701
7914
|
}
|
|
7702
7915
|
return bytes;
|
|
7703
7916
|
};
|
|
7704
7917
|
var customDecode = (bytes) => {
|
|
7705
7918
|
let str = "";
|
|
7706
|
-
let
|
|
7707
|
-
while (
|
|
7708
|
-
const byte = bytes[
|
|
7919
|
+
let i2 = 0;
|
|
7920
|
+
while (i2 < bytes.length) {
|
|
7921
|
+
const byte = bytes[i2];
|
|
7709
7922
|
if (byte <= 127) {
|
|
7710
7923
|
str += String.fromCharCode(byte);
|
|
7711
|
-
|
|
7924
|
+
i2++;
|
|
7712
7925
|
} else if (byte === VALUE_PROLONGED) {
|
|
7713
7926
|
str += String.fromCharCode(PROLONGED_MARK);
|
|
7714
|
-
|
|
7927
|
+
i2++;
|
|
7715
7928
|
} else if (byte >= 128 && byte <= 222) {
|
|
7716
7929
|
str += String.fromCharCode(HIRAGANA_START + (byte - 128));
|
|
7717
|
-
|
|
7930
|
+
i2++;
|
|
7718
7931
|
} else if (byte === SHIFT_KATAKANA) {
|
|
7719
|
-
if (
|
|
7720
|
-
const nextByte = bytes[
|
|
7932
|
+
if (i2 + 1 < bytes.length) {
|
|
7933
|
+
const nextByte = bytes[i2 + 1];
|
|
7721
7934
|
if (nextByte >= 128 && nextByte <= 222) {
|
|
7722
7935
|
str += String.fromCharCode(HIRAGANA_START + 96 + (nextByte - 128));
|
|
7723
7936
|
}
|
|
7724
|
-
|
|
7937
|
+
i2 += 2;
|
|
7725
7938
|
} else {
|
|
7726
|
-
|
|
7939
|
+
i2++;
|
|
7727
7940
|
}
|
|
7728
7941
|
} else {
|
|
7729
|
-
|
|
7942
|
+
i2++;
|
|
7730
7943
|
}
|
|
7731
7944
|
}
|
|
7732
7945
|
return str;
|
|
@@ -8291,7 +8504,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8291
8504
|
const beatRow = doc.createElement("div");
|
|
8292
8505
|
beatRow.className = "dtm-player-beat-row";
|
|
8293
8506
|
const beatDots = [];
|
|
8294
|
-
for (let
|
|
8507
|
+
for (let i2 = 0; i2 < 4; i2++) {
|
|
8295
8508
|
const d = doc.createElement("span");
|
|
8296
8509
|
d.className = "dtm-player-beat-dot";
|
|
8297
8510
|
beatRow.appendChild(d);
|
|
@@ -8395,9 +8608,9 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8395
8608
|
lane.appendChild(metaEl);
|
|
8396
8609
|
}
|
|
8397
8610
|
const count = Math.min(notes.length, lyricTrack.syllables.length);
|
|
8398
|
-
for (let
|
|
8399
|
-
const note = notes[
|
|
8400
|
-
if (breaks.has(
|
|
8611
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
8612
|
+
const note = notes[i2];
|
|
8613
|
+
if (breaks.has(i2)) {
|
|
8401
8614
|
const br = doc.createElement("span");
|
|
8402
8615
|
br.className = "dtm-tk dtm-tk--break";
|
|
8403
8616
|
br.textContent = "\\n";
|
|
@@ -8405,7 +8618,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8405
8618
|
}
|
|
8406
8619
|
const span = doc.createElement("span");
|
|
8407
8620
|
span.className = "dtm-tk dtm-tk--lyric";
|
|
8408
|
-
span.textContent = lyricTrack.syllables[
|
|
8621
|
+
span.textContent = lyricTrack.syllables[i2].kana;
|
|
8409
8622
|
lane.appendChild(span);
|
|
8410
8623
|
laneTokens.push({
|
|
8411
8624
|
el: span,
|
|
@@ -8558,8 +8771,8 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8558
8771
|
const intStep = Math.floor(step);
|
|
8559
8772
|
playStep = intStep;
|
|
8560
8773
|
const beatIndex = Math.floor(step / STEPS_PER_BEAT2) % 4;
|
|
8561
|
-
for (let
|
|
8562
|
-
beatDots[
|
|
8774
|
+
for (let i2 = 0; i2 < 4; i2++)
|
|
8775
|
+
beatDots[i2].classList.toggle("dtm-player-beat-dot--on", i2 === beatIndex);
|
|
8563
8776
|
barEl.textContent = String(Math.floor(step / STEPS_PER_BAR2) + 1);
|
|
8564
8777
|
if (!isSeeking) {
|
|
8565
8778
|
seekInput.value = String(Math.min(maxStep, Math.max(0, intStep)));
|
|
@@ -8654,11 +8867,11 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8654
8867
|
const semis = (lt.octave ?? 0) * 12;
|
|
8655
8868
|
const count = Math.min(sorted.length, lt.syllables.length);
|
|
8656
8869
|
const notes = [];
|
|
8657
|
-
for (let
|
|
8658
|
-
const n = sorted[
|
|
8870
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
8871
|
+
const n = sorted[i2];
|
|
8659
8872
|
if (n.startStep < fromStep) continue;
|
|
8660
8873
|
notes.push({
|
|
8661
|
-
syllable: lt.syllables[
|
|
8874
|
+
syllable: lt.syllables[i2],
|
|
8662
8875
|
pitch: n.pitch + semis,
|
|
8663
8876
|
startSec: (n.startStep - fromStep) * secondsPerStep,
|
|
8664
8877
|
durationSec: n.durationSteps * secondsPerStep * gate
|
|
@@ -8669,6 +8882,8 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8669
8882
|
model: lt.model,
|
|
8670
8883
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
8671
8884
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
8885
|
+
vibrato: lt.vibrato,
|
|
8886
|
+
reverbSend: (lt.reverb ?? 0) / 100,
|
|
8672
8887
|
notes
|
|
8673
8888
|
};
|
|
8674
8889
|
});
|
|
@@ -8928,13 +9143,13 @@ var findZone = (ctx, fontName, zones, pitchs = []) => {
|
|
|
8928
9143
|
for (const zone of zones) {
|
|
8929
9144
|
const low = zone.keyRangeLow | 0, high = zone.keyRangeHigh | 0;
|
|
8930
9145
|
if (low > high) continue;
|
|
8931
|
-
for (let
|
|
9146
|
+
for (let i2 = low; i2 <= high; i2++) pitchs.push(i2);
|
|
8932
9147
|
}
|
|
8933
9148
|
const set = new Set(pitchs);
|
|
8934
9149
|
const map = new Map(pitchs.map((v) => [v, zones[0]]));
|
|
8935
|
-
for (let
|
|
9150
|
+
for (let i2 = zones.length - 1; i2 >= 0; i2--)
|
|
8936
9151
|
for (const v of set) {
|
|
8937
|
-
const zone = zones[
|
|
9152
|
+
const zone = zones[i2];
|
|
8938
9153
|
if (v < zone.keyRangeLow || v > zone.keyRangeHigh) continue;
|
|
8939
9154
|
set.delete(v);
|
|
8940
9155
|
map.set(v, { ...zone });
|
|
@@ -8964,13 +9179,13 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
8964
9179
|
const decoded = atob(zone.sample);
|
|
8965
9180
|
zone.buffer = ctx.createBuffer(1, decoded.length / 2, zone.sampleRate);
|
|
8966
9181
|
const a = zone.buffer.getChannelData(0);
|
|
8967
|
-
for (let
|
|
8968
|
-
let b1 = decoded.charCodeAt(
|
|
9182
|
+
for (let i2 = 0; i2 < decoded.length / 2; i2++) {
|
|
9183
|
+
let b1 = decoded.charCodeAt(i2 * 2), b2 = decoded.charCodeAt(i2 * 2 + 1);
|
|
8969
9184
|
if (b1 < 0) b1 = 256 + b1;
|
|
8970
9185
|
if (b2 < 0) b2 = 256 + b2;
|
|
8971
9186
|
let n = b2 * 256 + b1;
|
|
8972
9187
|
if (n >= 65536 / 2) n = n - 65536;
|
|
8973
|
-
a[
|
|
9188
|
+
a[i2] = n / 65536;
|
|
8974
9189
|
}
|
|
8975
9190
|
} else if (zone.file) {
|
|
8976
9191
|
const bytes = Uint8Array.from(atob(zone.file), (c) => c.charCodeAt(0));
|
|
@@ -9010,10 +9225,10 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9010
9225
|
let loopPeak = 0;
|
|
9011
9226
|
if (oldBuf.numberOfChannels > 0) {
|
|
9012
9227
|
const ch0 = oldBuf.getChannelData(0);
|
|
9013
|
-
for (let
|
|
9014
|
-
const abs = Math.abs(ch0[
|
|
9228
|
+
for (let i2 = 0; i2 < ch0.length; i2++) {
|
|
9229
|
+
const abs = Math.abs(ch0[i2]);
|
|
9015
9230
|
if (abs > totalPeak) totalPeak = abs;
|
|
9016
|
-
if (
|
|
9231
|
+
if (i2 >= loopStartFrame && i2 < loopEndFrame) {
|
|
9017
9232
|
if (abs > loopPeak) loopPeak = abs;
|
|
9018
9233
|
}
|
|
9019
9234
|
}
|
|
@@ -9032,16 +9247,16 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9032
9247
|
for (let ch = 0; ch < oldBuf.numberOfChannels; ch++) {
|
|
9033
9248
|
const oldData = oldBuf.getChannelData(ch);
|
|
9034
9249
|
const newData = newBuf.getChannelData(ch);
|
|
9035
|
-
for (let
|
|
9036
|
-
const ratio = attackLength > 1 ?
|
|
9250
|
+
for (let i2 = 0; i2 < attackLength; i2++) {
|
|
9251
|
+
const ratio = attackLength > 1 ? i2 / (attackLength - 1) : 0;
|
|
9037
9252
|
const m = 1 + (gainMultiplier - 1) * ratio;
|
|
9038
|
-
newData[
|
|
9253
|
+
newData[i2] = oldData[i2] * m;
|
|
9039
9254
|
}
|
|
9040
9255
|
let offset = attackLength;
|
|
9041
9256
|
const loopData = oldData.subarray(loopStartFrame, loopEndFrame);
|
|
9042
9257
|
const normalizedLoopData = new Float32Array(loopLengthFrame);
|
|
9043
|
-
for (let
|
|
9044
|
-
normalizedLoopData[
|
|
9258
|
+
for (let i2 = 0; i2 < loopLengthFrame; i2++) {
|
|
9259
|
+
normalizedLoopData[i2] = loopData[i2] * gainMultiplier;
|
|
9045
9260
|
}
|
|
9046
9261
|
for (let r = 0; r < repeatCount; r++) {
|
|
9047
9262
|
newData.set(normalizedLoopData, offset);
|
|
@@ -9051,8 +9266,8 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9051
9266
|
const releaseData = oldData.subarray(loopEndFrame);
|
|
9052
9267
|
if (gainMultiplier !== 1) {
|
|
9053
9268
|
const normalizedRelease = new Float32Array(releaseLength);
|
|
9054
|
-
for (let
|
|
9055
|
-
normalizedRelease[
|
|
9269
|
+
for (let i2 = 0; i2 < releaseLength; i2++) {
|
|
9270
|
+
normalizedRelease[i2] = releaseData[i2] * gainMultiplier;
|
|
9056
9271
|
}
|
|
9057
9272
|
newData.set(normalizedRelease, offset);
|
|
9058
9273
|
} else {
|
|
@@ -9248,10 +9463,10 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
9248
9463
|
if (segments.length === 0) continue;
|
|
9249
9464
|
const hasMultiSeg = segments.length > 1;
|
|
9250
9465
|
const parts = [];
|
|
9251
|
-
for (let
|
|
9252
|
-
if (hasMultiSeg &&
|
|
9466
|
+
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
9467
|
+
if (hasMultiSeg && i2 > 0)
|
|
9253
9468
|
parts.push({ text: "|", isChord: false, eventIdx: -1 });
|
|
9254
|
-
const bar = segments[
|
|
9469
|
+
const bar = segments[i2].trim();
|
|
9255
9470
|
if (!bar) continue;
|
|
9256
9471
|
const splitAt = [];
|
|
9257
9472
|
for (let j = 0; j < bar.length; j++) {
|
|
@@ -10414,6 +10629,11 @@ var buildUI = (target, options) => {
|
|
|
10414
10629
|
<input type="range" class="dtm-range dtm-grow" data-dtm="master-volume" value="50" min="0" max="100">
|
|
10415
10630
|
<span class="dtm-label" data-dtm="master-volume-label">50%</span>
|
|
10416
10631
|
</div>
|
|
10632
|
+
<div class="dtm-row">
|
|
10633
|
+
<span class="dtm-label">\u30EA\u30D0\u30FC\u30D6</span>
|
|
10634
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="reverb-amount" value="0" min="0" max="100" aria-label="\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\uFF08\u5168\u30C8\u30E9\u30C3\u30AF\u3078\u4E00\u5F8B\u306B\u639B\u304B\u308B\u6B8B\u97FF\uFF09" title="\u30EA\u30D0\u30FC\u30D6">
|
|
10635
|
+
<span class="dtm-label" data-dtm="reverb-amount-label">0%</span>
|
|
10636
|
+
</div>
|
|
10417
10637
|
<div class="dtm-track-body" data-dtm="track-body"></div>
|
|
10418
10638
|
</div>
|
|
10419
10639
|
</details>
|
|
@@ -10637,6 +10857,8 @@ var buildUI = (target, options) => {
|
|
|
10637
10857
|
hScrollThumb: sel("hscroll-thumb"),
|
|
10638
10858
|
masterVolume: sel("master-volume"),
|
|
10639
10859
|
masterVolumeLabel: sel("master-volume-label"),
|
|
10860
|
+
reverbAmount: sel("reverb-amount"),
|
|
10861
|
+
reverbAmountLabel: sel("reverb-amount-label"),
|
|
10640
10862
|
trackTabs: sel("track-tabs"),
|
|
10641
10863
|
trackBody: sel("track-body"),
|
|
10642
10864
|
drumSelect: sel("drum-select"),
|
|
@@ -10805,16 +11027,16 @@ var generateRandomPattern = (core, options) => {
|
|
|
10805
11027
|
const scale = SCALES[Math.floor(Math.random() * SCALES.length)];
|
|
10806
11028
|
const rootOffset = Math.floor(Math.random() * 12);
|
|
10807
11029
|
const availablePitches = [];
|
|
10808
|
-
for (let
|
|
10809
|
-
const noteInOctave = (
|
|
10810
|
-
if (scale.includes(noteInOctave)) availablePitches.push(basePitch +
|
|
11030
|
+
for (let i2 = 0; i2 < 12; i2++) {
|
|
11031
|
+
const noteInOctave = (i2 - rootOffset + 12) % 12;
|
|
11032
|
+
if (scale.includes(noteInOctave)) availablePitches.push(basePitch + i2);
|
|
10811
11033
|
}
|
|
10812
11034
|
core.beginBatch();
|
|
10813
11035
|
for (let bar = 0; bar < numBars; bar++) {
|
|
10814
11036
|
const barStart = startStep + bar * stepsPerBar;
|
|
10815
11037
|
const numNotes = Math.floor(Math.random() * 4) + 2;
|
|
10816
11038
|
const occupied = /* @__PURE__ */ new Set();
|
|
10817
|
-
for (let
|
|
11039
|
+
for (let i2 = 0; i2 < numNotes; i2++) {
|
|
10818
11040
|
const stepInRange = Math.floor(Math.random() * (stepsPerBar / noteLength)) * noteLength;
|
|
10819
11041
|
const step = barStart + stepInRange;
|
|
10820
11042
|
if (occupied.has(step)) continue;
|
|
@@ -10915,10 +11137,10 @@ var STEPS_PER_BEAT3 = 48;
|
|
|
10915
11137
|
var analyzeMidiTracks = (midi) => {
|
|
10916
11138
|
const { tracks } = midi;
|
|
10917
11139
|
const result = [];
|
|
10918
|
-
for (let
|
|
11140
|
+
for (let i2 = 0; i2 < tracks.length; i2++) {
|
|
10919
11141
|
const notes = [];
|
|
10920
11142
|
let currentTime = 0;
|
|
10921
|
-
for (const event of tracks[
|
|
11143
|
+
for (const event of tracks[i2]) {
|
|
10922
11144
|
currentTime += event.delta;
|
|
10923
11145
|
if (event.noteOn && event.noteOn.velocity > 0) {
|
|
10924
11146
|
notes.push({
|
|
@@ -10941,8 +11163,8 @@ var analyzeMidiTracks = (midi) => {
|
|
|
10941
11163
|
const editableNotes = validNotes.filter((n) => n.channel !== 9);
|
|
10942
11164
|
if (validNotes.length > 0 && editableNotes.length === 0) continue;
|
|
10943
11165
|
result.push({
|
|
10944
|
-
index:
|
|
10945
|
-
name: `Ch${
|
|
11166
|
+
index: i2,
|
|
11167
|
+
name: `Ch${i2 + 1}`,
|
|
10946
11168
|
noteCount: editableNotes.length,
|
|
10947
11169
|
selected: editableNotes.length > 0
|
|
10948
11170
|
});
|
|
@@ -10989,8 +11211,8 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
10989
11211
|
const pitch = noteOff.noteNumber;
|
|
10990
11212
|
const channel = event.channel ?? 0;
|
|
10991
11213
|
if (channelNotes[channel]) {
|
|
10992
|
-
for (let
|
|
10993
|
-
const note = channelNotes[channel][
|
|
11214
|
+
for (let i2 = channelNotes[channel].length - 1; i2 >= 0; i2--) {
|
|
11215
|
+
const note = channelNotes[channel][i2];
|
|
10994
11216
|
if (note.pitch === pitch && note.end === null) {
|
|
10995
11217
|
note.end = currentTime;
|
|
10996
11218
|
break;
|
|
@@ -11020,10 +11242,10 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
11020
11242
|
const avgPitch = validNotes.reduce((sum, n) => sum + n.pitch, 0) / validNotes.length;
|
|
11021
11243
|
let maxSimultaneous = 0;
|
|
11022
11244
|
const sortedNotes = [...validNotes].sort((a, b) => a.start - b.start);
|
|
11023
|
-
for (let
|
|
11245
|
+
for (let i2 = 0; i2 < sortedNotes.length; i2++) {
|
|
11024
11246
|
let simultaneous = 1;
|
|
11025
|
-
for (let j =
|
|
11026
|
-
if (sortedNotes[j].start < sortedNotes[
|
|
11247
|
+
for (let j = i2 + 1; j < sortedNotes.length; j++) {
|
|
11248
|
+
if (sortedNotes[j].start < sortedNotes[i2].end) {
|
|
11027
11249
|
simultaneous++;
|
|
11028
11250
|
}
|
|
11029
11251
|
}
|
|
@@ -11034,14 +11256,14 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
11034
11256
|
const blocks = [];
|
|
11035
11257
|
let blockStart = sortedNotes[0].start;
|
|
11036
11258
|
let blockEnd = sortedNotes[0].end;
|
|
11037
|
-
for (let
|
|
11038
|
-
const gap = sortedNotes[
|
|
11259
|
+
for (let i2 = 1; i2 < sortedNotes.length; i2++) {
|
|
11260
|
+
const gap = sortedNotes[i2].start - sortedNotes[i2 - 1].end;
|
|
11039
11261
|
if (gap >= ticksPerBar) {
|
|
11040
11262
|
blocks.push({ start: blockStart, end: blockEnd });
|
|
11041
|
-
blockStart = sortedNotes[
|
|
11042
|
-
blockEnd = sortedNotes[
|
|
11263
|
+
blockStart = sortedNotes[i2].start;
|
|
11264
|
+
blockEnd = sortedNotes[i2].end;
|
|
11043
11265
|
} else {
|
|
11044
|
-
blockEnd = sortedNotes[
|
|
11266
|
+
blockEnd = sortedNotes[i2].end;
|
|
11045
11267
|
}
|
|
11046
11268
|
}
|
|
11047
11269
|
blocks.push({ start: blockStart, end: blockEnd });
|
|
@@ -11155,9 +11377,9 @@ var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
|
|
|
11155
11377
|
const noteOff = event.noteOff || event.noteOn;
|
|
11156
11378
|
if (noteOff) {
|
|
11157
11379
|
const pitch = noteOff.noteNumber;
|
|
11158
|
-
for (let
|
|
11159
|
-
if (active[
|
|
11160
|
-
active[
|
|
11380
|
+
for (let i2 = active.length - 1; i2 >= 0; i2--) {
|
|
11381
|
+
if (active[i2].pitch === pitch && active[i2].end === null) {
|
|
11382
|
+
active[i2].end = currentTime;
|
|
11161
11383
|
break;
|
|
11162
11384
|
}
|
|
11163
11385
|
}
|
|
@@ -11322,17 +11544,17 @@ var extractDrumPatternFromNotes = (rawNotes, drumFont = "FluidR3_GM_sf2_file:0")
|
|
|
11322
11544
|
let prev = bList[0];
|
|
11323
11545
|
const parts = key.split("_");
|
|
11324
11546
|
const noteObj = { step: +parts[0], pitch: +parts[1], velocity: +parts[2] };
|
|
11325
|
-
for (let
|
|
11326
|
-
if (
|
|
11547
|
+
for (let i2 = 1; i2 <= bList.length; i2++) {
|
|
11548
|
+
if (i2 === bList.length || bList[i2] !== prev + 1) {
|
|
11327
11549
|
const rKey = `${start}-${prev}`;
|
|
11328
11550
|
if (!rangeMap[rKey]) rangeMap[rKey] = [];
|
|
11329
11551
|
rangeMap[rKey].push(noteObj);
|
|
11330
|
-
if (
|
|
11331
|
-
start = bList[
|
|
11332
|
-
prev = bList[
|
|
11552
|
+
if (i2 < bList.length) {
|
|
11553
|
+
start = bList[i2];
|
|
11554
|
+
prev = bList[i2];
|
|
11333
11555
|
}
|
|
11334
11556
|
} else {
|
|
11335
|
-
prev = bList[
|
|
11557
|
+
prev = bList[i2];
|
|
11336
11558
|
}
|
|
11337
11559
|
}
|
|
11338
11560
|
}
|
|
@@ -11709,8 +11931,8 @@ var drawHeader = () => {
|
|
|
11709
11931
|
(g_draw_offset_x + g_header_canvas.width) / (stepsPerBar * stepWidth)
|
|
11710
11932
|
);
|
|
11711
11933
|
for (let bar = startBar; bar <= endBar + 1; bar++) {
|
|
11712
|
-
const
|
|
11713
|
-
const screenX =
|
|
11934
|
+
const x2 = bar * stepsPerBar * stepWidth;
|
|
11935
|
+
const screenX = x2;
|
|
11714
11936
|
g_header_ctx.beginPath();
|
|
11715
11937
|
g_header_ctx.moveTo(screenX, 0);
|
|
11716
11938
|
g_header_ctx.lineTo(screenX, HEADER_HEIGHT);
|
|
@@ -11757,11 +11979,11 @@ var drawGrid = (noteLengthSteps = 1) => {
|
|
|
11757
11979
|
const startX = Math.floor(g_draw_offset_x / (stepWidth * gridStep)) * stepWidth * gridStep;
|
|
11758
11980
|
const endX = g_draw_offset_x + g_grid_canvas.width;
|
|
11759
11981
|
const lineStep = stepWidth * gridStep;
|
|
11760
|
-
for (let
|
|
11761
|
-
const step =
|
|
11982
|
+
for (let x2 = startX; x2 <= endX; x2 += lineStep) {
|
|
11983
|
+
const step = x2 / stepWidth;
|
|
11762
11984
|
const isBarLine = step % stepsPerBar === 0;
|
|
11763
11985
|
const isNoteLine = step % gridStep === 0;
|
|
11764
|
-
const screenX =
|
|
11986
|
+
const screenX = x2 - g_draw_offset_x;
|
|
11765
11987
|
g_grid_ctx.beginPath();
|
|
11766
11988
|
g_grid_ctx.strokeStyle = isBarLine ? "#3d405b" : isNoteLine ? "#242840" : "#1a1d30";
|
|
11767
11989
|
g_grid_ctx.lineWidth = isBarLine ? 2 : 1;
|
|
@@ -11823,26 +12045,26 @@ var drawSelectedNotes = (notes, selectedIds, baseColor = [59, 130, 246, 1]) => {
|
|
|
11823
12045
|
var getXY = (e) => {
|
|
11824
12046
|
const { clientX, clientY } = e;
|
|
11825
12047
|
const rect = g_grid_canvas.getBoundingClientRect();
|
|
11826
|
-
const
|
|
12048
|
+
const x2 = Math.floor(clientX - rect.left);
|
|
11827
12049
|
const y = Math.floor(clientY - rect.top);
|
|
11828
|
-
return [
|
|
12050
|
+
return [x2, y, e.buttons];
|
|
11829
12051
|
};
|
|
11830
12052
|
var getGridPosition = (e) => {
|
|
11831
|
-
const [
|
|
12053
|
+
const [x2, y] = getXY(e);
|
|
11832
12054
|
const { keyCount, pitchRangeStart, keyHeight, stepWidth } = g_config;
|
|
11833
|
-
const step = Math.floor((
|
|
12055
|
+
const step = Math.floor((x2 + g_draw_offset_x) / stepWidth);
|
|
11834
12056
|
const absoluteY = y + g_draw_offset_y;
|
|
11835
12057
|
const yIndex = Math.floor(absoluteY / keyHeight);
|
|
11836
12058
|
const pitch = keyCount - 1 - yIndex + pitchRangeStart;
|
|
11837
|
-
return { step, pitch, x, y };
|
|
12059
|
+
return { step, pitch, x: x2, y };
|
|
11838
12060
|
};
|
|
11839
12061
|
var onClick = (callback) => {
|
|
11840
12062
|
g_grid_canvas.addEventListener(
|
|
11841
12063
|
"click",
|
|
11842
12064
|
(e) => {
|
|
11843
|
-
const [
|
|
12065
|
+
const [x2, y] = getXY(e);
|
|
11844
12066
|
const { keyCount, pitchRangeStart, keyHeight, stepWidth } = g_config;
|
|
11845
|
-
const step = Math.floor((
|
|
12067
|
+
const step = Math.floor((x2 + g_draw_offset_x) / stepWidth);
|
|
11846
12068
|
const absoluteY = y + g_draw_offset_y;
|
|
11847
12069
|
const yIndex = Math.floor(absoluteY / keyHeight);
|
|
11848
12070
|
const pitch = keyCount - 1 - yIndex + pitchRangeStart;
|
|
@@ -11854,8 +12076,8 @@ var onClick = (callback) => {
|
|
|
11854
12076
|
);
|
|
11855
12077
|
g_grid_canvas.addEventListener("contextmenu", (e) => e.preventDefault());
|
|
11856
12078
|
};
|
|
11857
|
-
var setDrawOffset = (
|
|
11858
|
-
g_draw_offset_x =
|
|
12079
|
+
var setDrawOffset = (x2, y) => {
|
|
12080
|
+
g_draw_offset_x = x2;
|
|
11859
12081
|
g_draw_offset_y = y;
|
|
11860
12082
|
drawKeyboard();
|
|
11861
12083
|
drawHeader();
|
|
@@ -12170,12 +12392,12 @@ var MMLCore = class _MMLCore {
|
|
|
12170
12392
|
currentCursor += steps;
|
|
12171
12393
|
}
|
|
12172
12394
|
};
|
|
12173
|
-
for (let
|
|
12174
|
-
const startStep = sortedSteps[
|
|
12395
|
+
for (let i2 = 0; i2 < sortedSteps.length; i2++) {
|
|
12396
|
+
const startStep = sortedSteps[i2];
|
|
12175
12397
|
const notes = notesByStep.get(startStep);
|
|
12176
12398
|
if (!notes) continue;
|
|
12177
12399
|
fillRests(startStep);
|
|
12178
|
-
const nextStart = sortedSteps[
|
|
12400
|
+
const nextStart = sortedSteps[i2 + 1] ?? endStep;
|
|
12179
12401
|
const physicsLimit = nextStart - currentCursor;
|
|
12180
12402
|
if (physicsLimit < MIN_STEP) {
|
|
12181
12403
|
continue;
|
|
@@ -12240,10 +12462,10 @@ var decomposeToMonophonic = (notes) => {
|
|
|
12240
12462
|
for (const note of sorted) {
|
|
12241
12463
|
let assigned = -1;
|
|
12242
12464
|
let minEnd = Infinity;
|
|
12243
|
-
for (let
|
|
12244
|
-
if (trackEnds[
|
|
12245
|
-
minEnd = trackEnds[
|
|
12246
|
-
assigned =
|
|
12465
|
+
for (let i2 = 0; i2 < tracks.length; i2++) {
|
|
12466
|
+
if (trackEnds[i2] <= note.startStep && trackEnds[i2] < minEnd) {
|
|
12467
|
+
minEnd = trackEnds[i2];
|
|
12468
|
+
assigned = i2;
|
|
12247
12469
|
}
|
|
12248
12470
|
}
|
|
12249
12471
|
if (assigned === -1) {
|
|
@@ -12299,6 +12521,14 @@ var CHORD_INFO_HTML2 = `
|
|
|
12299
12521
|
</ul>
|
|
12300
12522
|
</div>
|
|
12301
12523
|
`;
|
|
12524
|
+
var VIBRATO_INFO_HTML = `
|
|
12525
|
+
<div class="dtm-modal-body-content">
|
|
12526
|
+
<h4>\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u3068\u306F</h4>
|
|
12527
|
+
<p>ON\u306B\u3059\u308B\u3068\u3001\u4E00\u5B9A\u306E\u9577\u3055\uFF08\u7D040.35\u79D2\uFF09\u4EE5\u4E0A\u306E\u97F3\u7B26\uFF08\u30ED\u30F3\u30B0\u30C8\u30FC\u30F3\uFF09\u306B\u3060\u3051\u3001\u81EA\u52D5\u3067\u30D4\u30C3\u30C1\u304C\u5C0F\u523B\u307F\u306B\u63FA\u308C\u308B\u6B4C\u5531\u8868\u73FE\uFF08\u30D3\u30D6\u30E9\u30FC\u30C8\uFF09\u304C\u639B\u304B\u308A\u307E\u3059\u3002</p>
|
|
12528
|
+
<p style="margin-top:4px;"><small>\u77ED\u3044\u97F3\u7B26\u306B\u306F\u639B\u304B\u308A\u307E\u305B\u3093\u30021\u5468\u671F\u3082\u63FA\u308C\u304D\u3089\u306A\u3044\u3046\u3061\u306B\u6B21\u306E\u97F3\u3078\u79FB\u3063\u3066\u3057\u307E\u3044\u3001\u30D3\u30D6\u30E9\u30FC\u30C8\u3068\u3044\u3046\u3088\u308A\u5358\u306A\u308B\u97F3\u7A0B\u306E\u30D6\u30EC\u3068\u3057\u3066\u4E0D\u81EA\u7136\u306B\u805E\u3053\u3048\u308B\u305F\u3081\u3067\u3059\u3002</small></p>
|
|
12529
|
+
<p style="margin-top:4px;"><small>\u901F\u3055\u30FB\u6DF1\u3055\u306F\u8ABF\u6574\u3067\u304D\u307E\u305B\u3093\uFF08\u6B4C\u3068\u3057\u3066\u7834\u7DBB\u3057\u306B\u304F\u3044\u63A7\u3048\u3081\u306A\u91CF\u306B\u56FA\u5B9A\u3057\u3066\u3044\u307E\u3059\uFF09\u3002\u66F2\u3084\u7B87\u6240\u3054\u3068\u306B\u639B\u3051\u305F\u3044/\u639B\u3051\u305F\u304F\u306A\u3044\u304C\u3042\u308B\u5834\u5408\u306F\u3001\u30C8\u30E9\u30C3\u30AF\u3092\u5206\u3051\u3066\u6B4C\u8A5E\u3092\u66F8\u3044\u3066\u304F\u3060\u3055\u3044\u3002</small></p>
|
|
12530
|
+
</div>
|
|
12531
|
+
`;
|
|
12302
12532
|
var MIDI_INFO_HTML = `
|
|
12303
12533
|
<div class="dtm-modal-body-content">
|
|
12304
12534
|
<h4>1. MIDI\u30D5\u30A1\u30A4\u30EB\u3068\u306F</h4>
|
|
@@ -12502,7 +12732,7 @@ var LYRIC_MODEL_CATEGORIES = [
|
|
|
12502
12732
|
},
|
|
12503
12733
|
{
|
|
12504
12734
|
label: "\u304A\u3093J",
|
|
12505
|
-
models: ["roze", "shiyo", "rino"]
|
|
12735
|
+
models: ["roze", "shiyo", "rino", "rino121", "uc"]
|
|
12506
12736
|
},
|
|
12507
12737
|
{
|
|
12508
12738
|
label: "\u4E00\u822C",
|
|
@@ -12570,6 +12800,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
12570
12800
|
});
|
|
12571
12801
|
refs.masterVolume.value = String(options.masterVolume ?? 50);
|
|
12572
12802
|
refs.masterVolumeLabel.textContent = `${options.masterVolume ?? 50}%`;
|
|
12803
|
+
refs.reverbAmount.value = String(options.reverbAmount ?? 0);
|
|
12804
|
+
refs.reverbAmountLabel.textContent = `${options.reverbAmount ?? 0}%`;
|
|
12573
12805
|
refs.drumVolume.value = String(options.drumVolume ?? 80);
|
|
12574
12806
|
refs.drumVolumeLabel.textContent = `${options.drumVolume ?? 80}%`;
|
|
12575
12807
|
const renderConfig = {
|
|
@@ -12585,6 +12817,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
12585
12817
|
let bpm = options.defaultBpm ?? DEFAULT_BPM;
|
|
12586
12818
|
let masterVolume = options.masterVolume ?? 50;
|
|
12587
12819
|
options.singingVoices?.setVolume(masterVolume / 100);
|
|
12820
|
+
let reverbAmount = options.reverbAmount ?? 0;
|
|
12821
|
+
options.onReverbChange?.(reverbAmount);
|
|
12588
12822
|
let drumVolume = options.drumVolume ?? 80;
|
|
12589
12823
|
let currentDrumPattern = refs.drumSelect.value;
|
|
12590
12824
|
let currentDrumFont = options.drumFont ?? "FluidR3_GM_sf2_file:0";
|
|
@@ -12662,7 +12896,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
12662
12896
|
vocalVolume: t.vocalVolume,
|
|
12663
12897
|
vocalGate: t.vocalGate,
|
|
12664
12898
|
vocalPan: t.vocalPan,
|
|
12665
|
-
vocalOctave: t.vocalOctave
|
|
12899
|
+
vocalOctave: t.vocalOctave,
|
|
12900
|
+
vocalVibrato: t.vocalVibrato,
|
|
12901
|
+
vocalReverb: t.vocalReverb
|
|
12666
12902
|
};
|
|
12667
12903
|
if (lyricsDebounceTimer) clearTimeout(lyricsDebounceTimer);
|
|
12668
12904
|
lyricsDebounceTimer = setTimeout(() => {
|
|
@@ -12722,25 +12958,29 @@ var mountDAW = (target, options = {}) => {
|
|
|
12722
12958
|
vocalGate: 100,
|
|
12723
12959
|
vocalPan: 64,
|
|
12724
12960
|
vocalOctave: 0,
|
|
12961
|
+
vocalVibrato: false,
|
|
12962
|
+
vocalReverb: 0,
|
|
12725
12963
|
trackInstrument: ""
|
|
12726
12964
|
};
|
|
12727
12965
|
});
|
|
12728
12966
|
};
|
|
12729
12967
|
const buildLyricsMap = () => {
|
|
12730
12968
|
const map = /* @__PURE__ */ new Map();
|
|
12731
|
-
trackStates.forEach((t,
|
|
12969
|
+
trackStates.forEach((t, i2) => {
|
|
12732
12970
|
const model = t.lyricModel.trim();
|
|
12733
12971
|
const text = t.lyrics.trim();
|
|
12734
12972
|
if (!model || !text) return;
|
|
12735
12973
|
const syllables = normalizeLyrics(text);
|
|
12736
12974
|
if (syllables.length === 0) return;
|
|
12737
|
-
map.set(
|
|
12738
|
-
trackId:
|
|
12975
|
+
map.set(i2, {
|
|
12976
|
+
trackId: i2,
|
|
12739
12977
|
model: model.toLowerCase(),
|
|
12740
12978
|
volume: t.vocalVolume,
|
|
12741
12979
|
gate: t.vocalGate,
|
|
12742
12980
|
pan: t.vocalPan,
|
|
12743
12981
|
octave: t.vocalOctave,
|
|
12982
|
+
vibrato: t.vocalVibrato,
|
|
12983
|
+
reverb: t.vocalReverb,
|
|
12744
12984
|
syllables
|
|
12745
12985
|
});
|
|
12746
12986
|
});
|
|
@@ -12780,15 +13020,15 @@ var mountDAW = (target, options = {}) => {
|
|
|
12780
13020
|
const ctx = getGridContext();
|
|
12781
13021
|
const canvas = getGridCanvas();
|
|
12782
13022
|
if (!ctx) return;
|
|
12783
|
-
const
|
|
12784
|
-
if (
|
|
13023
|
+
const x2 = playStartStep * renderConfig.stepWidth - currentOffsetX;
|
|
13024
|
+
if (x2 < -10 || x2 > canvas.width + 10) return;
|
|
12785
13025
|
ctx.save();
|
|
12786
13026
|
ctx.strokeStyle = "#ffec27";
|
|
12787
13027
|
ctx.lineWidth = 2;
|
|
12788
13028
|
ctx.setLineDash([4, 4]);
|
|
12789
13029
|
ctx.beginPath();
|
|
12790
|
-
ctx.moveTo(
|
|
12791
|
-
ctx.lineTo(
|
|
13030
|
+
ctx.moveTo(x2, 0);
|
|
13031
|
+
ctx.lineTo(x2, canvas.height);
|
|
12792
13032
|
ctx.stroke();
|
|
12793
13033
|
ctx.restore();
|
|
12794
13034
|
};
|
|
@@ -12796,14 +13036,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
12796
13036
|
const ctx = getGridContext();
|
|
12797
13037
|
const canvas = getGridCanvas();
|
|
12798
13038
|
if (!ctx) return;
|
|
12799
|
-
const
|
|
12800
|
-
if (
|
|
13039
|
+
const x2 = currentPlayStep * renderConfig.stepWidth - currentOffsetX;
|
|
13040
|
+
if (x2 < 0 || x2 > canvas.width) return;
|
|
12801
13041
|
ctx.save();
|
|
12802
13042
|
ctx.strokeStyle = "#ff004d";
|
|
12803
13043
|
ctx.lineWidth = 2;
|
|
12804
13044
|
ctx.beginPath();
|
|
12805
|
-
ctx.moveTo(
|
|
12806
|
-
ctx.lineTo(
|
|
13045
|
+
ctx.moveTo(x2, 0);
|
|
13046
|
+
ctx.lineTo(x2, canvas.height);
|
|
12807
13047
|
ctx.stroke();
|
|
12808
13048
|
ctx.restore();
|
|
12809
13049
|
};
|
|
@@ -12931,8 +13171,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
12931
13171
|
if (maxOffsetX <= 0) return;
|
|
12932
13172
|
const rect = refs.hScroll.getBoundingClientRect();
|
|
12933
13173
|
const thumbW = Number.parseFloat(refs.hScrollThumb.style.width) || 40;
|
|
12934
|
-
const
|
|
12935
|
-
const ratio =
|
|
13174
|
+
const x2 = clamp3(clientX - rect.left - thumbW / 2, 0, rect.width - thumbW);
|
|
13175
|
+
const ratio = x2 / (rect.width - thumbW);
|
|
12936
13176
|
currentOffsetX = clamp3(ratio * maxOffsetX, 0, maxOffsetX);
|
|
12937
13177
|
setDrawOffset(currentOffsetX, currentOffsetY);
|
|
12938
13178
|
redrawAll();
|
|
@@ -12959,13 +13199,60 @@ var mountDAW = (target, options = {}) => {
|
|
|
12959
13199
|
let selectionStart = null;
|
|
12960
13200
|
let selectedOriginal = [];
|
|
12961
13201
|
let lastMultiPreviewPitch = null;
|
|
13202
|
+
const AUTO_SCROLL_MARGIN = 30;
|
|
13203
|
+
const AUTO_SCROLL_MAX_SPEED = 22;
|
|
13204
|
+
let autoScrollRAF = null;
|
|
13205
|
+
let lastMoveEvent = null;
|
|
13206
|
+
const computeEdgeSpeed = (pos, size) => {
|
|
13207
|
+
if (pos < AUTO_SCROLL_MARGIN) {
|
|
13208
|
+
const t = (AUTO_SCROLL_MARGIN - pos) / AUTO_SCROLL_MARGIN;
|
|
13209
|
+
return -Math.ceil(t * AUTO_SCROLL_MAX_SPEED);
|
|
13210
|
+
}
|
|
13211
|
+
if (pos > size - AUTO_SCROLL_MARGIN) {
|
|
13212
|
+
const t = (pos - (size - AUTO_SCROLL_MARGIN)) / AUTO_SCROLL_MARGIN;
|
|
13213
|
+
return Math.ceil(t * AUTO_SCROLL_MAX_SPEED);
|
|
13214
|
+
}
|
|
13215
|
+
return 0;
|
|
13216
|
+
};
|
|
13217
|
+
const stopAutoScroll = () => {
|
|
13218
|
+
if (autoScrollRAF !== null) {
|
|
13219
|
+
cancelAnimationFrame(autoScrollRAF);
|
|
13220
|
+
autoScrollRAF = null;
|
|
13221
|
+
}
|
|
13222
|
+
lastMoveEvent = null;
|
|
13223
|
+
};
|
|
13224
|
+
const autoScrollTick = () => {
|
|
13225
|
+
autoScrollRAF = null;
|
|
13226
|
+
if (!isSelecting || !lastMoveEvent) return;
|
|
13227
|
+
const canvas = getGridCanvas();
|
|
13228
|
+
const { x: x2, y } = getGridPosition(lastMoveEvent);
|
|
13229
|
+
const dx = computeEdgeSpeed(x2, canvas.width);
|
|
13230
|
+
const dy = computeEdgeSpeed(y, canvas.height);
|
|
13231
|
+
if (dx !== 0 || dy !== 0) {
|
|
13232
|
+
const maxOffsetX = getMaxOffsetX();
|
|
13233
|
+
const maxOffsetY = getMaxOffsetY();
|
|
13234
|
+
currentOffsetX = clamp3(currentOffsetX + dx, 0, maxOffsetX);
|
|
13235
|
+
currentOffsetY = clamp3(currentOffsetY + dy, 0, maxOffsetY);
|
|
13236
|
+
setDrawOffset(currentOffsetX, currentOffsetY);
|
|
13237
|
+
onPointerMove(lastMoveEvent);
|
|
13238
|
+
}
|
|
13239
|
+
if (isSelecting) {
|
|
13240
|
+
autoScrollRAF = requestAnimationFrame(autoScrollTick);
|
|
13241
|
+
}
|
|
13242
|
+
};
|
|
13243
|
+
const ensureAutoScroll = (event) => {
|
|
13244
|
+
lastMoveEvent = event;
|
|
13245
|
+
if (autoScrollRAF === null) {
|
|
13246
|
+
autoScrollRAF = requestAnimationFrame(autoScrollTick);
|
|
13247
|
+
}
|
|
13248
|
+
};
|
|
12962
13249
|
const playPreview = (pitch) => {
|
|
12963
13250
|
if (isLoading) return;
|
|
12964
13251
|
options.onResumeAudio?.();
|
|
12965
13252
|
const active = getActive();
|
|
12966
13253
|
dispatchNote(active.config.id, pitch, active.volume, 100, 0, 0.5);
|
|
12967
13254
|
};
|
|
12968
|
-
const findActiveNoteAt = (
|
|
13255
|
+
const findActiveNoteAt = (x2, y, margin = 0) => {
|
|
12969
13256
|
const active = getActive();
|
|
12970
13257
|
const { stepWidth, keyHeight, keyCount, pitchRangeStart } = renderConfig;
|
|
12971
13258
|
const offset = getDrawOffset();
|
|
@@ -12976,7 +13263,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
12976
13263
|
const w = note.durationSteps * stepWidth;
|
|
12977
13264
|
const renderX = logicalX - offset.x;
|
|
12978
13265
|
const renderY = logicalY - offset.y;
|
|
12979
|
-
if (
|
|
13266
|
+
if (x2 >= renderX - margin && x2 <= renderX + w + margin && y >= renderY - margin && y <= renderY + keyHeight + margin)
|
|
12980
13267
|
return note;
|
|
12981
13268
|
}
|
|
12982
13269
|
return null;
|
|
@@ -12995,17 +13282,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
12995
13282
|
const onGridPointerDown = (event) => {
|
|
12996
13283
|
event.preventDefault();
|
|
12997
13284
|
options.onResumeAudio?.();
|
|
12998
|
-
const { x, y, step, pitch } = getGridPosition(event);
|
|
13285
|
+
const { x: x2, y, step, pitch } = getGridPosition(event);
|
|
12999
13286
|
const active = getActive();
|
|
13000
13287
|
if (activeToolMode === "eraser") {
|
|
13001
13288
|
if (isActiveLocked()) return;
|
|
13002
|
-
const note = findActiveNoteAt(
|
|
13289
|
+
const note = findActiveNoteAt(x2, y);
|
|
13003
13290
|
if (note) active.core.deleteNoteById(note.id);
|
|
13004
13291
|
return;
|
|
13005
13292
|
}
|
|
13006
13293
|
if (activeToolMode === "select") {
|
|
13007
13294
|
if (selectedNotes.length > 0) {
|
|
13008
|
-
const clicked2 = findActiveNoteAt(
|
|
13295
|
+
const clicked2 = findActiveNoteAt(x2, y);
|
|
13009
13296
|
if (clicked2 && selectedNotes.some((n) => n.id === clicked2.id)) {
|
|
13010
13297
|
selectedOriginal = selectedNotes.map((n) => ({
|
|
13011
13298
|
id: n.id,
|
|
@@ -13014,7 +13301,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13014
13301
|
}));
|
|
13015
13302
|
isSelecting = true;
|
|
13016
13303
|
dragMode = "move";
|
|
13017
|
-
selectionStart = { x, y, step, pitch };
|
|
13304
|
+
selectionStart = { x: x2, y, step, pitch };
|
|
13018
13305
|
hasDragged = false;
|
|
13019
13306
|
lastMultiPreviewPitch = null;
|
|
13020
13307
|
return;
|
|
@@ -13022,7 +13309,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13022
13309
|
selectedNotes = [];
|
|
13023
13310
|
selectionRect = null;
|
|
13024
13311
|
}
|
|
13025
|
-
const clicked = findActiveNoteAt(
|
|
13312
|
+
const clicked = findActiveNoteAt(x2, y);
|
|
13026
13313
|
if (clicked) {
|
|
13027
13314
|
selectedNotes = [clicked];
|
|
13028
13315
|
selectedOriginal = [
|
|
@@ -13040,19 +13327,19 @@ var mountDAW = (target, options = {}) => {
|
|
|
13040
13327
|
isSelecting = true;
|
|
13041
13328
|
dragMode = "rect";
|
|
13042
13329
|
}
|
|
13043
|
-
selectionStart = { x, y, step, pitch };
|
|
13330
|
+
selectionStart = { x: x2, y, step, pitch };
|
|
13044
13331
|
hasDragged = false;
|
|
13045
13332
|
return;
|
|
13046
13333
|
}
|
|
13047
13334
|
hasDragged = false;
|
|
13048
|
-
const existing = findActiveNoteAt(
|
|
13335
|
+
const existing = findActiveNoteAt(x2, y, TOUCH_HIT_MARGIN);
|
|
13049
13336
|
if (existing) {
|
|
13050
13337
|
playPreview(existing.pitch);
|
|
13051
13338
|
const { stepWidth } = renderConfig;
|
|
13052
13339
|
const offset = getDrawOffset();
|
|
13053
13340
|
const renderX = existing.startStep * stepWidth - offset.x;
|
|
13054
13341
|
const w = existing.durationSteps * stepWidth;
|
|
13055
|
-
if (
|
|
13342
|
+
if (x2 >= renderX + w - resizeHandleWidth && x2 <= renderX + w) {
|
|
13056
13343
|
dragState = {
|
|
13057
13344
|
noteId: existing.id,
|
|
13058
13345
|
mode: "resize",
|
|
@@ -13131,12 +13418,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
13131
13418
|
return;
|
|
13132
13419
|
}
|
|
13133
13420
|
if (activeToolMode === "select" && isSelecting && selectionStart) {
|
|
13134
|
-
|
|
13421
|
+
ensureAutoScroll(event);
|
|
13422
|
+
const { x: x2, y, step, pitch } = getGridPosition(event);
|
|
13135
13423
|
if (dragMode === "rect") {
|
|
13136
13424
|
const rect = {
|
|
13137
|
-
x: Math.min(
|
|
13425
|
+
x: Math.min(x2, selectionStart.x),
|
|
13138
13426
|
y: Math.min(y, selectionStart.y),
|
|
13139
|
-
width: Math.abs(
|
|
13427
|
+
width: Math.abs(x2 - selectionStart.x),
|
|
13140
13428
|
height: Math.abs(y - selectionStart.y)
|
|
13141
13429
|
};
|
|
13142
13430
|
selectionRect = rect;
|
|
@@ -13149,7 +13437,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13149
13437
|
const nx = logicalX - offset.x;
|
|
13150
13438
|
const ny = logicalY - offset.y;
|
|
13151
13439
|
const nw = note.durationSteps * stepWidth;
|
|
13152
|
-
return rect.x
|
|
13440
|
+
return nx >= rect.x && nx + nw <= rect.x + rect.width && ny >= rect.y && ny + keyHeight <= rect.y + rect.height;
|
|
13153
13441
|
});
|
|
13154
13442
|
redrawAll();
|
|
13155
13443
|
} else {
|
|
@@ -13206,8 +13494,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
13206
13494
|
selectionStart = null;
|
|
13207
13495
|
hasDragged = false;
|
|
13208
13496
|
lastMultiPreviewPitch = null;
|
|
13209
|
-
|
|
13497
|
+
if (dragMode !== "rect" || selectedNotes.length === 0) {
|
|
13498
|
+
selectionRect = null;
|
|
13499
|
+
}
|
|
13210
13500
|
selectedOriginal = [];
|
|
13501
|
+
stopAutoScroll();
|
|
13211
13502
|
redrawAll();
|
|
13212
13503
|
}
|
|
13213
13504
|
};
|
|
@@ -13355,8 +13646,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
13355
13646
|
headerCanvas.addEventListener("click", (event) => {
|
|
13356
13647
|
if (playbackState === "playing") return;
|
|
13357
13648
|
const rect = headerCanvas.getBoundingClientRect();
|
|
13358
|
-
const
|
|
13359
|
-
const step = Math.floor((
|
|
13649
|
+
const x2 = event.clientX - rect.left;
|
|
13650
|
+
const step = Math.floor((x2 + currentOffsetX) / renderConfig.stepWidth);
|
|
13360
13651
|
playStartStep = Math.max(
|
|
13361
13652
|
0,
|
|
13362
13653
|
Math.floor(step / snapGridSteps) * snapGridSteps
|
|
@@ -13477,11 +13768,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
13477
13768
|
const semis = (lt.octave ?? 0) * 12;
|
|
13478
13769
|
const count = Math.min(sorted.length, lt.syllables.length);
|
|
13479
13770
|
const notes = [];
|
|
13480
|
-
for (let
|
|
13481
|
-
const n = sorted[
|
|
13771
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
13772
|
+
const n = sorted[i2];
|
|
13482
13773
|
if (n.startStep < fromStep) continue;
|
|
13483
13774
|
notes.push({
|
|
13484
|
-
syllable: lt.syllables[
|
|
13775
|
+
syllable: lt.syllables[i2],
|
|
13485
13776
|
pitch: n.pitch + semis,
|
|
13486
13777
|
startSec: (n.startStep - fromStep) * secondsPerStep,
|
|
13487
13778
|
durationSec: n.durationSteps * secondsPerStep * gate
|
|
@@ -13492,6 +13783,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
13492
13783
|
model: lt.model,
|
|
13493
13784
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
13494
13785
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
13786
|
+
vibrato: lt.vibrato,
|
|
13787
|
+
reverbSend: (lt.reverb ?? 0) / 100,
|
|
13495
13788
|
notes
|
|
13496
13789
|
};
|
|
13497
13790
|
}) : [];
|
|
@@ -13580,13 +13873,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
13580
13873
|
const updateTrackPanel = () => {
|
|
13581
13874
|
refs.trackTabs.innerHTML = "";
|
|
13582
13875
|
trackPillEls.clear();
|
|
13583
|
-
for (const [
|
|
13876
|
+
for (const [i2, t] of trackStates.entries()) {
|
|
13584
13877
|
const [r, g, b] = t.config.color;
|
|
13585
13878
|
const btn = document.createElement("button");
|
|
13586
13879
|
btn.className = `dtm-pill ${t.config.id === activeTrackId ? "dtm-pill--active" : ""}`;
|
|
13587
13880
|
btn.style.setProperty("--dtm-pill-color", `rgb(${r},${g},${b})`);
|
|
13588
13881
|
btn.title = t.config.name;
|
|
13589
|
-
btn.textContent = String(
|
|
13882
|
+
btn.textContent = String(i2 + 1);
|
|
13590
13883
|
btn.addEventListener("click", () => switchTrack(t.config.id));
|
|
13591
13884
|
refs.trackTabs.appendChild(btn);
|
|
13592
13885
|
trackPillEls.set(t.config.id, btn);
|
|
@@ -13684,6 +13977,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
13684
13977
|
<option value="-1">-1 oct</option>
|
|
13685
13978
|
<option value="-2">-2 oct</option>
|
|
13686
13979
|
</select>
|
|
13980
|
+
<label class="dtm-label" style="display:inline-flex;align-items:center;gap:2px;white-space:nowrap" title="\u30ED\u30F3\u30B0\u30C8\u30FC\u30F3\u306B\u81EA\u52D5\u3067\u30D3\u30D6\u30E9\u30FC\u30C8\u3092\u639B\u3051\u307E\u3059">
|
|
13981
|
+
<input type="checkbox" data-dtm="lyric-vibrato" aria-label="\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8">\u30D3\u30D6\u30E9\u30FC\u30C8
|
|
13982
|
+
</label>
|
|
13983
|
+
<button class="dtm-infobtn" data-dtm="lyric-vibrato-info" title="\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
13687
13984
|
<span class="dtm-label dtm-grow" data-dtm="lyric-count" style="text-align:right"></span>
|
|
13688
13985
|
</div>
|
|
13689
13986
|
<div class="dtm-row dtm-hidden" data-dtm="lyric-terms" style="font-size:10px;gap:4px;color:var(--dtm-warn)">
|
|
@@ -13714,6 +14011,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
13714
14011
|
<input type="range" class="dtm-range dtm-grow" data-dtm="lyric-pan" min="0" max="127" aria-label="\u6B4C\u5531\u306E\u30B9\u30C6\u30EC\u30AA\u5B9A\u4F4D\uFF08\u5DE6\u53F3\uFF09">
|
|
13715
14012
|
<span class="dtm-label" data-dtm="lyric-pan-label"></span>
|
|
13716
14013
|
</div>
|
|
14014
|
+
<div class="dtm-row">
|
|
14015
|
+
<span class="dtm-label">\u30EA\u30D0\u30FC\u30D6\u9001\u308A</span>
|
|
14016
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="lyric-reverb" min="0" max="100" aria-label="\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u304B\u3089\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\u3078\u9001\u308B\u91CF\uFF08\u30DE\u30B9\u30BF\u306E\u30EA\u30D0\u30FC\u30D6\u3064\u307E\u307F\u304C0%\u3060\u3068\u7121\u97F3\uFF09" title="\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\u3078\u306E\u30BB\u30F3\u30C9\u91CF">
|
|
14017
|
+
<span class="dtm-label" data-dtm="lyric-reverb-label"></span>
|
|
14018
|
+
</div>
|
|
13717
14019
|
<textarea class="dtm-textarea" data-dtm="lyric-input" rows="2" placeholder="\u3072\u3089\u304C\u306A\u30FB\u30AB\u30BF\u30AB\u30CA\u3067\u6B4C\u8A5E\uFF08\u4F8B: \u3069\u308C\u307F\u3075\u3041\u305D\u3089\u3057\u3069\uFF09"></textarea>
|
|
13718
14020
|
</div>`;
|
|
13719
14021
|
refs.trackBody.appendChild(lyricDiv);
|
|
@@ -13747,6 +14049,21 @@ var mountDAW = (target, options = {}) => {
|
|
|
13747
14049
|
const lyricPanLabel = lyricDiv.querySelector(
|
|
13748
14050
|
'[data-dtm="lyric-pan-label"]'
|
|
13749
14051
|
);
|
|
14052
|
+
const lyricReverb = lyricDiv.querySelector(
|
|
14053
|
+
'[data-dtm="lyric-reverb"]'
|
|
14054
|
+
);
|
|
14055
|
+
const lyricReverbLabel = lyricDiv.querySelector(
|
|
14056
|
+
'[data-dtm="lyric-reverb-label"]'
|
|
14057
|
+
);
|
|
14058
|
+
const lyricVibrato = lyricDiv.querySelector(
|
|
14059
|
+
'[data-dtm="lyric-vibrato"]'
|
|
14060
|
+
);
|
|
14061
|
+
const lyricVibratoInfo = lyricDiv.querySelector(
|
|
14062
|
+
'[data-dtm="lyric-vibrato-info"]'
|
|
14063
|
+
);
|
|
14064
|
+
lyricVibratoInfo.addEventListener("click", () => {
|
|
14065
|
+
showModal("\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u89E3\u8AAC", VIBRATO_INFO_HTML);
|
|
14066
|
+
});
|
|
13750
14067
|
const lyricTerms = lyricDiv.querySelector(
|
|
13751
14068
|
'[data-dtm="lyric-terms"]'
|
|
13752
14069
|
);
|
|
@@ -13808,6 +14125,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
13808
14125
|
lyricVolLabel.textContent = String(active.vocalVolume);
|
|
13809
14126
|
lyricPan.value = String(active.vocalPan);
|
|
13810
14127
|
lyricPanLabel.textContent = fmtPan(active.vocalPan);
|
|
14128
|
+
lyricReverb.value = String(active.vocalReverb);
|
|
14129
|
+
lyricReverbLabel.textContent = `${active.vocalReverb}%`;
|
|
14130
|
+
lyricVibrato.checked = active.vocalVibrato;
|
|
13811
14131
|
const updateLyricCount = () => {
|
|
13812
14132
|
const n = normalizeLyrics(lyricInput.value).length;
|
|
13813
14133
|
lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
|
|
@@ -13926,6 +14246,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
13926
14246
|
active.vocalOctave = Number.parseInt(lyricOctaveSel.value, 10);
|
|
13927
14247
|
fireLyricsChange(active);
|
|
13928
14248
|
});
|
|
14249
|
+
lyricVibrato.addEventListener("change", () => {
|
|
14250
|
+
active.vocalVibrato = lyricVibrato.checked;
|
|
14251
|
+
fireLyricsChange(active);
|
|
14252
|
+
});
|
|
13929
14253
|
lyricInput.addEventListener("input", () => {
|
|
13930
14254
|
active.lyrics = lyricInput.value;
|
|
13931
14255
|
updateLyricCount();
|
|
@@ -13949,6 +14273,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
13949
14273
|
lyricPanLabel.textContent = fmtPan(64);
|
|
13950
14274
|
fireLyricsChange(active);
|
|
13951
14275
|
});
|
|
14276
|
+
lyricReverb.addEventListener("input", () => {
|
|
14277
|
+
active.vocalReverb = Number.parseInt(lyricReverb.value, 10);
|
|
14278
|
+
lyricReverbLabel.textContent = `${active.vocalReverb}%`;
|
|
14279
|
+
fireLyricsChange(active);
|
|
14280
|
+
});
|
|
13952
14281
|
}
|
|
13953
14282
|
if (active.config.id === "chord" && showChord) {
|
|
13954
14283
|
const div = document.createElement("div");
|
|
@@ -14032,8 +14361,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14032
14361
|
const limitSteps = barLimitBars > 0 ? barLimitBars * renderConfig.stepsPerBar : Infinity;
|
|
14033
14362
|
const clipNotes = (notes) => limitSteps === Infinity ? notes : notes.filter((n) => n.startStep < limitSteps);
|
|
14034
14363
|
const trackInstrumentsForMeta = {};
|
|
14035
|
-
trackStates.forEach((t,
|
|
14036
|
-
if (t.trackInstrument) trackInstrumentsForMeta[
|
|
14364
|
+
trackStates.forEach((t, i2) => {
|
|
14365
|
+
if (t.trackInstrument) trackInstrumentsForMeta[i2] = t.trackInstrument;
|
|
14037
14366
|
});
|
|
14038
14367
|
const trackInstMeta = Object.keys(trackInstrumentsForMeta).length > 0 ? trackInstrumentsForMeta : void 0;
|
|
14039
14368
|
const metaLineFull = formatMmlMeta(
|
|
@@ -14068,10 +14397,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14068
14397
|
const monoTracks = decomposeToMonophonic(allNotes);
|
|
14069
14398
|
const refCore = trackStates[0].core;
|
|
14070
14399
|
const decomposedFull = monoTracks.map(
|
|
14071
|
-
(notes,
|
|
14400
|
+
(notes, i2) => `@${i2} ${refCore.getMMLFromNotes(notes, bpm, 100).trim()}`
|
|
14072
14401
|
);
|
|
14073
14402
|
const decomposedMini = monoTracks.map(
|
|
14074
|
-
(notes,
|
|
14403
|
+
(notes, i2) => `@${i2}${refCore.getMMLFromNotes(notes, bpm, 100).trim().replace(/\s+/g, "")}`
|
|
14075
14404
|
);
|
|
14076
14405
|
const full2 = [metaLineFull, ...decomposedFull, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
|
|
14077
14406
|
const minified2 = [metaLineMini, ...decomposedMini, MML_END_MARKER].filter((s) => s.length > 0).join(";");
|
|
@@ -14085,34 +14414,38 @@ var mountDAW = (target, options = {}) => {
|
|
|
14085
14414
|
}
|
|
14086
14415
|
const trackLines = [];
|
|
14087
14416
|
const trackLinesMini = [];
|
|
14088
|
-
trackStates.forEach((t,
|
|
14417
|
+
trackStates.forEach((t, i2) => {
|
|
14089
14418
|
const notes = clipNotes(t.core.getNotes());
|
|
14090
14419
|
if (notes.length > 0) {
|
|
14091
14420
|
const mml = t.core.getMMLFromNotes(notes, bpm, t.volume).trim();
|
|
14092
|
-
trackLines.push(`@${
|
|
14093
|
-
trackLinesMini.push(`@${
|
|
14421
|
+
trackLines.push(`@${i2} ${mml}`);
|
|
14422
|
+
trackLinesMini.push(`@${i2}${mml.replace(/\s+/g, "")}`);
|
|
14094
14423
|
}
|
|
14095
14424
|
});
|
|
14096
|
-
const lyricLines = trackStates.map((t,
|
|
14097
|
-
i,
|
|
14425
|
+
const lyricLines = trackStates.map((t, i2) => ({
|
|
14426
|
+
i: i2,
|
|
14098
14427
|
notes: clipNotes(t.core.getNotes()),
|
|
14099
14428
|
text: t.lyrics.replace(/[\r\n]+/g, " ").trim(),
|
|
14100
14429
|
model: t.lyricModel.trim(),
|
|
14101
14430
|
vol: t.vocalVolume,
|
|
14102
14431
|
gate: t.vocalGate,
|
|
14103
14432
|
pan: t.vocalPan,
|
|
14104
|
-
oct: t.vocalOctave
|
|
14433
|
+
oct: t.vocalOctave,
|
|
14434
|
+
vib: t.vocalVibrato,
|
|
14435
|
+
rev: t.vocalReverb
|
|
14105
14436
|
})).filter(
|
|
14106
|
-
(
|
|
14107
|
-
).map((
|
|
14437
|
+
(x2) => x2.model.length > 0 && x2.text.length > 0 && x2.notes.length > 0
|
|
14438
|
+
).map((x2) => {
|
|
14108
14439
|
const params = [
|
|
14109
|
-
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14440
|
+
x2.vol === DEFAULT_VOCAL_VOLUME ? "" : `v${x2.vol}`,
|
|
14441
|
+
x2.gate === 100 ? "" : `q${x2.gate}`,
|
|
14442
|
+
x2.pan === 64 ? "" : `p${x2.pan}`,
|
|
14443
|
+
x2.oct === 0 ? "" : `o${x2.oct}`,
|
|
14444
|
+
x2.vib ? "b1" : "",
|
|
14445
|
+
x2.rev === 0 ? "" : `r${x2.rev}`
|
|
14113
14446
|
].filter((s) => s.length > 0).join(" ");
|
|
14114
|
-
const head = params ? `${
|
|
14115
|
-
return `@@${
|
|
14447
|
+
const head = params ? `${x2.model} ${params}` : x2.model;
|
|
14448
|
+
return `@@${x2.i} ${head} ${x2.text}`;
|
|
14116
14449
|
});
|
|
14117
14450
|
const customVocalDecls = [];
|
|
14118
14451
|
for (const [key, def] of customVocalsMap) {
|
|
@@ -14250,17 +14583,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
14250
14583
|
refs.drumVolumeLabel.textContent = `${drumVolume}%`;
|
|
14251
14584
|
}
|
|
14252
14585
|
}
|
|
14253
|
-
trackStates.forEach((t,
|
|
14254
|
-
if (applyActiveOnly &&
|
|
14255
|
-
const name = normalizeInstrumentName(meta.trackInstruments?.[
|
|
14586
|
+
trackStates.forEach((t, i2) => {
|
|
14587
|
+
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
14588
|
+
const name = normalizeInstrumentName(meta.trackInstruments?.[i2] ?? "");
|
|
14256
14589
|
if (t.trackInstrument !== name) {
|
|
14257
14590
|
t.trackInstrument = name;
|
|
14258
|
-
options.onTrackInstrumentChange?.(
|
|
14591
|
+
options.onTrackInstrumentChange?.(i2, name);
|
|
14259
14592
|
}
|
|
14260
14593
|
});
|
|
14261
|
-
trackStates.forEach((t,
|
|
14262
|
-
if (applyActiveOnly &&
|
|
14263
|
-
const v = trackVelocity.get(
|
|
14594
|
+
trackStates.forEach((t, i2) => {
|
|
14595
|
+
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
14596
|
+
const v = trackVelocity.get(i2);
|
|
14264
14597
|
if (v !== void 0 && v !== t.volume) {
|
|
14265
14598
|
t.volume = v;
|
|
14266
14599
|
t.core.setVolume(v);
|
|
@@ -14274,6 +14607,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14274
14607
|
active.vocalGate = 100;
|
|
14275
14608
|
active.vocalPan = 64;
|
|
14276
14609
|
active.vocalOctave = 0;
|
|
14610
|
+
active.vocalVibrato = false;
|
|
14611
|
+
active.vocalReverb = 0;
|
|
14277
14612
|
} else {
|
|
14278
14613
|
for (const t of trackStates) {
|
|
14279
14614
|
t.lyrics = "";
|
|
@@ -14282,6 +14617,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14282
14617
|
t.vocalGate = 100;
|
|
14283
14618
|
t.vocalPan = 64;
|
|
14284
14619
|
t.vocalOctave = 0;
|
|
14620
|
+
t.vocalVibrato = false;
|
|
14621
|
+
t.vocalReverb = 0;
|
|
14285
14622
|
}
|
|
14286
14623
|
}
|
|
14287
14624
|
lyrics?.forEach((lt) => {
|
|
@@ -14294,6 +14631,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14294
14631
|
t.vocalGate = lt.gate;
|
|
14295
14632
|
t.vocalPan = lt.pan;
|
|
14296
14633
|
t.vocalOctave = lt.octave ?? 0;
|
|
14634
|
+
t.vocalVibrato = lt.vibrato ?? false;
|
|
14635
|
+
t.vocalReverb = lt.reverb ?? 0;
|
|
14297
14636
|
});
|
|
14298
14637
|
for (const p of placements) {
|
|
14299
14638
|
if (applyActiveOnly && p.trackIndex !== activeTrackIndex) continue;
|
|
@@ -14372,6 +14711,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14372
14711
|
active.vocalGate = 100;
|
|
14373
14712
|
active.vocalPan = 64;
|
|
14374
14713
|
active.vocalOctave = 0;
|
|
14714
|
+
active.vocalVibrato = false;
|
|
14715
|
+
active.vocalReverb = 0;
|
|
14375
14716
|
} else {
|
|
14376
14717
|
clearAll();
|
|
14377
14718
|
for (const t of trackStates) t.core.setLoadMode(true);
|
|
@@ -14382,6 +14723,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14382
14723
|
t.vocalGate = 100;
|
|
14383
14724
|
t.vocalPan = 64;
|
|
14384
14725
|
t.vocalOctave = 0;
|
|
14726
|
+
t.vocalVibrato = false;
|
|
14727
|
+
t.vocalReverb = 0;
|
|
14385
14728
|
}
|
|
14386
14729
|
}
|
|
14387
14730
|
const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
|
|
@@ -14591,6 +14934,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
14591
14934
|
refs.masterVolumeLabel.textContent = `${masterVolume}%`;
|
|
14592
14935
|
options.singingVoices?.setVolume(masterVolume / 100);
|
|
14593
14936
|
});
|
|
14937
|
+
refs.reverbAmount.addEventListener("input", () => {
|
|
14938
|
+
reverbAmount = Number.parseInt(refs.reverbAmount.value, 10) || 0;
|
|
14939
|
+
refs.reverbAmountLabel.textContent = `${reverbAmount}%`;
|
|
14940
|
+
options.onReverbChange?.(reverbAmount);
|
|
14941
|
+
});
|
|
14594
14942
|
refs.drumSelect.addEventListener("change", () => {
|
|
14595
14943
|
currentDrumPattern = refs.drumSelect.value;
|
|
14596
14944
|
options.onDrumChange?.(currentDrumPattern);
|
|
@@ -14871,7 +15219,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
14871
15219
|
console.error(e);
|
|
14872
15220
|
}
|
|
14873
15221
|
refs.midiTrackSelection.innerHTML = `<span class="dtm-label">\u30C8\u30E9\u30C3\u30AF</span>`;
|
|
14874
|
-
detectedTracks.forEach((t,
|
|
15222
|
+
detectedTracks.forEach((t, i2) => {
|
|
14875
15223
|
const btn = document.createElement("button");
|
|
14876
15224
|
btn.className = `dtm-btn ${t.selected ? "dtm-btn--primary" : "dtm-btn--ghost"}`;
|
|
14877
15225
|
btn.dataset.selected = String(t.selected);
|
|
@@ -14883,7 +15231,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
14883
15231
|
btn.classList.toggle("dtm-btn--ghost", !on);
|
|
14884
15232
|
});
|
|
14885
15233
|
refs.midiTrackSelection.appendChild(btn);
|
|
14886
|
-
if (
|
|
15234
|
+
if (i2 === 0) refs.midiTrackSelection.dataset.ready = "1";
|
|
14887
15235
|
});
|
|
14888
15236
|
refs.midiTrackSelection.classList.remove("dtm-hidden");
|
|
14889
15237
|
refs.overlay.hidden = true;
|
|
@@ -14893,9 +15241,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
14893
15241
|
if (!pendingMidi) return;
|
|
14894
15242
|
const selected = [];
|
|
14895
15243
|
const btns = refs.midiTrackSelection.querySelectorAll("button");
|
|
14896
|
-
btns.forEach((b,
|
|
15244
|
+
btns.forEach((b, i2) => {
|
|
14897
15245
|
if (b.dataset.selected === "true")
|
|
14898
|
-
selected.push(detectedTracks[
|
|
15246
|
+
selected.push(detectedTracks[i2].index);
|
|
14899
15247
|
});
|
|
14900
15248
|
if (selected.length === 0) return;
|
|
14901
15249
|
if (!isAdvanced && options.onRequestAdvancedMode && selected.length > trackStates.length) {
|
|
@@ -14929,7 +15277,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
14929
15277
|
const refCore = trackStates[0].core;
|
|
14930
15278
|
const tempo = Math.round(parsedBpm) || bpm;
|
|
14931
15279
|
const lines = [];
|
|
14932
|
-
let
|
|
15280
|
+
let i2 = 0;
|
|
14933
15281
|
for (const notes of byTrack.values()) {
|
|
14934
15282
|
const asNotes = notes.map((p) => ({
|
|
14935
15283
|
id: 0,
|
|
@@ -14939,8 +15287,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
14939
15287
|
velocity: p.velocity
|
|
14940
15288
|
}));
|
|
14941
15289
|
const mml = refCore.getMMLFromNotes(asNotes, tempo, 100).trim();
|
|
14942
|
-
lines.push(`@${
|
|
14943
|
-
|
|
15290
|
+
lines.push(`@${i2} ${mml}`);
|
|
15291
|
+
i2++;
|
|
14944
15292
|
}
|
|
14945
15293
|
return [...lines, MML_END_MARKER].join(";\n");
|
|
14946
15294
|
};
|
|
@@ -15555,6 +15903,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
15555
15903
|
refs.drumVolume.value = String(drumVolume);
|
|
15556
15904
|
refs.drumVolumeLabel.textContent = `${drumVolume}%`;
|
|
15557
15905
|
},
|
|
15906
|
+
setReverbAmount: (amount) => {
|
|
15907
|
+
reverbAmount = clamp3(amount, 0, 100);
|
|
15908
|
+
refs.reverbAmount.value = String(reverbAmount);
|
|
15909
|
+
refs.reverbAmountLabel.textContent = `${reverbAmount}%`;
|
|
15910
|
+
options.onReverbChange?.(reverbAmount);
|
|
15911
|
+
},
|
|
15558
15912
|
applyPatch: (trackId, added, removed) => {
|
|
15559
15913
|
const track = trackStates.find((t) => t.config.id === trackId);
|
|
15560
15914
|
if (!track) return;
|
|
@@ -15594,6 +15948,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
15594
15948
|
t.vocalGate = data.vocalGate;
|
|
15595
15949
|
t.vocalPan = data.vocalPan;
|
|
15596
15950
|
t.vocalOctave = data.vocalOctave;
|
|
15951
|
+
t.vocalVibrato = data.vocalVibrato ?? false;
|
|
15952
|
+
t.vocalReverb = data.vocalReverb ?? 0;
|
|
15597
15953
|
},
|
|
15598
15954
|
applyTrackInstrument: (trackIndex, instrumentName) => {
|
|
15599
15955
|
const t = trackStates[trackIndex];
|
|
@@ -15604,17 +15960,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
15604
15960
|
},
|
|
15605
15961
|
noteToCanvas: (step, pitch) => {
|
|
15606
15962
|
const canvas = getGridCanvas();
|
|
15607
|
-
const
|
|
15963
|
+
const x2 = step * renderConfig.stepWidth - currentOffsetX;
|
|
15608
15964
|
const y = (renderConfig.keyCount - 1 - pitch) * renderConfig.keyHeight - currentOffsetY;
|
|
15609
|
-
const onScreen =
|
|
15965
|
+
const onScreen = x2 >= 0 && x2 <= canvas.width && y >= 0 && y <= canvas.height;
|
|
15610
15966
|
let side = null;
|
|
15611
15967
|
if (!onScreen) {
|
|
15612
|
-
if (
|
|
15613
|
-
else if (
|
|
15968
|
+
if (x2 < 0) side = "left";
|
|
15969
|
+
else if (x2 > canvas.width) side = "right";
|
|
15614
15970
|
else if (y < 0) side = "top";
|
|
15615
15971
|
else side = "bottom";
|
|
15616
15972
|
}
|
|
15617
|
-
return { x, y, onScreen, side };
|
|
15973
|
+
return { x: x2, y, onScreen, side };
|
|
15618
15974
|
},
|
|
15619
15975
|
destroy: () => {
|
|
15620
15976
|
sequencer.stop();
|
|
@@ -15694,11 +16050,11 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
15694
16050
|
const semis = (lt.octave ?? 0) * 12;
|
|
15695
16051
|
const count = Math.min(sorted.length, lt.syllables.length);
|
|
15696
16052
|
const notes = [];
|
|
15697
|
-
for (let
|
|
15698
|
-
const n = sorted[
|
|
16053
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
16054
|
+
const n = sorted[i2];
|
|
15699
16055
|
if (n.startStep < fromStep) continue;
|
|
15700
16056
|
notes.push({
|
|
15701
|
-
syllable: lt.syllables[
|
|
16057
|
+
syllable: lt.syllables[i2],
|
|
15702
16058
|
pitch: n.pitch + semis,
|
|
15703
16059
|
startSec: (n.startStep - fromStep) * secondsPerStep,
|
|
15704
16060
|
durationSec: n.durationSteps * secondsPerStep * gate
|
|
@@ -15709,6 +16065,8 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
15709
16065
|
model: lt.model,
|
|
15710
16066
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
15711
16067
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
16068
|
+
vibrato: lt.vibrato,
|
|
16069
|
+
reverbSend: (lt.reverb ?? 0) / 100,
|
|
15712
16070
|
notes
|
|
15713
16071
|
};
|
|
15714
16072
|
});
|
|
@@ -15923,7 +16281,7 @@ var createPianoRoll = (options, handlers) => {
|
|
|
15923
16281
|
let dragState = null;
|
|
15924
16282
|
let hasDragged = false;
|
|
15925
16283
|
let lastPreviewPitch = null;
|
|
15926
|
-
const findNoteAtPosition = (
|
|
16284
|
+
const findNoteAtPosition = (x2, y) => {
|
|
15927
16285
|
const { stepWidth, keyHeight, keyCount, pitchRangeStart } = getRenderConfig();
|
|
15928
16286
|
const offset = getDrawOffset();
|
|
15929
16287
|
for (const note of core.getNotes()) {
|
|
@@ -15934,7 +16292,7 @@ var createPianoRoll = (options, handlers) => {
|
|
|
15934
16292
|
const h = keyHeight;
|
|
15935
16293
|
const renderX = logicalX - offset.x;
|
|
15936
16294
|
const renderY = logicalY - offset.y;
|
|
15937
|
-
if (
|
|
16295
|
+
if (x2 >= renderX && x2 <= renderX + w && y >= renderY && y <= renderY + h) {
|
|
15938
16296
|
return note;
|
|
15939
16297
|
}
|
|
15940
16298
|
}
|
|
@@ -15942,10 +16300,10 @@ var createPianoRoll = (options, handlers) => {
|
|
|
15942
16300
|
};
|
|
15943
16301
|
const handlePointerMove = (e) => {
|
|
15944
16302
|
if (core.getToolMode() === "select" && isSelecting && selectionStart) {
|
|
15945
|
-
const { x, y } = getGridPosition(e);
|
|
15946
|
-
const minX = Math.min(
|
|
16303
|
+
const { x: x2, y } = getGridPosition(e);
|
|
16304
|
+
const minX = Math.min(x2, selectionStart.x);
|
|
15947
16305
|
const minY = Math.min(y, selectionStart.y);
|
|
15948
|
-
const width2 = Math.abs(
|
|
16306
|
+
const width2 = Math.abs(x2 - selectionStart.x);
|
|
15949
16307
|
const height2 = Math.abs(y - selectionStart.y);
|
|
15950
16308
|
selectionRect = { x: minX, y: minY, width: width2, height: height2 };
|
|
15951
16309
|
selectedNotes = getNotesInRect(selectionRect);
|
|
@@ -16003,10 +16361,10 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16003
16361
|
}
|
|
16004
16362
|
};
|
|
16005
16363
|
gridCanvas.addEventListener("pointerdown", (e) => {
|
|
16006
|
-
const { x, y, step, pitch } = getGridPosition(e);
|
|
16364
|
+
const { x: x2, y, step, pitch } = getGridPosition(e);
|
|
16007
16365
|
const currentMode = core.getToolMode();
|
|
16008
16366
|
if (currentMode === "select") {
|
|
16009
|
-
const clickedNote = findNoteAtPosition(
|
|
16367
|
+
const clickedNote = findNoteAtPosition(x2, y);
|
|
16010
16368
|
if (selectionRect && clickedNote) {
|
|
16011
16369
|
const notesInRect = getNotesInRect(selectionRect);
|
|
16012
16370
|
if (notesInRect.some((n) => n.id === clickedNote.id)) {
|
|
@@ -16027,10 +16385,10 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16027
16385
|
selectedNotes = [];
|
|
16028
16386
|
selectionRect = null;
|
|
16029
16387
|
isSelecting = true;
|
|
16030
|
-
selectionStart = { x, y, step, pitch };
|
|
16388
|
+
selectionStart = { x: x2, y, step, pitch };
|
|
16031
16389
|
return;
|
|
16032
16390
|
}
|
|
16033
|
-
const note = findNoteAtPosition(
|
|
16391
|
+
const note = findNoteAtPosition(x2, y);
|
|
16034
16392
|
if (!note) return;
|
|
16035
16393
|
const { stepWidth, keyHeight, keyCount, pitchRangeStart } = getRenderConfig();
|
|
16036
16394
|
const offset = getDrawOffset();
|
|
@@ -16040,7 +16398,7 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16040
16398
|
const renderX = logicalX - offset.x;
|
|
16041
16399
|
const renderY = logicalY - offset.y;
|
|
16042
16400
|
const w = note.durationSteps * stepWidth;
|
|
16043
|
-
if (
|
|
16401
|
+
if (x2 >= renderX + w - resizeHandleWidth && x2 <= renderX + w && y >= renderY && y <= renderY + keyHeight) {
|
|
16044
16402
|
dragState = {
|
|
16045
16403
|
noteId: note.id,
|
|
16046
16404
|
mode: "resize",
|
|
@@ -16316,6 +16674,25 @@ var isSupported = midiJsonParser.isSupported;
|
|
|
16316
16674
|
var parseArrayBuffer = midiJsonParser.parseArrayBuffer;
|
|
16317
16675
|
URL.revokeObjectURL(url);
|
|
16318
16676
|
|
|
16677
|
+
// src/reverb.ts
|
|
16678
|
+
var IMPULSE_DURATION_SEC = 2.2;
|
|
16679
|
+
var IMPULSE_DECAY = 2.5;
|
|
16680
|
+
var createReverbImpulse = (ctx) => {
|
|
16681
|
+
const rate = ctx.sampleRate;
|
|
16682
|
+
const length = Math.max(1, Math.floor(rate * IMPULSE_DURATION_SEC));
|
|
16683
|
+
const impulse = ctx.createBuffer(2, length, rate);
|
|
16684
|
+
for (let ch = 0; ch < impulse.numberOfChannels; ch++) {
|
|
16685
|
+
const data = impulse.getChannelData(ch);
|
|
16686
|
+
for (let i2 = 0; i2 < length; i2++) {
|
|
16687
|
+
const envelope = (1 - i2 / length) ** IMPULSE_DECAY;
|
|
16688
|
+
data[i2] = (Math.random() * 2 - 1) * envelope;
|
|
16689
|
+
}
|
|
16690
|
+
}
|
|
16691
|
+
return impulse;
|
|
16692
|
+
};
|
|
16693
|
+
var REVERB_MAX_WET = 0.6;
|
|
16694
|
+
var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100 * REVERB_MAX_WET;
|
|
16695
|
+
|
|
16319
16696
|
// src/sf/SoundFont_drum.ts
|
|
16320
16697
|
var touch = (map, key, ctor) => {
|
|
16321
16698
|
if (!map.has(key)) map.set(key, new ctor());
|
|
@@ -16471,6 +16848,21 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16471
16848
|
const drumGain = audioCtx.createGain();
|
|
16472
16849
|
drumGain.gain.value = options.drumVolume ?? 1;
|
|
16473
16850
|
drumGain.connect(masterGain);
|
|
16851
|
+
const reverbConvolver = audioCtx.createConvolver();
|
|
16852
|
+
reverbConvolver.buffer = createReverbImpulse(audioCtx);
|
|
16853
|
+
reverbConvolver.normalize = true;
|
|
16854
|
+
const reverbWetGain = audioCtx.createGain();
|
|
16855
|
+
reverbWetGain.gain.value = reverbAmountToGain(options.reverbAmount ?? 0);
|
|
16856
|
+
masterGain.connect(reverbConvolver);
|
|
16857
|
+
reverbConvolver.connect(reverbWetGain);
|
|
16858
|
+
reverbWetGain.connect(audioCtx.destination);
|
|
16859
|
+
const setReverbAmount = (amount) => {
|
|
16860
|
+
reverbWetGain.gain.setTargetAtTime(
|
|
16861
|
+
reverbAmountToGain(amount),
|
|
16862
|
+
audioCtx.currentTime,
|
|
16863
|
+
0.02
|
|
16864
|
+
);
|
|
16865
|
+
};
|
|
16474
16866
|
const resumeAudio = () => {
|
|
16475
16867
|
if (audioCtx.state === "closed") return Promise.resolve();
|
|
16476
16868
|
return audioCtx.resume();
|
|
@@ -16501,7 +16893,10 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16501
16893
|
const singingVoices = createSingingVoices(audioCtx, masterGain, {
|
|
16502
16894
|
voiceWorkerUrl,
|
|
16503
16895
|
voicebanks,
|
|
16504
|
-
worldlineScriptUrl: options.worldlineScriptUrl
|
|
16896
|
+
worldlineScriptUrl: options.worldlineScriptUrl,
|
|
16897
|
+
// ボーカルトラック個別のリバーブセンド(`r`トークン)先。マスタリバーブの
|
|
16898
|
+
// Convolver 入力へ直接センドする(masterGain 経由のドライ段は素通り)。
|
|
16899
|
+
reverbBus: reverbConvolver
|
|
16505
16900
|
});
|
|
16506
16901
|
const listReady = new Promise((resolve) => {
|
|
16507
16902
|
sfList.init();
|
|
@@ -16776,6 +17171,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16776
17171
|
void handleTrackInstrumentChange(idx, name);
|
|
16777
17172
|
externalOnTrackInstrumentChange?.(idx, name);
|
|
16778
17173
|
},
|
|
17174
|
+
reverbAmount: options.reverbAmount,
|
|
17175
|
+
onReverbChange: setReverbAmount,
|
|
16779
17176
|
...dawOverrides,
|
|
16780
17177
|
// dawOverrides で上書きされないよう、スプレッドの後に配置して合成する
|
|
16781
17178
|
onDrumChange: (name) => {
|
|
@@ -16833,8 +17230,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16833
17230
|
presetSelect?.destroy();
|
|
16834
17231
|
if (editorPresetSelects.get(target) === presetSelect)
|
|
16835
17232
|
editorPresetSelects.delete(target);
|
|
16836
|
-
const
|
|
16837
|
-
if (
|
|
17233
|
+
const i2 = mountedEditors.indexOf(daw);
|
|
17234
|
+
if (i2 >= 0) mountedEditors.splice(i2, 1);
|
|
16838
17235
|
};
|
|
16839
17236
|
return {
|
|
16840
17237
|
...daw,
|
|
@@ -16937,8 +17334,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16937
17334
|
destroy: () => {
|
|
16938
17335
|
doUnmount();
|
|
16939
17336
|
wrapper.remove();
|
|
16940
|
-
const
|
|
16941
|
-
if (
|
|
17337
|
+
const i2 = mountedModeSwitches.indexOf(instance);
|
|
17338
|
+
if (i2 >= 0) mountedModeSwitches.splice(i2, 1);
|
|
16942
17339
|
}
|
|
16943
17340
|
};
|
|
16944
17341
|
mountedModeSwitches.push(instance);
|
|
@@ -17025,8 +17422,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17025
17422
|
mountedPlayers.push(player);
|
|
17026
17423
|
const destroy = () => {
|
|
17027
17424
|
player.destroy();
|
|
17028
|
-
const
|
|
17029
|
-
if (
|
|
17425
|
+
const i2 = mountedPlayers.indexOf(player);
|
|
17426
|
+
if (i2 >= 0) mountedPlayers.splice(i2, 1);
|
|
17030
17427
|
};
|
|
17031
17428
|
return { ...player, destroy };
|
|
17032
17429
|
};
|
|
@@ -17287,8 +17684,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17287
17684
|
mountedChordPlayers.push(player);
|
|
17288
17685
|
const destroy = () => {
|
|
17289
17686
|
player.destroy();
|
|
17290
|
-
const
|
|
17291
|
-
if (
|
|
17687
|
+
const i2 = mountedChordPlayers.indexOf(player);
|
|
17688
|
+
if (i2 >= 0) mountedChordPlayers.splice(i2, 1);
|
|
17292
17689
|
};
|
|
17293
17690
|
return {
|
|
17294
17691
|
...player,
|
|
@@ -17343,6 +17740,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17343
17740
|
mountModeSwitch,
|
|
17344
17741
|
setMasterVolume,
|
|
17345
17742
|
setVolume: setMasterVolume,
|
|
17743
|
+
setReverbAmount,
|
|
17346
17744
|
dispose
|
|
17347
17745
|
};
|
|
17348
17746
|
};
|
|
@@ -17373,6 +17771,7 @@ export {
|
|
|
17373
17771
|
PREWARM_NOTES,
|
|
17374
17772
|
TRACKS_ADVANCED,
|
|
17375
17773
|
TRACKS_SIMPLE,
|
|
17774
|
+
VIBRATO_MIN_SEC,
|
|
17376
17775
|
VOICE_IMAGES,
|
|
17377
17776
|
VOICE_IMAGE_KEY,
|
|
17378
17777
|
analyzeMidiTracks,
|