@onjmin/dtm 0.1.83 → 0.1.85
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 +165 -5
- package/dist/index.d.ts +165 -5
- package/dist/index.js +1345 -338
- package/dist/index.mjs +1344 -338
- package/dist/voice-worker.js +185 -14
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ __export(index_exports, {
|
|
|
46
46
|
PREWARM_NOTES: () => PREWARM_NOTES,
|
|
47
47
|
TRACKS_ADVANCED: () => TRACKS_ADVANCED,
|
|
48
48
|
TRACKS_SIMPLE: () => TRACKS_SIMPLE,
|
|
49
|
+
VIBRATO_MIN_SEC: () => VIBRATO_MIN_SEC,
|
|
49
50
|
VOICE_IMAGES: () => VOICE_IMAGES,
|
|
50
51
|
VOICE_IMAGE_KEY: () => VOICE_IMAGE_KEY,
|
|
51
52
|
analyzeMidiTracks: () => analyzeMidiTracks,
|
|
@@ -348,8 +349,8 @@ var Input = class _Input {
|
|
|
348
349
|
}
|
|
349
350
|
return str.length ? Number(str) : null;
|
|
350
351
|
}
|
|
351
|
-
slice(
|
|
352
|
-
return this.str.slice(this.idx, this.idx +
|
|
352
|
+
slice(i2) {
|
|
353
|
+
return this.str.slice(this.idx, this.idx + i2);
|
|
353
354
|
}
|
|
354
355
|
};
|
|
355
356
|
var Output = class {
|
|
@@ -385,8 +386,8 @@ var Matcher = class {
|
|
|
385
386
|
else this._set(key, value);
|
|
386
387
|
}
|
|
387
388
|
parse(input) {
|
|
388
|
-
for (const
|
|
389
|
-
const s = input.slice(
|
|
389
|
+
for (const i2 of this.lengths) {
|
|
390
|
+
const s = input.slice(i2);
|
|
390
391
|
if (this.map.has(s)) {
|
|
391
392
|
input.idx += s.length;
|
|
392
393
|
return this.map.get(s);
|
|
@@ -440,7 +441,7 @@ var parseFormula = (input, output = new Output(), nest = 0) => {
|
|
|
440
441
|
if (o.isChord) {
|
|
441
442
|
output.value = [...o.value].concat(v);
|
|
442
443
|
} else {
|
|
443
|
-
const a = v.sort((
|
|
444
|
+
const a = v.sort((x2, y) => x2 - y);
|
|
444
445
|
const pitch = (o.pitch + 3) % 12 - 3;
|
|
445
446
|
if (a[0] < pitch) {
|
|
446
447
|
while (a[0] < pitch) a.push(a.shift() + 12);
|
|
@@ -477,16 +478,16 @@ halfMatcher.set("+", 1);
|
|
|
477
478
|
halfMatcher.set("-", -1);
|
|
478
479
|
var parseHalf = (input, isPitch = false) => (isPitch ? halfMatcherStrict : halfMatcher).parse(input);
|
|
479
480
|
var idx2pitch = [0, 2, 4, 5, 7, 9, 11];
|
|
480
|
-
for (const
|
|
481
|
+
for (const i2 of [...idx2pitch.keys()]) idx2pitch.push(idx2pitch[i2] + 12);
|
|
481
482
|
var deg2pitch = (deg) => idx2pitch[deg - 1];
|
|
482
483
|
var pitchMatcher = new Matcher();
|
|
483
|
-
for (const [
|
|
484
|
-
pitchMatcher.set(v, idx2pitch[
|
|
484
|
+
for (const [i2, v] of [..."CDEFGAB"].entries())
|
|
485
|
+
pitchMatcher.set(v, idx2pitch[i2]);
|
|
485
486
|
var parsePitch = (input, output) => {
|
|
486
487
|
const pitch = pitchMatcher.parse(input);
|
|
487
488
|
if (pitch === null) err(input, "Not found pitch");
|
|
488
489
|
output.pitch = pitch;
|
|
489
|
-
for (let
|
|
490
|
+
for (let i2 = 0; i2 < 2; i2++) {
|
|
490
491
|
const half = parseHalf(input, true);
|
|
491
492
|
if (half === null) break;
|
|
492
493
|
output.pitch += half;
|
|
@@ -692,11 +693,11 @@ var pearson = (a, b) => {
|
|
|
692
693
|
let num = 0;
|
|
693
694
|
let da = 0;
|
|
694
695
|
let db = 0;
|
|
695
|
-
for (let
|
|
696
|
-
const
|
|
697
|
-
const y = b[
|
|
698
|
-
num +=
|
|
699
|
-
da +=
|
|
696
|
+
for (let i2 = 0; i2 < a.length; i2++) {
|
|
697
|
+
const x2 = a[i2] - ma;
|
|
698
|
+
const y = b[i2] - mb;
|
|
699
|
+
num += x2 * y;
|
|
700
|
+
da += x2 * x2;
|
|
700
701
|
db += y * y;
|
|
701
702
|
}
|
|
702
703
|
const den = Math.sqrt(da * db);
|
|
@@ -772,19 +773,19 @@ var coalesce = (segments) => {
|
|
|
772
773
|
var mergeShortSegments = (segments, min) => {
|
|
773
774
|
if (min <= 0) return segments;
|
|
774
775
|
const result = segments.map((s) => ({ ...s }));
|
|
775
|
-
let
|
|
776
|
-
while (
|
|
777
|
-
if (result[
|
|
778
|
-
|
|
776
|
+
let i2 = 0;
|
|
777
|
+
while (i2 < result.length && result.length > 1) {
|
|
778
|
+
if (result[i2].duration >= min) {
|
|
779
|
+
i2++;
|
|
779
780
|
continue;
|
|
780
781
|
}
|
|
781
|
-
if (
|
|
782
|
-
result[
|
|
783
|
-
result.splice(
|
|
782
|
+
if (i2 > 0) {
|
|
783
|
+
result[i2 - 1].duration += result[i2].duration;
|
|
784
|
+
result.splice(i2, 1);
|
|
784
785
|
} else {
|
|
785
|
-
result[
|
|
786
|
-
result[
|
|
787
|
-
result.splice(
|
|
786
|
+
result[i2 + 1].when = result[i2].when;
|
|
787
|
+
result[i2 + 1].duration += result[i2].duration;
|
|
788
|
+
result.splice(i2, 1);
|
|
788
789
|
}
|
|
789
790
|
}
|
|
790
791
|
return coalesce(result);
|
|
@@ -1003,19 +1004,19 @@ var viterbi = (emissions, changePenalty) => {
|
|
|
1003
1004
|
const curr = new Array(N).fill(0);
|
|
1004
1005
|
const em = emissions[t];
|
|
1005
1006
|
const switchVal = bestPrevVal - changePenalty;
|
|
1006
|
-
for (let
|
|
1007
|
-
if (prev[
|
|
1008
|
-
curr[
|
|
1009
|
-
back[t][
|
|
1007
|
+
for (let i2 = 0; i2 < N; i2++) {
|
|
1008
|
+
if (prev[i2] >= switchVal) {
|
|
1009
|
+
curr[i2] = em[i2] + prev[i2];
|
|
1010
|
+
back[t][i2] = i2;
|
|
1010
1011
|
} else {
|
|
1011
|
-
curr[
|
|
1012
|
-
back[t][
|
|
1012
|
+
curr[i2] = em[i2] + switchVal;
|
|
1013
|
+
back[t][i2] = bestPrevIdx;
|
|
1013
1014
|
}
|
|
1014
1015
|
}
|
|
1015
1016
|
prev = curr;
|
|
1016
1017
|
}
|
|
1017
1018
|
let bestIdx = 0;
|
|
1018
|
-
for (let
|
|
1019
|
+
for (let i2 = 1; i2 < N; i2++) if (prev[i2] > prev[bestIdx]) bestIdx = i2;
|
|
1019
1020
|
const path = new Array(T).fill(0);
|
|
1020
1021
|
path[T - 1] = bestIdx;
|
|
1021
1022
|
for (let t = T - 1; t > 0; t--) path[t - 1] = back[t][path[t]];
|
|
@@ -1112,20 +1113,20 @@ var parseChords = (str, bpm = 120) => {
|
|
|
1112
1113
|
if (!str2.length) continue;
|
|
1113
1114
|
const when = idx++ * secBar;
|
|
1114
1115
|
const a = [];
|
|
1115
|
-
for (let
|
|
1116
|
-
const char = str2[
|
|
1117
|
-
const prev = str2[
|
|
1118
|
-
const prev2 = str2.slice(
|
|
1116
|
+
for (let i2 = 0; i2 < str2.length; i2++) {
|
|
1117
|
+
const char = str2[i2];
|
|
1118
|
+
const prev = str2[i2 - 1];
|
|
1119
|
+
const prev2 = str2.slice(i2 - 2, i2);
|
|
1119
1120
|
if (!frontChars.has(char)) continue;
|
|
1120
1121
|
if (prev === "/" || prev2 === "on") continue;
|
|
1121
1122
|
if (prev2 === "N." && char === "C") continue;
|
|
1122
|
-
a.push(
|
|
1123
|
+
a.push(i2);
|
|
1123
1124
|
}
|
|
1124
1125
|
if (!a.length) continue;
|
|
1125
1126
|
const divide = 2 ** Math.ceil(Math.log2(a.length));
|
|
1126
1127
|
const unitTime = secBar / divide;
|
|
1127
|
-
for (const [
|
|
1128
|
-
const s = str2.slice(v,
|
|
1128
|
+
for (const [i2, v] of a.entries()) {
|
|
1129
|
+
const s = str2.slice(v, i2 === a.length - 1 ? str2.length : a[i2 + 1]).replace(/\s+/g, "");
|
|
1129
1130
|
const c = s[0];
|
|
1130
1131
|
if (c === "_" || c === "N") {
|
|
1131
1132
|
last = null;
|
|
@@ -1135,7 +1136,7 @@ var parseChords = (str, bpm = 120) => {
|
|
|
1135
1136
|
if (last) last.duration += unitTime;
|
|
1136
1137
|
continue;
|
|
1137
1138
|
}
|
|
1138
|
-
const _when = when +
|
|
1139
|
+
const _when = when + i2 * unitTime;
|
|
1139
1140
|
if (c === "%") {
|
|
1140
1141
|
if (last === null) continue;
|
|
1141
1142
|
const base = last;
|
|
@@ -1300,19 +1301,19 @@ var resolveDrumPattern = (name, dict, currentBar) => {
|
|
|
1300
1301
|
if (Array.isArray(patternObj) && patternObj.length > 0 && "ranges" in patternObj[0]) {
|
|
1301
1302
|
const songDef = patternObj;
|
|
1302
1303
|
const instructions = songDef.filter(
|
|
1303
|
-
(
|
|
1304
|
+
(i2) => i2.ranges.some(([s, e]) => currentBar >= s && currentBar <= e)
|
|
1304
1305
|
);
|
|
1305
1306
|
if (instructions.length > 0) {
|
|
1306
|
-
return instructions.flatMap((
|
|
1307
|
-
const maxStep = Math.max(...
|
|
1308
|
-
const loopLengthBars =
|
|
1309
|
-
const range =
|
|
1307
|
+
return instructions.flatMap((i2) => {
|
|
1308
|
+
const maxStep = Math.max(...i2.pattern.map((p) => p.step), 0);
|
|
1309
|
+
const loopLengthBars = i2.patternBars ?? Math.max(1, Math.ceil((maxStep + 1) / 192));
|
|
1310
|
+
const range = i2.ranges.find(
|
|
1310
1311
|
([s, e]) => currentBar >= s && currentBar <= e
|
|
1311
1312
|
);
|
|
1312
1313
|
const startBar = range ? range[0] : 1;
|
|
1313
1314
|
const barInLoop = (currentBar - startBar) % loopLengthBars;
|
|
1314
1315
|
const stepOffset = barInLoop * 192;
|
|
1315
|
-
return
|
|
1316
|
+
return i2.pattern.filter((p) => p.step >= stepOffset && p.step < stepOffset + 192).map((p) => ({ ...p, step: p.step - stepOffset }));
|
|
1316
1317
|
});
|
|
1317
1318
|
}
|
|
1318
1319
|
}
|
|
@@ -1455,8 +1456,8 @@ var getDrumPatternKeys = (name, dict) => {
|
|
|
1455
1456
|
const keys = /* @__PURE__ */ new Set();
|
|
1456
1457
|
if (Array.isArray(patternObj) && patternObj.length > 0 && "ranges" in patternObj[0]) {
|
|
1457
1458
|
const songDef = patternObj;
|
|
1458
|
-
for (const
|
|
1459
|
-
for (const p of
|
|
1459
|
+
for (const i2 of songDef) {
|
|
1460
|
+
for (const p of i2.pattern) keys.add(p.pitch);
|
|
1460
1461
|
}
|
|
1461
1462
|
} else if (Array.isArray(patternObj)) {
|
|
1462
1463
|
for (const p of patternObj) keys.add(p.pitch);
|
|
@@ -1513,21 +1514,21 @@ var buildChordPlacements = (options) => {
|
|
|
1513
1514
|
}
|
|
1514
1515
|
} else if (patternType === "arpeggio") {
|
|
1515
1516
|
const arpInterval = Math.floor(noteLength / notes.length);
|
|
1516
|
-
notes.forEach((noteOffset,
|
|
1517
|
+
notes.forEach((noteOffset, i2) => {
|
|
1517
1518
|
placements.push({
|
|
1518
|
-
startStep: chord.whenStep +
|
|
1519
|
+
startStep: chord.whenStep + i2 * arpInterval,
|
|
1519
1520
|
pitch: C3 + noteOffset + offset,
|
|
1520
|
-
durationSteps: noteLength -
|
|
1521
|
+
durationSteps: noteLength - i2 * arpInterval,
|
|
1521
1522
|
velocity: 100
|
|
1522
1523
|
});
|
|
1523
1524
|
});
|
|
1524
1525
|
} else if (patternType === "arpeggio-fast") {
|
|
1525
1526
|
const arpInterval = 6;
|
|
1526
|
-
notes.forEach((noteOffset,
|
|
1527
|
+
notes.forEach((noteOffset, i2) => {
|
|
1527
1528
|
placements.push({
|
|
1528
|
-
startStep: chord.whenStep +
|
|
1529
|
+
startStep: chord.whenStep + i2 * arpInterval,
|
|
1529
1530
|
pitch: C3 + noteOffset + offset,
|
|
1530
|
-
durationSteps: Math.max(12, noteLength -
|
|
1531
|
+
durationSteps: Math.max(12, noteLength - i2 * arpInterval),
|
|
1531
1532
|
velocity: 100
|
|
1532
1533
|
});
|
|
1533
1534
|
});
|
|
@@ -1567,8 +1568,8 @@ var buildChordPlacements = (options) => {
|
|
|
1567
1568
|
}
|
|
1568
1569
|
}
|
|
1569
1570
|
} else if (patternType === "alternating") {
|
|
1570
|
-
notes.forEach((noteOffset,
|
|
1571
|
-
const stepOffset =
|
|
1571
|
+
notes.forEach((noteOffset, i2) => {
|
|
1572
|
+
const stepOffset = i2 * Math.floor(stepsPerBar / 4);
|
|
1572
1573
|
placements.push({
|
|
1573
1574
|
startStep: chord.whenStep + stepOffset,
|
|
1574
1575
|
pitch: C3 + noteOffset + offset,
|
|
@@ -1590,8 +1591,8 @@ var buildChordPlacements = (options) => {
|
|
|
1590
1591
|
}
|
|
1591
1592
|
if (notes.length === 0) return;
|
|
1592
1593
|
const startStep = barIndex * chordLength;
|
|
1593
|
-
notes.forEach((noteOffset,
|
|
1594
|
-
const stepOffset =
|
|
1594
|
+
notes.forEach((noteOffset, i2) => {
|
|
1595
|
+
const stepOffset = i2 * 3;
|
|
1595
1596
|
placements.push({
|
|
1596
1597
|
startStep: startStep + stepOffset,
|
|
1597
1598
|
pitch: C3 + noteOffset + offset,
|
|
@@ -1604,7 +1605,136 @@ var buildChordPlacements = (options) => {
|
|
|
1604
1605
|
return placements;
|
|
1605
1606
|
};
|
|
1606
1607
|
|
|
1607
|
-
// node_modules/.pnpm/@onjmin+koe@1.0.
|
|
1608
|
+
// node_modules/.pnpm/@onjmin+koe@1.0.5/node_modules/@onjmin/koe/dist/index.js
|
|
1609
|
+
var u8 = Uint8Array;
|
|
1610
|
+
var u16 = Uint16Array;
|
|
1611
|
+
var i32 = Int32Array;
|
|
1612
|
+
var fleb = new u8([
|
|
1613
|
+
0,
|
|
1614
|
+
0,
|
|
1615
|
+
0,
|
|
1616
|
+
0,
|
|
1617
|
+
0,
|
|
1618
|
+
0,
|
|
1619
|
+
0,
|
|
1620
|
+
0,
|
|
1621
|
+
1,
|
|
1622
|
+
1,
|
|
1623
|
+
1,
|
|
1624
|
+
1,
|
|
1625
|
+
2,
|
|
1626
|
+
2,
|
|
1627
|
+
2,
|
|
1628
|
+
2,
|
|
1629
|
+
3,
|
|
1630
|
+
3,
|
|
1631
|
+
3,
|
|
1632
|
+
3,
|
|
1633
|
+
4,
|
|
1634
|
+
4,
|
|
1635
|
+
4,
|
|
1636
|
+
4,
|
|
1637
|
+
5,
|
|
1638
|
+
5,
|
|
1639
|
+
5,
|
|
1640
|
+
5,
|
|
1641
|
+
0,
|
|
1642
|
+
/* unused */
|
|
1643
|
+
0,
|
|
1644
|
+
0,
|
|
1645
|
+
/* impossible */
|
|
1646
|
+
0
|
|
1647
|
+
]);
|
|
1648
|
+
var fdeb = new u8([
|
|
1649
|
+
0,
|
|
1650
|
+
0,
|
|
1651
|
+
0,
|
|
1652
|
+
0,
|
|
1653
|
+
1,
|
|
1654
|
+
1,
|
|
1655
|
+
2,
|
|
1656
|
+
2,
|
|
1657
|
+
3,
|
|
1658
|
+
3,
|
|
1659
|
+
4,
|
|
1660
|
+
4,
|
|
1661
|
+
5,
|
|
1662
|
+
5,
|
|
1663
|
+
6,
|
|
1664
|
+
6,
|
|
1665
|
+
7,
|
|
1666
|
+
7,
|
|
1667
|
+
8,
|
|
1668
|
+
8,
|
|
1669
|
+
9,
|
|
1670
|
+
9,
|
|
1671
|
+
10,
|
|
1672
|
+
10,
|
|
1673
|
+
11,
|
|
1674
|
+
11,
|
|
1675
|
+
12,
|
|
1676
|
+
12,
|
|
1677
|
+
13,
|
|
1678
|
+
13,
|
|
1679
|
+
/* unused */
|
|
1680
|
+
0,
|
|
1681
|
+
0
|
|
1682
|
+
]);
|
|
1683
|
+
var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
1684
|
+
var freb = function(eb, start) {
|
|
1685
|
+
var b = new u16(31);
|
|
1686
|
+
for (var i2 = 0; i2 < 31; ++i2) {
|
|
1687
|
+
b[i2] = start += 1 << eb[i2 - 1];
|
|
1688
|
+
}
|
|
1689
|
+
var r = new i32(b[30]);
|
|
1690
|
+
for (var i2 = 1; i2 < 30; ++i2) {
|
|
1691
|
+
for (var j = b[i2]; j < b[i2 + 1]; ++j) {
|
|
1692
|
+
r[j] = j - b[i2] << 5 | i2;
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
return { b, r };
|
|
1696
|
+
};
|
|
1697
|
+
var _a = freb(fleb, 2);
|
|
1698
|
+
var fl = _a.b;
|
|
1699
|
+
var revfl = _a.r;
|
|
1700
|
+
fl[28] = 258, revfl[258] = 28;
|
|
1701
|
+
var _b = freb(fdeb, 0);
|
|
1702
|
+
var fd = _b.b;
|
|
1703
|
+
var revfd = _b.r;
|
|
1704
|
+
var rev = new u16(32768);
|
|
1705
|
+
for (i = 0; i < 32768; ++i) {
|
|
1706
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
1707
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
1708
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
1709
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
1710
|
+
}
|
|
1711
|
+
var x;
|
|
1712
|
+
var i;
|
|
1713
|
+
var flt = new u8(288);
|
|
1714
|
+
for (i = 0; i < 144; ++i)
|
|
1715
|
+
flt[i] = 8;
|
|
1716
|
+
var i;
|
|
1717
|
+
for (i = 144; i < 256; ++i)
|
|
1718
|
+
flt[i] = 9;
|
|
1719
|
+
var i;
|
|
1720
|
+
for (i = 256; i < 280; ++i)
|
|
1721
|
+
flt[i] = 7;
|
|
1722
|
+
var i;
|
|
1723
|
+
for (i = 280; i < 288; ++i)
|
|
1724
|
+
flt[i] = 8;
|
|
1725
|
+
var i;
|
|
1726
|
+
var fdt = new u8(32);
|
|
1727
|
+
for (i = 0; i < 32; ++i)
|
|
1728
|
+
fdt[i] = 5;
|
|
1729
|
+
var i;
|
|
1730
|
+
var et = /* @__PURE__ */ new u8(0);
|
|
1731
|
+
var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
|
|
1732
|
+
var tds = 0;
|
|
1733
|
+
try {
|
|
1734
|
+
td.decode(et, { stream: true });
|
|
1735
|
+
tds = 1;
|
|
1736
|
+
} catch (e) {
|
|
1737
|
+
}
|
|
1608
1738
|
var MAGIC = 1263486208;
|
|
1609
1739
|
function parseKoeHeader(headerBytes) {
|
|
1610
1740
|
const view = new DataView(headerBytes);
|
|
@@ -1770,7 +1900,7 @@ var VoiceBank = class _VoiceBank {
|
|
|
1770
1900
|
if (!buf) return null;
|
|
1771
1901
|
const int16 = new Int16Array(buf, 0, Math.floor(buf.byteLength / 2));
|
|
1772
1902
|
const f64 = new Float64Array(int16.length);
|
|
1773
|
-
for (let
|
|
1903
|
+
for (let i2 = 0; i2 < int16.length; i2++) f64[i2] = int16[i2] / 32768;
|
|
1774
1904
|
return f64;
|
|
1775
1905
|
}
|
|
1776
1906
|
};
|
|
@@ -1778,6 +1908,7 @@ var WORLDLINE_SAMPLE_RATE = 48e3;
|
|
|
1778
1908
|
var MIN_WORLDLINE_SAMPLES = 4096;
|
|
1779
1909
|
var SYNTH_REQ_SIZE = 120;
|
|
1780
1910
|
var WL_FRAME_MS = 10;
|
|
1911
|
+
var sampleCurve = (input, curve, totalMs) => typeof curve === "function" ? curve(input, totalMs) : curve;
|
|
1781
1912
|
var samplesToMs = (samples) => samples / WORLDLINE_SAMPLE_RATE * 1e3;
|
|
1782
1913
|
function leadInFromEntry(entry) {
|
|
1783
1914
|
return {
|
|
@@ -1863,11 +1994,23 @@ var Worldline = class _Worldline {
|
|
|
1863
1994
|
* {@link MIN_WORLDLINE_SAMPLES} (too short for stable F0 analysis).
|
|
1864
1995
|
*/
|
|
1865
1996
|
renderNote(params) {
|
|
1866
|
-
const {
|
|
1997
|
+
const {
|
|
1998
|
+
pcm,
|
|
1999
|
+
pitch,
|
|
2000
|
+
durationMs,
|
|
2001
|
+
preMs,
|
|
2002
|
+
consonantMs,
|
|
2003
|
+
tempo = 120,
|
|
2004
|
+
gender = 0.5,
|
|
2005
|
+
tension = 0.5,
|
|
2006
|
+
breathiness = 0.5,
|
|
2007
|
+
voicing = 1
|
|
2008
|
+
} = params;
|
|
1867
2009
|
if (!pcm || pcm.length < MIN_WORLDLINE_SAMPLES) return null;
|
|
1868
2010
|
const WL = this.wasm;
|
|
1869
2011
|
const FS = WORLDLINE_SAMPLE_RATE;
|
|
1870
|
-
const
|
|
2012
|
+
const basePitch = sampleCurve(preMs + durationMs / 2, pitch, preMs + durationMs);
|
|
2013
|
+
const midiNote = Math.round(69 + 12 * Math.log2(basePitch / 440));
|
|
1871
2014
|
const posMs = 0;
|
|
1872
2015
|
const reqLen = preMs + durationMs;
|
|
1873
2016
|
const cutMs = WL_FRAME_MS * 2;
|
|
@@ -1913,11 +2056,19 @@ var Worldline = class _Worldline {
|
|
|
1913
2056
|
WL._free(reqPtr);
|
|
1914
2057
|
const totalMs = posMs + reqLen + WL_FRAME_MS * 2;
|
|
1915
2058
|
const nFrames = Math.ceil(totalMs / WL_FRAME_MS) + 4;
|
|
1916
|
-
const f0Arr = new Float64Array(nFrames)
|
|
1917
|
-
const gArr = new Float64Array(nFrames)
|
|
1918
|
-
const tArr = new Float64Array(nFrames)
|
|
1919
|
-
const bArr = new Float64Array(nFrames)
|
|
1920
|
-
const vArr = new Float64Array(nFrames)
|
|
2059
|
+
const f0Arr = new Float64Array(nFrames);
|
|
2060
|
+
const gArr = new Float64Array(nFrames);
|
|
2061
|
+
const tArr = new Float64Array(nFrames);
|
|
2062
|
+
const bArr = new Float64Array(nFrames);
|
|
2063
|
+
const vArr = new Float64Array(nFrames);
|
|
2064
|
+
for (let i2 = 0; i2 < nFrames; i2++) {
|
|
2065
|
+
const tMs = i2 * WL_FRAME_MS;
|
|
2066
|
+
f0Arr[i2] = sampleCurve(tMs, pitch, totalMs);
|
|
2067
|
+
gArr[i2] = sampleCurve(tMs, gender, totalMs);
|
|
2068
|
+
tArr[i2] = sampleCurve(tMs, tension, totalMs);
|
|
2069
|
+
bArr[i2] = sampleCurve(tMs, breathiness, totalMs);
|
|
2070
|
+
vArr[i2] = sampleCurve(tMs, voicing, totalMs);
|
|
2071
|
+
}
|
|
1921
2072
|
const f0Ptr = WL._malloc(nFrames * 8);
|
|
1922
2073
|
const gPtr = WL._malloc(nFrames * 8);
|
|
1923
2074
|
const tPtr = WL._malloc(nFrames * 8);
|
|
@@ -1977,6 +2128,19 @@ var DEFAULT_PLAYBACK_VELOCITY = 127;
|
|
|
1977
2128
|
var DEFAULT_STEPS_PER_BAR = 192;
|
|
1978
2129
|
var MML_END_MARKER = "#end;";
|
|
1979
2130
|
|
|
2131
|
+
// src/vibrato.ts
|
|
2132
|
+
var VIBRATO_MIN_SEC = 0.35;
|
|
2133
|
+
var VIBRATO_RATE_HZ = 5.5;
|
|
2134
|
+
var VIBRATO_DEPTH_CENTS = 35;
|
|
2135
|
+
var VIBRATO_FADE_MS = 150;
|
|
2136
|
+
var vibratoPitchCurve = (baseHz, preMs) => (tMs) => {
|
|
2137
|
+
const sinceOnset = tMs - preMs;
|
|
2138
|
+
if (sinceOnset <= 0) return baseHz;
|
|
2139
|
+
const depth = VIBRATO_DEPTH_CENTS * Math.min(1, sinceOnset / VIBRATO_FADE_MS);
|
|
2140
|
+
const cents = depth * Math.sin(2 * Math.PI * VIBRATO_RATE_HZ * sinceOnset / 1e3);
|
|
2141
|
+
return baseHz * 2 ** (cents / 1200);
|
|
2142
|
+
};
|
|
2143
|
+
|
|
1980
2144
|
// src/lyrics.ts
|
|
1981
2145
|
var kanaTable = {
|
|
1982
2146
|
\u3042: ["", "a"],
|
|
@@ -2141,8 +2305,8 @@ var vocalVolumeToGain = (v) => {
|
|
|
2141
2305
|
var parseLyrics = (mml) => {
|
|
2142
2306
|
const tracks = /* @__PURE__ */ new Map();
|
|
2143
2307
|
const segments = splitSegments(mml);
|
|
2144
|
-
for (let
|
|
2145
|
-
const m = segments[
|
|
2308
|
+
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
2309
|
+
const m = segments[i2].match(LYRIC_LINE);
|
|
2146
2310
|
if (!m) continue;
|
|
2147
2311
|
const trackId = Number.parseInt(m[1], 10);
|
|
2148
2312
|
let rest = m[2].trim();
|
|
@@ -2150,8 +2314,12 @@ var parseLyrics = (mml) => {
|
|
|
2150
2314
|
let gate = 100;
|
|
2151
2315
|
let pan = 64;
|
|
2152
2316
|
let octave = 0;
|
|
2317
|
+
let vibrato = false;
|
|
2318
|
+
let reverb = 0;
|
|
2319
|
+
let gender = 50;
|
|
2320
|
+
let breathiness = 50;
|
|
2153
2321
|
const modelMatch = rest.match(
|
|
2154
|
-
/^([a-z_][a-z0-9_]*?)(?=(?:[
|
|
2322
|
+
/^([a-z_][a-z0-9_]*?)(?=(?:[vqpobrgh]-?\d)|[^a-z0-9_]|$)(?::(\d+))?/i
|
|
2155
2323
|
);
|
|
2156
2324
|
let model = "";
|
|
2157
2325
|
const metaTokens = [];
|
|
@@ -2192,11 +2360,39 @@ var parseLyrics = (mml) => {
|
|
|
2192
2360
|
rest = rest.substring(oMatch[0].length).trim();
|
|
2193
2361
|
continue;
|
|
2194
2362
|
}
|
|
2363
|
+
const bMatch = rest.match(/^b([01])/i);
|
|
2364
|
+
if (bMatch) {
|
|
2365
|
+
vibrato = bMatch[1] === "1";
|
|
2366
|
+
metaTokens.push(bMatch[0]);
|
|
2367
|
+
rest = rest.substring(bMatch[0].length).trim();
|
|
2368
|
+
continue;
|
|
2369
|
+
}
|
|
2370
|
+
const rMatch = rest.match(/^r(\d+)/i);
|
|
2371
|
+
if (rMatch) {
|
|
2372
|
+
reverb = clamp(Number.parseInt(rMatch[1], 10), 0, 100);
|
|
2373
|
+
metaTokens.push(rMatch[0]);
|
|
2374
|
+
rest = rest.substring(rMatch[0].length).trim();
|
|
2375
|
+
continue;
|
|
2376
|
+
}
|
|
2377
|
+
const gMatch = rest.match(/^g(\d+)/i);
|
|
2378
|
+
if (gMatch) {
|
|
2379
|
+
gender = clamp(Number.parseInt(gMatch[1], 10), 0, 100);
|
|
2380
|
+
metaTokens.push(gMatch[0]);
|
|
2381
|
+
rest = rest.substring(gMatch[0].length).trim();
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
const hMatch = rest.match(/^h(\d+)/i);
|
|
2385
|
+
if (hMatch) {
|
|
2386
|
+
breathiness = clamp(Number.parseInt(hMatch[1], 10), 0, 100);
|
|
2387
|
+
metaTokens.push(hMatch[0]);
|
|
2388
|
+
rest = rest.substring(hMatch[0].length).trim();
|
|
2389
|
+
continue;
|
|
2390
|
+
}
|
|
2195
2391
|
break;
|
|
2196
2392
|
}
|
|
2197
2393
|
const lyricLines = [rest];
|
|
2198
|
-
while (
|
|
2199
|
-
lyricLines.push(segments[++
|
|
2394
|
+
while (i2 + 1 < segments.length && isLyricContinuation(segments[i2 + 1])) {
|
|
2395
|
+
lyricLines.push(segments[++i2]);
|
|
2200
2396
|
}
|
|
2201
2397
|
const { syllables, lineBreaks } = normalizeLyricLines(lyricLines);
|
|
2202
2398
|
tracks.set(trackId, {
|
|
@@ -2206,6 +2402,10 @@ var parseLyrics = (mml) => {
|
|
|
2206
2402
|
gate,
|
|
2207
2403
|
pan,
|
|
2208
2404
|
octave,
|
|
2405
|
+
vibrato,
|
|
2406
|
+
reverb,
|
|
2407
|
+
gender,
|
|
2408
|
+
breathiness,
|
|
2209
2409
|
syllables,
|
|
2210
2410
|
metaText: metaTokens.join(" "),
|
|
2211
2411
|
...lineBreaks.length > 0 ? { lineBreaks } : {}
|
|
@@ -2216,13 +2416,13 @@ var parseLyrics = (mml) => {
|
|
|
2216
2416
|
var stripLyrics = (mml) => {
|
|
2217
2417
|
const segments = splitSegments(mml);
|
|
2218
2418
|
const kept = [];
|
|
2219
|
-
for (let
|
|
2220
|
-
if (LYRIC_LINE.test(segments[
|
|
2221
|
-
while (
|
|
2222
|
-
|
|
2419
|
+
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
2420
|
+
if (LYRIC_LINE.test(segments[i2])) {
|
|
2421
|
+
while (i2 + 1 < segments.length && isLyricContinuation(segments[i2 + 1]))
|
|
2422
|
+
i2++;
|
|
2223
2423
|
continue;
|
|
2224
2424
|
}
|
|
2225
|
-
kept.push(segments[
|
|
2425
|
+
kept.push(segments[i2]);
|
|
2226
2426
|
}
|
|
2227
2427
|
return kept.join("\n");
|
|
2228
2428
|
};
|
|
@@ -2291,7 +2491,7 @@ var FORMANTS = {
|
|
|
2291
2491
|
N: [250, 1e3]
|
|
2292
2492
|
};
|
|
2293
2493
|
var midiToFreq = (m) => 440 * 2 ** ((m - 69) / 12);
|
|
2294
|
-
var createKlattVoice = (ctx, destination) => {
|
|
2494
|
+
var createKlattVoice = (ctx, destination, reverbBus) => {
|
|
2295
2495
|
const active = /* @__PURE__ */ new Set();
|
|
2296
2496
|
const voice = (syllable, e) => {
|
|
2297
2497
|
const t0 = ctx.currentTime + e.when;
|
|
@@ -2301,14 +2501,21 @@ var createKlattVoice = (ctx, destination) => {
|
|
|
2301
2501
|
const attack = 0.02;
|
|
2302
2502
|
const release = 0.06;
|
|
2303
2503
|
const sustainEnd = t0 + Math.max(attack + 0.02, e.duration);
|
|
2504
|
+
const dest = e.destination ?? destination;
|
|
2304
2505
|
let panner = null;
|
|
2305
|
-
let out =
|
|
2506
|
+
let out = dest;
|
|
2306
2507
|
if (typeof ctx.createStereoPanner === "function") {
|
|
2307
2508
|
panner = ctx.createStereoPanner();
|
|
2308
2509
|
panner.pan.value = Math.max(-1, Math.min(1, e.pan ?? 0));
|
|
2309
|
-
panner.connect(
|
|
2510
|
+
panner.connect(dest);
|
|
2310
2511
|
out = panner;
|
|
2311
2512
|
}
|
|
2513
|
+
let sendGain = null;
|
|
2514
|
+
if (reverbBus && e.reverbSend && e.reverbSend > 0 && panner) {
|
|
2515
|
+
sendGain = ctx.createGain();
|
|
2516
|
+
sendGain.gain.value = Math.max(0, Math.min(1, e.reverbSend));
|
|
2517
|
+
panner.connect(sendGain).connect(reverbBus);
|
|
2518
|
+
}
|
|
2312
2519
|
const osc = ctx.createOscillator();
|
|
2313
2520
|
osc.type = "sawtooth";
|
|
2314
2521
|
osc.frequency.value = midiToFreq(e.pitch);
|
|
@@ -2337,7 +2544,7 @@ var createKlattVoice = (ctx, destination) => {
|
|
|
2337
2544
|
const length = Math.max(1, Math.floor(ctx.sampleRate * dur));
|
|
2338
2545
|
const buffer = ctx.createBuffer(1, length, ctx.sampleRate);
|
|
2339
2546
|
const data = buffer.getChannelData(0);
|
|
2340
|
-
for (let
|
|
2547
|
+
for (let i2 = 0; i2 < length; i2++) data[i2] = Math.random() * 2 - 1;
|
|
2341
2548
|
const src = ctx.createBufferSource();
|
|
2342
2549
|
src.buffer = buffer;
|
|
2343
2550
|
const hp = ctx.createBiquadFilter();
|
|
@@ -2364,6 +2571,7 @@ var createKlattVoice = (ctx, destination) => {
|
|
|
2364
2571
|
active.delete(osc);
|
|
2365
2572
|
osc.disconnect();
|
|
2366
2573
|
panner?.disconnect();
|
|
2574
|
+
sendGain?.disconnect();
|
|
2367
2575
|
};
|
|
2368
2576
|
};
|
|
2369
2577
|
voice.stopAll = () => {
|
|
@@ -2382,6 +2590,7 @@ var KOE_BASE_URL = "https://pub-12482a6b5cbc4c9e906b2e1904cabae5.r2.dev";
|
|
|
2382
2590
|
var KOE_VOICEBANKS = {
|
|
2383
2591
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093.koe",
|
|
2384
2592
|
rino: "\u6625\u97F3\u30EA\u30CEver0.3.koe",
|
|
2593
|
+
rino121: "\u6625\u97F3\u30EA\u30CEver.1.1(226).koe",
|
|
2385
2594
|
roze: "\u675F\u97F3\u30ED\u30BCver0.\uFF151(\u591A\u97F3\u968E).koe",
|
|
2386
2595
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642\u9023\u7D9A\u97F3Ver.1.03.koe",
|
|
2387
2596
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640\u6B4C\u9023\u7D9A\u97F3\u666E1.00.koe",
|
|
@@ -2390,11 +2599,13 @@ var KOE_VOICEBANKS = {
|
|
|
2390
2599
|
rei: "\u8DB3\u7ACB\u30EC\u30A4ver3.5.0.koe",
|
|
2391
2600
|
mgroid: "MGRoid_\u539F\u97F3\u8A2D\u5B9A\u6E08\u307F.koe",
|
|
2392
2601
|
motroid: "MOTRoid\u5B8C\u5168\u7248V2.koe",
|
|
2393
|
-
nynroid: "NYNRoidver1.4.koe"
|
|
2602
|
+
nynroid: "NYNRoidver1.4.koe",
|
|
2603
|
+
uc: "\u84C4\u97F3\u30AD\u30EA\u30B3\u97F3\u6E90.koe"
|
|
2394
2604
|
};
|
|
2395
2605
|
var KOE_VOICEBANK_LABELS = {
|
|
2396
2606
|
tsukuyomi: "\u3064\u304F\u3088\u307F\u3061\u3083\u3093",
|
|
2397
2607
|
rino: "\u6625\u97F3\u30EA\u30CE",
|
|
2608
|
+
rino121: "\u6625\u97F3\u30EA\u30CEv1.2.1",
|
|
2398
2609
|
roze: "\u675F\u97F3\u30ED\u30BC",
|
|
2399
2610
|
ruko_male: "\u6B32\u97F3\u30EB\u30B3\u2642",
|
|
2400
2611
|
ruko_female: "\u6B32\u97F3\u30EB\u30B3\u2640",
|
|
@@ -2403,12 +2614,14 @@ var KOE_VOICEBANK_LABELS = {
|
|
|
2403
2614
|
rei: "\u8DB3\u7ACB\u30EC\u30A4",
|
|
2404
2615
|
mgroid: "MGRoid",
|
|
2405
2616
|
motroid: "MOTRoid",
|
|
2406
|
-
nynroid: "NYNRoid"
|
|
2617
|
+
nynroid: "NYNRoid",
|
|
2618
|
+
uc: "\u84C4\u97F3\u30AD\u30EA\u30B3"
|
|
2407
2619
|
};
|
|
2408
2620
|
var VOICE_IMAGE_KEY = {
|
|
2409
2621
|
klatt: "puyuyu",
|
|
2410
2622
|
tsukuyomi: "tsukuyomi",
|
|
2411
2623
|
rino: "rino",
|
|
2624
|
+
rino121: "rino",
|
|
2412
2625
|
roze: "roze",
|
|
2413
2626
|
ruko_male: "ruko",
|
|
2414
2627
|
ruko_female: "ruko",
|
|
@@ -2417,11 +2630,13 @@ var VOICE_IMAGE_KEY = {
|
|
|
2417
2630
|
rei: "rei",
|
|
2418
2631
|
mgroid: "MGRoid",
|
|
2419
2632
|
motroid: "MOTRoid",
|
|
2420
|
-
nynroid: "NYNRoid"
|
|
2633
|
+
nynroid: "NYNRoid",
|
|
2634
|
+
uc: "uc"
|
|
2421
2635
|
};
|
|
2422
2636
|
var KOE_VOICEBANK_TERMS = {
|
|
2423
2637
|
tsukuyomi: "https://tyc.rei-yumesaki.net/material/utau/terms/",
|
|
2424
2638
|
rino: "https://hatenakun1.github.io/halunelino/",
|
|
2639
|
+
rino121: "https://harunerino.vercel.app/",
|
|
2425
2640
|
roze: "https://tabaneroze.ninja-web.net/terms-of-use.html",
|
|
2426
2641
|
ruko_male: "https://long-sleeper.net/index.php?id=22",
|
|
2427
2642
|
ruko_female: "https://long-sleeper.net/index.php?id=22",
|
|
@@ -2430,7 +2645,8 @@ var KOE_VOICEBANK_TERMS = {
|
|
|
2430
2645
|
rei: "https://mechanicalgirl.jp/guidelines/",
|
|
2431
2646
|
mgroid: "https://x.com/nisusansu/status/1048825378188353536",
|
|
2432
2647
|
motroid: "https://www.nicovideo.jp/watch/sm40031282",
|
|
2433
|
-
nynroid: "https://www.bilibili.com/video/BV1V24y1a7qs"
|
|
2648
|
+
nynroid: "https://www.bilibili.com/video/BV1V24y1a7qs",
|
|
2649
|
+
uc: "https://chi9nekiriko.wixsite.com/home/%E5%88%A9%E7%94%A8%E8%A6%8F%E7%B4%84"
|
|
2434
2650
|
};
|
|
2435
2651
|
var koeUrl = (name, base = KOE_BASE_URL) => `${base}/${encodeURIComponent(name)}`;
|
|
2436
2652
|
var DEFAULT_WORLDLINE_SCRIPT = "https://onjmin.github.io/koe/demo/world/worldline.js";
|
|
@@ -2519,7 +2735,7 @@ var createLocalBackend = async (options) => {
|
|
|
2519
2735
|
}
|
|
2520
2736
|
return p;
|
|
2521
2737
|
};
|
|
2522
|
-
const renderAlias = async (alias, pitch, durationMs) => {
|
|
2738
|
+
const renderAlias = async (alias, pitch, durationMs, vibrato, expr) => {
|
|
2523
2739
|
const pcm = await getPcm(alias);
|
|
2524
2740
|
if (!pcm || pcm.length === 0) return null;
|
|
2525
2741
|
const entry = bank.manifest.phonemes[alias];
|
|
@@ -2528,9 +2744,11 @@ var createLocalBackend = async (options) => {
|
|
|
2528
2744
|
if (worldline) {
|
|
2529
2745
|
const audio = worldline.renderNote({
|
|
2530
2746
|
pcm,
|
|
2531
|
-
pitch: targetHz,
|
|
2747
|
+
pitch: vibrato ? vibratoPitchCurve(targetHz, lead.preMs) : targetHz,
|
|
2532
2748
|
durationMs,
|
|
2533
|
-
...lead
|
|
2749
|
+
...lead,
|
|
2750
|
+
gender: expr?.gender,
|
|
2751
|
+
breathiness: expr?.breathiness
|
|
2534
2752
|
});
|
|
2535
2753
|
if (audio) return { pcm: audio, preSec: lead.preMs / 1e3, rate: 1 };
|
|
2536
2754
|
}
|
|
@@ -2595,7 +2813,7 @@ var createWorkerBackend = async (workerUrl, options) => {
|
|
|
2595
2813
|
});
|
|
2596
2814
|
onReady = null;
|
|
2597
2815
|
onFail = null;
|
|
2598
|
-
const renderAlias = (alias, pitch, durationMs) => new Promise((resolve) => {
|
|
2816
|
+
const renderAlias = (alias, pitch, durationMs, vibrato, expr) => new Promise((resolve) => {
|
|
2599
2817
|
const id = ++reqId;
|
|
2600
2818
|
pending.set(
|
|
2601
2819
|
id,
|
|
@@ -2608,7 +2826,10 @@ var createWorkerBackend = async (workerUrl, options) => {
|
|
|
2608
2826
|
id,
|
|
2609
2827
|
alias,
|
|
2610
2828
|
pitch,
|
|
2611
|
-
durationMs
|
|
2829
|
+
durationMs,
|
|
2830
|
+
vibrato,
|
|
2831
|
+
gender: expr?.gender,
|
|
2832
|
+
breathiness: expr?.breathiness
|
|
2612
2833
|
});
|
|
2613
2834
|
});
|
|
2614
2835
|
return {
|
|
@@ -2637,15 +2858,21 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2637
2858
|
const inflight = /* @__PURE__ */ new Map();
|
|
2638
2859
|
const active = /* @__PURE__ */ new Set();
|
|
2639
2860
|
let prevVowel = "";
|
|
2640
|
-
const keyOf = (alias, pitch, durationMs) => `${alias}|${pitch}|${Math.round(durationMs / 10) * 10}`;
|
|
2641
|
-
const renderInto = (alias, pitch, durationMs) => {
|
|
2642
|
-
const key = keyOf(alias, pitch, durationMs);
|
|
2861
|
+
const keyOf = (alias, pitch, durationMs, vibrato, expr) => `${alias}|${pitch}|${Math.round(durationMs / 10) * 10}${vibrato ? "|vib" : ""}${expr?.gender !== void 0 ? `|g${Math.round(expr.gender * 100)}` : ""}${expr?.breathiness !== void 0 ? `|h${Math.round(expr.breathiness * 100)}` : ""}`;
|
|
2862
|
+
const renderInto = (alias, pitch, durationMs, vibrato, expr) => {
|
|
2863
|
+
const key = keyOf(alias, pitch, durationMs, vibrato, expr);
|
|
2643
2864
|
const existing = renderCache.get(key);
|
|
2644
2865
|
if (existing !== void 0) return Promise.resolve(existing);
|
|
2645
2866
|
const flying = inflight.get(key);
|
|
2646
2867
|
if (flying) return flying;
|
|
2647
2868
|
const p = (async () => {
|
|
2648
|
-
const out = await backend.renderAlias(
|
|
2869
|
+
const out = await backend.renderAlias(
|
|
2870
|
+
alias,
|
|
2871
|
+
pitch,
|
|
2872
|
+
durationMs,
|
|
2873
|
+
vibrato,
|
|
2874
|
+
expr
|
|
2875
|
+
);
|
|
2649
2876
|
let rendered = null;
|
|
2650
2877
|
if (out) {
|
|
2651
2878
|
const buf = ctx.createBuffer(1, out.pcm.length, KOE_SAMPLE_RATE);
|
|
@@ -2660,15 +2887,22 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2660
2887
|
return p;
|
|
2661
2888
|
};
|
|
2662
2889
|
const LEADCAP_S = 0.09;
|
|
2663
|
-
const schedule = (r, t0, peak, pan) => {
|
|
2664
|
-
|
|
2890
|
+
const schedule = (r, t0, peak, pan, reverbSend = 0, destOverride) => {
|
|
2891
|
+
const dest = destOverride ?? destination;
|
|
2892
|
+
let out = dest;
|
|
2665
2893
|
let panner = null;
|
|
2666
2894
|
if (typeof ctx.createStereoPanner === "function") {
|
|
2667
2895
|
panner = ctx.createStereoPanner();
|
|
2668
2896
|
panner.pan.value = Math.max(-1, Math.min(1, pan));
|
|
2669
|
-
panner.connect(
|
|
2897
|
+
panner.connect(dest);
|
|
2670
2898
|
out = panner;
|
|
2671
2899
|
}
|
|
2900
|
+
let sendGain = null;
|
|
2901
|
+
if (options.reverbBus && reverbSend > 0 && panner) {
|
|
2902
|
+
sendGain = ctx.createGain();
|
|
2903
|
+
sendGain.gain.value = Math.max(0, Math.min(1, reverbSend));
|
|
2904
|
+
panner.connect(sendGain).connect(options.reverbBus);
|
|
2905
|
+
}
|
|
2672
2906
|
const src = ctx.createBufferSource();
|
|
2673
2907
|
src.buffer = r.audio;
|
|
2674
2908
|
src.playbackRate.value = r.rate;
|
|
@@ -2694,6 +2928,7 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2694
2928
|
src.disconnect();
|
|
2695
2929
|
env.disconnect();
|
|
2696
2930
|
panner?.disconnect();
|
|
2931
|
+
sendGain?.disconnect();
|
|
2697
2932
|
};
|
|
2698
2933
|
};
|
|
2699
2934
|
const model = (syllable, e) => {
|
|
@@ -2712,10 +2947,10 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2712
2947
|
const pan = e.pan ?? 0;
|
|
2713
2948
|
const durationMs = Math.max(60, e.duration * 1e3);
|
|
2714
2949
|
void renderInto(alias, e.pitch, durationMs).then((r) => {
|
|
2715
|
-
if (r) schedule(r, t0, peak, pan);
|
|
2950
|
+
if (r) schedule(r, t0, peak, pan, e.reverbSend, e.destination);
|
|
2716
2951
|
});
|
|
2717
2952
|
};
|
|
2718
|
-
model.renderToCache = async (syllable, prevVowelArg, pitch, durationMs) => {
|
|
2953
|
+
model.renderToCache = async (syllable, prevVowelArg, pitch, durationMs, vibrato, expr) => {
|
|
2719
2954
|
if (syllable.consonant === "Q" || syllable.vowel === "") return null;
|
|
2720
2955
|
const alias = resolveKoeAlias(
|
|
2721
2956
|
backend.hasAlias,
|
|
@@ -2726,12 +2961,13 @@ var createKoeVoice = async (ctx, destination, options) => {
|
|
|
2726
2961
|
);
|
|
2727
2962
|
if (!alias) return null;
|
|
2728
2963
|
const dMs = Math.max(60, durationMs);
|
|
2729
|
-
const
|
|
2730
|
-
|
|
2964
|
+
const vib = !!vibrato && dMs / 1e3 >= VIBRATO_MIN_SEC;
|
|
2965
|
+
const r = await renderInto(alias, pitch, dMs, vib, expr);
|
|
2966
|
+
return r ? keyOf(alias, pitch, dMs, vib, expr) : null;
|
|
2731
2967
|
};
|
|
2732
|
-
model.scheduleCached = (key, t0, peak, pan) => {
|
|
2968
|
+
model.scheduleCached = (key, t0, peak, pan, reverbSend, dest) => {
|
|
2733
2969
|
const r = renderCache.get(key);
|
|
2734
|
-
if (r) schedule(r, t0, peak, pan);
|
|
2970
|
+
if (r) schedule(r, t0, peak, pan, reverbSend, dest);
|
|
2735
2971
|
};
|
|
2736
2972
|
model.stopAll = () => {
|
|
2737
2973
|
for (const src of active) {
|
|
@@ -2762,7 +2998,7 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2762
2998
|
const masterGain = ctx.createGain();
|
|
2763
2999
|
masterGain.connect(destination);
|
|
2764
3000
|
const loaded = /* @__PURE__ */ new Map([
|
|
2765
|
-
[FALLBACK_MODEL, createKlattVoice(ctx, masterGain)]
|
|
3001
|
+
[FALLBACK_MODEL, createKlattVoice(ctx, masterGain, options.reverbBus)]
|
|
2766
3002
|
]);
|
|
2767
3003
|
const loading = /* @__PURE__ */ new Map();
|
|
2768
3004
|
const load2 = (model) => {
|
|
@@ -2782,7 +3018,8 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2782
3018
|
koe,
|
|
2783
3019
|
worldlineScriptUrl: options.worldlineScriptUrl,
|
|
2784
3020
|
lightweight: options.lightweight,
|
|
2785
|
-
voiceWorkerUrl: options.voiceWorkerUrl
|
|
3021
|
+
voiceWorkerUrl: options.voiceWorkerUrl,
|
|
3022
|
+
reverbBus: options.reverbBus
|
|
2786
3023
|
})
|
|
2787
3024
|
))().then((v) => {
|
|
2788
3025
|
loaded.set(m, v);
|
|
@@ -2824,10 +3061,14 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2824
3061
|
const m = loaded.get(track.model.toLowerCase());
|
|
2825
3062
|
if (!m?.renderToCache) continue;
|
|
2826
3063
|
let n = 0;
|
|
3064
|
+
const expr = {
|
|
3065
|
+
gender: track.gender,
|
|
3066
|
+
breathiness: track.breathiness
|
|
3067
|
+
};
|
|
2827
3068
|
forEachSungNote(track, (note, prevVowel) => {
|
|
2828
3069
|
if (n >= count && note.startSec >= STREAM_LOOKAHEAD_SEC) return;
|
|
2829
3070
|
n++;
|
|
2830
|
-
tasks.push({ model: m, note, prevVowel });
|
|
3071
|
+
tasks.push({ model: m, note, prevVowel, vibrato: track.vibrato, expr });
|
|
2831
3072
|
});
|
|
2832
3073
|
}
|
|
2833
3074
|
const total = tasks.length;
|
|
@@ -2842,7 +3083,9 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2842
3083
|
task.note.syllable,
|
|
2843
3084
|
task.prevVowel,
|
|
2844
3085
|
task.note.pitch,
|
|
2845
|
-
task.note.durationSec * 1e3
|
|
3086
|
+
task.note.durationSec * 1e3,
|
|
3087
|
+
task.vibrato,
|
|
3088
|
+
task.expr
|
|
2846
3089
|
) ?? Promise.resolve(null));
|
|
2847
3090
|
done++;
|
|
2848
3091
|
onProgress?.(done, total);
|
|
@@ -2887,13 +3130,22 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2887
3130
|
note.syllable,
|
|
2888
3131
|
prevVowel,
|
|
2889
3132
|
note.pitch,
|
|
2890
|
-
note.durationSec * 1e3
|
|
3133
|
+
note.durationSec * 1e3,
|
|
3134
|
+
track.vibrato,
|
|
3135
|
+
{ gender: track.gender, breathiness: track.breathiness }
|
|
2891
3136
|
);
|
|
2892
3137
|
if (session !== streamSession) return;
|
|
2893
3138
|
if (key) {
|
|
2894
3139
|
const delay = ctx.currentTime - t0;
|
|
2895
3140
|
if (delay < 0.05) {
|
|
2896
|
-
scheduleCached(
|
|
3141
|
+
scheduleCached(
|
|
3142
|
+
key,
|
|
3143
|
+
t0,
|
|
3144
|
+
peak,
|
|
3145
|
+
track.pan,
|
|
3146
|
+
track.reverbSend,
|
|
3147
|
+
options.getTrackDestination?.(track.id ?? "")
|
|
3148
|
+
);
|
|
2897
3149
|
opts?.onScheduled?.(track, note, t0);
|
|
2898
3150
|
} else {
|
|
2899
3151
|
console.warn(
|
|
@@ -2906,13 +3158,15 @@ var createSingingVoices = (ctx, destination, options = {}) => {
|
|
|
2906
3158
|
} else {
|
|
2907
3159
|
const when = t0 - ctx.currentTime;
|
|
2908
3160
|
model(note.syllable, {
|
|
2909
|
-
trackId: "",
|
|
3161
|
+
trackId: track.id ?? "",
|
|
2910
3162
|
pitch: note.pitch,
|
|
2911
3163
|
velocity: 100,
|
|
2912
3164
|
volume: peak,
|
|
2913
3165
|
when,
|
|
2914
3166
|
duration: note.durationSec,
|
|
2915
|
-
pan: track.pan
|
|
3167
|
+
pan: track.pan,
|
|
3168
|
+
reverbSend: track.reverbSend,
|
|
3169
|
+
destination: options.getTrackDestination?.(track.id ?? "")
|
|
2916
3170
|
});
|
|
2917
3171
|
opts?.onScheduled?.(track, note, t0);
|
|
2918
3172
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
@@ -2971,8 +3225,10 @@ var PITCH_MAP = {
|
|
|
2971
3225
|
b: 11
|
|
2972
3226
|
};
|
|
2973
3227
|
var clamp2 = (value, lo, hi) => Math.min(hi, Math.max(lo, value));
|
|
2974
|
-
var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|mode)=([\w-]+)/gi;
|
|
3228
|
+
var META_DIRECTIVE = /#(inst|drum|drumfont|volume|drumvolume|reverb|mode)=([\w-]+)/gi;
|
|
2975
3229
|
var TRACK_INST_DIRECTIVE = /#t(\d+)inst=([^#;\r\n]+)/gi;
|
|
3230
|
+
var TRACK_COMP_DIRECTIVE = /#t(\d+)comp=(\d+)/gi;
|
|
3231
|
+
var TRACK_WIDTH_DIRECTIVE = /#t(\d+)width=(\d+)/gi;
|
|
2976
3232
|
var parseMmlMeta = (mml) => {
|
|
2977
3233
|
const meta = {};
|
|
2978
3234
|
for (const m of mml.matchAll(META_DIRECTIVE)) {
|
|
@@ -2986,6 +3242,9 @@ var parseMmlMeta = (mml) => {
|
|
|
2986
3242
|
} else if (key === "drumvolume") {
|
|
2987
3243
|
const dv = Number.parseInt(m[2], 10);
|
|
2988
3244
|
if (!Number.isNaN(dv)) meta.drumVolume = dv;
|
|
3245
|
+
} else if (key === "reverb") {
|
|
3246
|
+
const rv = Number.parseInt(m[2], 10);
|
|
3247
|
+
if (!Number.isNaN(rv)) meta.reverb = clamp2(rv, 0, 100);
|
|
2989
3248
|
} else if (key === "mode") {
|
|
2990
3249
|
if (m[2] === "simple" || m[2] === "advanced") {
|
|
2991
3250
|
meta.mode = m[2];
|
|
@@ -3000,9 +3259,25 @@ var parseMmlMeta = (mml) => {
|
|
|
3000
3259
|
meta.trackInstruments[idx] = name;
|
|
3001
3260
|
}
|
|
3002
3261
|
}
|
|
3262
|
+
for (const m of mml.matchAll(TRACK_COMP_DIRECTIVE)) {
|
|
3263
|
+
const idx = Number.parseInt(m[1], 10);
|
|
3264
|
+
const val = clamp2(Number.parseInt(m[2], 10), 0, 100);
|
|
3265
|
+
if (!Number.isNaN(idx) && !Number.isNaN(val)) {
|
|
3266
|
+
meta.trackCompression ??= {};
|
|
3267
|
+
meta.trackCompression[idx] = val;
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
for (const m of mml.matchAll(TRACK_WIDTH_DIRECTIVE)) {
|
|
3271
|
+
const idx = Number.parseInt(m[1], 10);
|
|
3272
|
+
const val = clamp2(Number.parseInt(m[2], 10), 0, 200);
|
|
3273
|
+
if (!Number.isNaN(idx) && !Number.isNaN(val)) {
|
|
3274
|
+
meta.trackWidth ??= {};
|
|
3275
|
+
meta.trackWidth[idx] = val;
|
|
3276
|
+
}
|
|
3277
|
+
}
|
|
3003
3278
|
return meta;
|
|
3004
3279
|
};
|
|
3005
|
-
var stripMmlMeta = (mml) => mml.replace(META_DIRECTIVE, "").replace(TRACK_INST_DIRECTIVE, "");
|
|
3280
|
+
var stripMmlMeta = (mml) => mml.replace(META_DIRECTIVE, "").replace(TRACK_INST_DIRECTIVE, "").replace(TRACK_COMP_DIRECTIVE, "").replace(TRACK_WIDTH_DIRECTIVE, "");
|
|
3006
3281
|
var formatMmlMeta = (meta, space = "") => {
|
|
3007
3282
|
const parts = [];
|
|
3008
3283
|
if (meta.instrument) parts.push(`#inst=${meta.instrument}`);
|
|
@@ -3011,12 +3286,24 @@ var formatMmlMeta = (meta, space = "") => {
|
|
|
3011
3286
|
if (meta.volume !== void 0) parts.push(`#volume=${meta.volume}`);
|
|
3012
3287
|
if (meta.drumVolume !== void 0)
|
|
3013
3288
|
parts.push(`#drumvolume=${meta.drumVolume}`);
|
|
3289
|
+
if (meta.reverb !== void 0 && meta.reverb !== 0)
|
|
3290
|
+
parts.push(`#reverb=${meta.reverb}`);
|
|
3014
3291
|
if (meta.mode) parts.push(`#mode=${meta.mode}`);
|
|
3015
3292
|
if (meta.trackInstruments) {
|
|
3016
3293
|
for (const [idx, name] of Object.entries(meta.trackInstruments)) {
|
|
3017
3294
|
if (name) parts.push(`#t${idx}inst=${name}`);
|
|
3018
3295
|
}
|
|
3019
3296
|
}
|
|
3297
|
+
if (meta.trackCompression) {
|
|
3298
|
+
for (const [idx, val] of Object.entries(meta.trackCompression)) {
|
|
3299
|
+
if (val !== 0) parts.push(`#t${idx}comp=${val}`);
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
if (meta.trackWidth) {
|
|
3303
|
+
for (const [idx, val] of Object.entries(meta.trackWidth)) {
|
|
3304
|
+
if (val !== 100) parts.push(`#t${idx}width=${val}`);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3020
3307
|
return parts.join(space);
|
|
3021
3308
|
};
|
|
3022
3309
|
var parseMML = (mml, options = {}) => {
|
|
@@ -5773,7 +6060,7 @@ var createSynth = (ctx, destination = ctx.destination, tone = {}) => {
|
|
|
5773
6060
|
const length = Math.max(1, Math.floor(ctx.sampleRate * dur));
|
|
5774
6061
|
const buffer = ctx.createBuffer(1, length, ctx.sampleRate);
|
|
5775
6062
|
const data = buffer.getChannelData(0);
|
|
5776
|
-
for (let
|
|
6063
|
+
for (let i2 = 0; i2 < length; i2++) data[i2] = Math.random() * 2 - 1;
|
|
5777
6064
|
const src = ctx.createBufferSource();
|
|
5778
6065
|
src.buffer = buffer;
|
|
5779
6066
|
const filter = ctx.createBiquadFilter();
|
|
@@ -6758,6 +7045,23 @@ var DAW_CSS = `
|
|
|
6758
7045
|
@keyframes dtm-blink { 0%,100%{opacity:1} 50%{opacity:0} }
|
|
6759
7046
|
.dtm-blink { animation: dtm-blink 1s steps(1) infinite; }
|
|
6760
7047
|
|
|
7048
|
+
/* \u2500\u2500\u2500 \u97F3\u5272\u308C\u691C\u77E5\u30D0\u30C3\u30B8 \u2500\u2500\u2500 \u30AF\u30EA\u30C3\u30D7\u767A\u751F\u4E2D\u3060\u3051\u8868\u793A\u3055\u308C\u308B\u8B66\u544A\u30DC\u30BF\u30F3\u3002\u30AF\u30EA\u30C3\u30AF\u3067\u6D88\u305B\u308B\u3002 */
|
|
7049
|
+
.dtm-clip-badge {
|
|
7050
|
+
flex: 0 0 auto;
|
|
7051
|
+
min-height: 24px;
|
|
7052
|
+
padding: 0 8px;
|
|
7053
|
+
border: 2px solid var(--c-black);
|
|
7054
|
+
background: var(--dtm-danger);
|
|
7055
|
+
color: var(--c-white);
|
|
7056
|
+
font-family: var(--dtm-font);
|
|
7057
|
+
font-size: 10px;
|
|
7058
|
+
letter-spacing: .1em;
|
|
7059
|
+
cursor: pointer;
|
|
7060
|
+
box-shadow: 0 0 0 2px var(--dtm-danger), 2px 2px 0 var(--c-black);
|
|
7061
|
+
animation: dtm-blink .5s steps(1) infinite;
|
|
7062
|
+
}
|
|
7063
|
+
.dtm-clip-badge:active { transform: translate(2px,2px); box-shadow: none; }
|
|
7064
|
+
|
|
6761
7065
|
/* \u2500\u2500\u2500 \u30A4\u30F3\u30D5\u30A9\u30DC\u30BF\u30F3 \u2500\u2500\u2500 */
|
|
6762
7066
|
.dtm-infobtn {
|
|
6763
7067
|
display: inline-flex;
|
|
@@ -7033,6 +7337,37 @@ var DAW_CSS = `
|
|
|
7033
7337
|
object-fit: cover;
|
|
7034
7338
|
image-rendering: pixelated;
|
|
7035
7339
|
}
|
|
7340
|
+
/* \u6B4C\u8A5E\u30C8\u30E9\u30C3\u30AF\u306E\u300C\u8A73\u7D30\u8A2D\u5B9A\u300D\u2014 \u5E38\u7528\u3057\u306A\u3044\u30D1\u30E9\u30E1\u30FC\u30BF\uFF08\u30AA\u30AF\u30BF\u30FC\u30D6/\u5B9A\u4F4D/\u30EA\u30D0\u30FC\u30D6\u9001\u308A/
|
|
7341
|
+
\u30B8\u30A7\u30F3\u30C0\u30FC/\u30D6\u30EC\u30B7\u30CD\u30B9/\u30D3\u30D6\u30E9\u30FC\u30C8\uFF09\u3092\u7573\u3093\u3067\u304A\u304F\u8EFD\u91CF\u306A details\u3002dtm-panel \u307B\u3069
|
|
7342
|
+
\u4EF0\u3005\u3057\u304F\u305B\u305A\u3001\u63A7\u3048\u3081\u306A\u4ED5\u5207\u308A\u7DDA\uFF0B\u5C0F\u3055\u3044\u25B6\u30DE\u30FC\u30AB\u30FC\u3060\u3051\u4ED8\u3051\u308B\u3002 */
|
|
7343
|
+
.dtm-advanced {
|
|
7344
|
+
border-top: 1px dashed var(--dtm-border2);
|
|
7345
|
+
padding-top: 6px;
|
|
7346
|
+
display: flex;
|
|
7347
|
+
flex-direction: column;
|
|
7348
|
+
gap: 6px;
|
|
7349
|
+
}
|
|
7350
|
+
.dtm-advanced > summary {
|
|
7351
|
+
list-style: none;
|
|
7352
|
+
cursor: pointer;
|
|
7353
|
+
font-size: 11px;
|
|
7354
|
+
letter-spacing: .08em;
|
|
7355
|
+
color: var(--dtm-text);
|
|
7356
|
+
display: flex;
|
|
7357
|
+
align-items: center;
|
|
7358
|
+
gap: 6px;
|
|
7359
|
+
min-height: 28px;
|
|
7360
|
+
padding: 0 8px;
|
|
7361
|
+
border: 2px solid var(--dtm-border2);
|
|
7362
|
+
background: var(--dtm-deep);
|
|
7363
|
+
box-shadow: 2px 2px 0 var(--c-black);
|
|
7364
|
+
width: fit-content;
|
|
7365
|
+
}
|
|
7366
|
+
.dtm-advanced > summary:active { transform: translate(2px,2px); box-shadow: none; }
|
|
7367
|
+
.dtm-advanced > summary::-webkit-details-marker { display: none; }
|
|
7368
|
+
.dtm-advanced > summary::before { content: "\u25B6"; font-size: 9px; color: var(--dtm-accent); }
|
|
7369
|
+
.dtm-advanced[open] > summary::before { content: "\u25BC"; }
|
|
7370
|
+
.dtm-advanced[open] > summary { border-color: var(--dtm-primary); color: var(--dtm-primary); }
|
|
7036
7371
|
|
|
7037
7372
|
/* \u2500\u2500\u2500 \u5E83\u5E45\u62E1\u5F35 \u2500\u2500\u2500 */
|
|
7038
7373
|
@media (min-width: 768px) {
|
|
@@ -7694,6 +8029,9 @@ var teto_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAA
|
|
|
7694
8029
|
// assets/tsukuyomi.png
|
|
7695
8030
|
var tsukuyomi_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAB3UlEQVR42tWXPUsDQRCGnwuijYIoFqKmEDSCxIgIgqnsogbsrC3ERiwN4g8Ikk6sFH+BnYofvcTKxoigBCzEYGGjWIiCOYvNBHe5TdQUt051czc3e++zO7tzHnUst7vn04BlFue9Ws8jhGxN9ZTPzU43NkIlj41E6AQ8m/JYfByAoWgXAPtHJzRCRN43SbizBkzlv1X2VzLuVoHYzf0TAMnys+aLCTGThMTJGnKfQOpyWF1cvgHQsh4FYPDzRd3vmQHgoPShJbi9uqhJyPk1UK3Jwsq1/115rLst8AX/4UFP0NsbGHf7+Kr579l7zR/ZGvbcrAJR7vvqEOwcTdZMYIuTPCYJUS7Ewydgzn2Bay2gdWzqR4nMuMPlhcC5l/HcWQOnCaU4lVU3xI9tnwFQnOgDoDmdDs5QKmlxYhdGmBA2ibhTBfKFHCkCm00dAKymJn+USAidHx8DkI+0q7PBUC7j5BJ7jlSB7RyXziVT8fM7Oz7AeLmsz3VEaWi7UvtAcmvJC+qmq4T/XT8gdTsw2692to07AF7jeU35wFq/7COqzhdVnVOnu3aHgNm1VpVXlImJX9zQffO5kDg1dlb3CNj6dZsVK2vAVP7Xf8bwCfxWuc23Eanmt/xlh07gC6oBviFE8rZHAAAAAElFTkSuQmCC";
|
|
7696
8031
|
|
|
8032
|
+
// assets/uc.png
|
|
8033
|
+
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==";
|
|
8034
|
+
|
|
7697
8035
|
// src/voice-images.ts
|
|
7698
8036
|
var VOICE_IMAGES = {
|
|
7699
8037
|
puyuyu: puyuyu_default,
|
|
@@ -7706,7 +8044,8 @@ var VOICE_IMAGES = {
|
|
|
7706
8044
|
rei: rei_default,
|
|
7707
8045
|
MGRoid: MGRoid_default,
|
|
7708
8046
|
MOTRoid: MOTRoid_default,
|
|
7709
|
-
NYNRoid: NYNRoid_default
|
|
8047
|
+
NYNRoid: NYNRoid_default,
|
|
8048
|
+
uc: uc_default
|
|
7710
8049
|
};
|
|
7711
8050
|
var FALLBACK_VOCAL_ICON = Chip_default;
|
|
7712
8051
|
|
|
@@ -7768,8 +8107,8 @@ var copyToClipboard = async (doc, text) => {
|
|
|
7768
8107
|
};
|
|
7769
8108
|
var toBase64Url = (bytes) => {
|
|
7770
8109
|
let bin = "";
|
|
7771
|
-
for (let
|
|
7772
|
-
bin += String.fromCharCode(bytes[
|
|
8110
|
+
for (let i2 = 0; i2 < bytes.length; i2++) {
|
|
8111
|
+
bin += String.fromCharCode(bytes[i2]);
|
|
7773
8112
|
}
|
|
7774
8113
|
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
7775
8114
|
};
|
|
@@ -7782,8 +8121,8 @@ var SHIFT_KATAKANA = 255;
|
|
|
7782
8121
|
var VALUE_PROLONGED = 223;
|
|
7783
8122
|
var customEncode = (str) => {
|
|
7784
8123
|
const bytes = [];
|
|
7785
|
-
for (let
|
|
7786
|
-
const code = str.charCodeAt(
|
|
8124
|
+
for (let i2 = 0; i2 < str.length; i2++) {
|
|
8125
|
+
const code = str.charCodeAt(i2);
|
|
7787
8126
|
if (code === 32) {
|
|
7788
8127
|
continue;
|
|
7789
8128
|
}
|
|
@@ -7825,37 +8164,37 @@ var fromBase64Url = (s) => {
|
|
|
7825
8164
|
}
|
|
7826
8165
|
const bin = atob(normalized);
|
|
7827
8166
|
const bytes = new Uint8Array(bin.length);
|
|
7828
|
-
for (let
|
|
7829
|
-
bytes[
|
|
8167
|
+
for (let i2 = 0; i2 < bin.length; i2++) {
|
|
8168
|
+
bytes[i2] = bin.charCodeAt(i2);
|
|
7830
8169
|
}
|
|
7831
8170
|
return bytes;
|
|
7832
8171
|
};
|
|
7833
8172
|
var customDecode = (bytes) => {
|
|
7834
8173
|
let str = "";
|
|
7835
|
-
let
|
|
7836
|
-
while (
|
|
7837
|
-
const byte = bytes[
|
|
8174
|
+
let i2 = 0;
|
|
8175
|
+
while (i2 < bytes.length) {
|
|
8176
|
+
const byte = bytes[i2];
|
|
7838
8177
|
if (byte <= 127) {
|
|
7839
8178
|
str += String.fromCharCode(byte);
|
|
7840
|
-
|
|
8179
|
+
i2++;
|
|
7841
8180
|
} else if (byte === VALUE_PROLONGED) {
|
|
7842
8181
|
str += String.fromCharCode(PROLONGED_MARK);
|
|
7843
|
-
|
|
8182
|
+
i2++;
|
|
7844
8183
|
} else if (byte >= 128 && byte <= 222) {
|
|
7845
8184
|
str += String.fromCharCode(HIRAGANA_START + (byte - 128));
|
|
7846
|
-
|
|
8185
|
+
i2++;
|
|
7847
8186
|
} else if (byte === SHIFT_KATAKANA) {
|
|
7848
|
-
if (
|
|
7849
|
-
const nextByte = bytes[
|
|
8187
|
+
if (i2 + 1 < bytes.length) {
|
|
8188
|
+
const nextByte = bytes[i2 + 1];
|
|
7850
8189
|
if (nextByte >= 128 && nextByte <= 222) {
|
|
7851
8190
|
str += String.fromCharCode(HIRAGANA_START + 96 + (nextByte - 128));
|
|
7852
8191
|
}
|
|
7853
|
-
|
|
8192
|
+
i2 += 2;
|
|
7854
8193
|
} else {
|
|
7855
|
-
|
|
8194
|
+
i2++;
|
|
7856
8195
|
}
|
|
7857
8196
|
} else {
|
|
7858
|
-
|
|
8197
|
+
i2++;
|
|
7859
8198
|
}
|
|
7860
8199
|
}
|
|
7861
8200
|
return str;
|
|
@@ -8420,7 +8759,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8420
8759
|
const beatRow = doc.createElement("div");
|
|
8421
8760
|
beatRow.className = "dtm-player-beat-row";
|
|
8422
8761
|
const beatDots = [];
|
|
8423
|
-
for (let
|
|
8762
|
+
for (let i2 = 0; i2 < 4; i2++) {
|
|
8424
8763
|
const d = doc.createElement("span");
|
|
8425
8764
|
d.className = "dtm-player-beat-dot";
|
|
8426
8765
|
beatRow.appendChild(d);
|
|
@@ -8524,9 +8863,9 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8524
8863
|
lane.appendChild(metaEl);
|
|
8525
8864
|
}
|
|
8526
8865
|
const count = Math.min(notes.length, lyricTrack.syllables.length);
|
|
8527
|
-
for (let
|
|
8528
|
-
const note = notes[
|
|
8529
|
-
if (breaks.has(
|
|
8866
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
8867
|
+
const note = notes[i2];
|
|
8868
|
+
if (breaks.has(i2)) {
|
|
8530
8869
|
const br = doc.createElement("span");
|
|
8531
8870
|
br.className = "dtm-tk dtm-tk--break";
|
|
8532
8871
|
br.textContent = "\\n";
|
|
@@ -8534,7 +8873,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8534
8873
|
}
|
|
8535
8874
|
const span = doc.createElement("span");
|
|
8536
8875
|
span.className = "dtm-tk dtm-tk--lyric";
|
|
8537
|
-
span.textContent = lyricTrack.syllables[
|
|
8876
|
+
span.textContent = lyricTrack.syllables[i2].kana;
|
|
8538
8877
|
lane.appendChild(span);
|
|
8539
8878
|
laneTokens.push({
|
|
8540
8879
|
el: span,
|
|
@@ -8687,8 +9026,8 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8687
9026
|
const intStep = Math.floor(step);
|
|
8688
9027
|
playStep = intStep;
|
|
8689
9028
|
const beatIndex = Math.floor(step / STEPS_PER_BEAT2) % 4;
|
|
8690
|
-
for (let
|
|
8691
|
-
beatDots[
|
|
9029
|
+
for (let i2 = 0; i2 < 4; i2++)
|
|
9030
|
+
beatDots[i2].classList.toggle("dtm-player-beat-dot--on", i2 === beatIndex);
|
|
8692
9031
|
barEl.textContent = String(Math.floor(step / STEPS_PER_BAR2) + 1);
|
|
8693
9032
|
if (!isSeeking) {
|
|
8694
9033
|
seekInput.value = String(Math.min(maxStep, Math.max(0, intStep)));
|
|
@@ -8783,11 +9122,11 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8783
9122
|
const semis = (lt.octave ?? 0) * 12;
|
|
8784
9123
|
const count = Math.min(sorted.length, lt.syllables.length);
|
|
8785
9124
|
const notes = [];
|
|
8786
|
-
for (let
|
|
8787
|
-
const n = sorted[
|
|
9125
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
9126
|
+
const n = sorted[i2];
|
|
8788
9127
|
if (n.startStep < fromStep) continue;
|
|
8789
9128
|
notes.push({
|
|
8790
|
-
syllable: lt.syllables[
|
|
9129
|
+
syllable: lt.syllables[i2],
|
|
8791
9130
|
pitch: n.pitch + semis,
|
|
8792
9131
|
startSec: (n.startStep - fromStep) * secondsPerStep,
|
|
8793
9132
|
durationSec: n.durationSteps * secondsPerStep * gate
|
|
@@ -8798,6 +9137,10 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
8798
9137
|
model: lt.model,
|
|
8799
9138
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
8800
9139
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
9140
|
+
vibrato: lt.vibrato,
|
|
9141
|
+
reverbSend: (lt.reverb ?? 0) / 100,
|
|
9142
|
+
gender: (lt.gender ?? 50) / 100,
|
|
9143
|
+
breathiness: (lt.breathiness ?? 50) / 100,
|
|
8801
9144
|
notes
|
|
8802
9145
|
};
|
|
8803
9146
|
});
|
|
@@ -9057,13 +9400,13 @@ var findZone = (ctx, fontName, zones, pitchs = []) => {
|
|
|
9057
9400
|
for (const zone of zones) {
|
|
9058
9401
|
const low = zone.keyRangeLow | 0, high = zone.keyRangeHigh | 0;
|
|
9059
9402
|
if (low > high) continue;
|
|
9060
|
-
for (let
|
|
9403
|
+
for (let i2 = low; i2 <= high; i2++) pitchs.push(i2);
|
|
9061
9404
|
}
|
|
9062
9405
|
const set = new Set(pitchs);
|
|
9063
9406
|
const map = new Map(pitchs.map((v) => [v, zones[0]]));
|
|
9064
|
-
for (let
|
|
9407
|
+
for (let i2 = zones.length - 1; i2 >= 0; i2--)
|
|
9065
9408
|
for (const v of set) {
|
|
9066
|
-
const zone = zones[
|
|
9409
|
+
const zone = zones[i2];
|
|
9067
9410
|
if (v < zone.keyRangeLow || v > zone.keyRangeHigh) continue;
|
|
9068
9411
|
set.delete(v);
|
|
9069
9412
|
map.set(v, { ...zone });
|
|
@@ -9093,13 +9436,13 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9093
9436
|
const decoded = atob(zone.sample);
|
|
9094
9437
|
zone.buffer = ctx.createBuffer(1, decoded.length / 2, zone.sampleRate);
|
|
9095
9438
|
const a = zone.buffer.getChannelData(0);
|
|
9096
|
-
for (let
|
|
9097
|
-
let b1 = decoded.charCodeAt(
|
|
9439
|
+
for (let i2 = 0; i2 < decoded.length / 2; i2++) {
|
|
9440
|
+
let b1 = decoded.charCodeAt(i2 * 2), b2 = decoded.charCodeAt(i2 * 2 + 1);
|
|
9098
9441
|
if (b1 < 0) b1 = 256 + b1;
|
|
9099
9442
|
if (b2 < 0) b2 = 256 + b2;
|
|
9100
9443
|
let n = b2 * 256 + b1;
|
|
9101
9444
|
if (n >= 65536 / 2) n = n - 65536;
|
|
9102
|
-
a[
|
|
9445
|
+
a[i2] = n / 65536;
|
|
9103
9446
|
}
|
|
9104
9447
|
} else if (zone.file) {
|
|
9105
9448
|
const bytes = Uint8Array.from(atob(zone.file), (c) => c.charCodeAt(0));
|
|
@@ -9139,10 +9482,10 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9139
9482
|
let loopPeak = 0;
|
|
9140
9483
|
if (oldBuf.numberOfChannels > 0) {
|
|
9141
9484
|
const ch0 = oldBuf.getChannelData(0);
|
|
9142
|
-
for (let
|
|
9143
|
-
const abs = Math.abs(ch0[
|
|
9485
|
+
for (let i2 = 0; i2 < ch0.length; i2++) {
|
|
9486
|
+
const abs = Math.abs(ch0[i2]);
|
|
9144
9487
|
if (abs > totalPeak) totalPeak = abs;
|
|
9145
|
-
if (
|
|
9488
|
+
if (i2 >= loopStartFrame && i2 < loopEndFrame) {
|
|
9146
9489
|
if (abs > loopPeak) loopPeak = abs;
|
|
9147
9490
|
}
|
|
9148
9491
|
}
|
|
@@ -9161,16 +9504,16 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9161
9504
|
for (let ch = 0; ch < oldBuf.numberOfChannels; ch++) {
|
|
9162
9505
|
const oldData = oldBuf.getChannelData(ch);
|
|
9163
9506
|
const newData = newBuf.getChannelData(ch);
|
|
9164
|
-
for (let
|
|
9165
|
-
const ratio = attackLength > 1 ?
|
|
9507
|
+
for (let i2 = 0; i2 < attackLength; i2++) {
|
|
9508
|
+
const ratio = attackLength > 1 ? i2 / (attackLength - 1) : 0;
|
|
9166
9509
|
const m = 1 + (gainMultiplier - 1) * ratio;
|
|
9167
|
-
newData[
|
|
9510
|
+
newData[i2] = oldData[i2] * m;
|
|
9168
9511
|
}
|
|
9169
9512
|
let offset = attackLength;
|
|
9170
9513
|
const loopData = oldData.subarray(loopStartFrame, loopEndFrame);
|
|
9171
9514
|
const normalizedLoopData = new Float32Array(loopLengthFrame);
|
|
9172
|
-
for (let
|
|
9173
|
-
normalizedLoopData[
|
|
9515
|
+
for (let i2 = 0; i2 < loopLengthFrame; i2++) {
|
|
9516
|
+
normalizedLoopData[i2] = loopData[i2] * gainMultiplier;
|
|
9174
9517
|
}
|
|
9175
9518
|
for (let r = 0; r < repeatCount; r++) {
|
|
9176
9519
|
newData.set(normalizedLoopData, offset);
|
|
@@ -9180,8 +9523,8 @@ var adjustZone = async (ctx, fontName, zone) => {
|
|
|
9180
9523
|
const releaseData = oldData.subarray(loopEndFrame);
|
|
9181
9524
|
if (gainMultiplier !== 1) {
|
|
9182
9525
|
const normalizedRelease = new Float32Array(releaseLength);
|
|
9183
|
-
for (let
|
|
9184
|
-
normalizedRelease[
|
|
9526
|
+
for (let i2 = 0; i2 < releaseLength; i2++) {
|
|
9527
|
+
normalizedRelease[i2] = releaseData[i2] * gainMultiplier;
|
|
9185
9528
|
}
|
|
9186
9529
|
newData.set(normalizedRelease, offset);
|
|
9187
9530
|
} else {
|
|
@@ -9377,10 +9720,10 @@ var buildDisplayLines = (chords, eventsCount) => {
|
|
|
9377
9720
|
if (segments.length === 0) continue;
|
|
9378
9721
|
const hasMultiSeg = segments.length > 1;
|
|
9379
9722
|
const parts = [];
|
|
9380
|
-
for (let
|
|
9381
|
-
if (hasMultiSeg &&
|
|
9723
|
+
for (let i2 = 0; i2 < segments.length; i2++) {
|
|
9724
|
+
if (hasMultiSeg && i2 > 0)
|
|
9382
9725
|
parts.push({ text: "|", isChord: false, eventIdx: -1 });
|
|
9383
|
-
const bar = segments[
|
|
9726
|
+
const bar = segments[i2].trim();
|
|
9384
9727
|
if (!bar) continue;
|
|
9385
9728
|
const splitAt = [];
|
|
9386
9729
|
for (let j = 0; j < bar.length; j++) {
|
|
@@ -10499,6 +10842,7 @@ var buildUI = (target, options) => {
|
|
|
10499
10842
|
<button class="dtm-iconbtn" data-dtm="next-bar" title="1\u5C0F\u7BC0\u5F8C">${icon("chevronRight")}</button>
|
|
10500
10843
|
<label class="dtm-toggle"><input type="checkbox" data-dtm="solo"><span>\u30BD\u30ED</span></label>
|
|
10501
10844
|
<span class="dtm-topbar-loading dtm-blink" data-dtm="topbar-loading">... LOADING ...</span>
|
|
10845
|
+
<button class="dtm-clip-badge dtm-hidden" data-dtm="clip-badge" title="\u97F3\u5272\u308C\u691C\u77E5\uFF08\u30AF\u30EA\u30C3\u30AF\u3067\u6D88\u3059\uFF09">CLIP</button>
|
|
10502
10846
|
<span class="dtm-grow"></span>
|
|
10503
10847
|
<span class="dtm-label">BPM</span>
|
|
10504
10848
|
<input type="number" class="dtm-input dtm-input--num" data-dtm="bpm" value="${defaultBpm}" min="20" max="300">
|
|
@@ -10536,13 +10880,8 @@ var buildUI = (target, options) => {
|
|
|
10536
10880
|
<div class="dtm-hscroll" data-dtm="hscroll"><div class="dtm-hscroll-thumb" data-dtm="hscroll-thumb"></div></div>
|
|
10537
10881
|
|
|
10538
10882
|
<details class="dtm-panel" open>
|
|
10539
|
-
<summary>\u30C8\u30E9\u30C3\u30AF\u8A2D\u5B9A</summary>
|
|
10883
|
+
<summary>\u500B\u5225\u30C8\u30E9\u30C3\u30AF\u8A2D\u5B9A</summary>
|
|
10540
10884
|
<div class="dtm-panel-body">
|
|
10541
|
-
<div class="dtm-row">
|
|
10542
|
-
<span class="dtm-label">\u5168\u4F53\u97F3\u91CF</span>
|
|
10543
|
-
<input type="range" class="dtm-range dtm-grow" data-dtm="master-volume" value="50" min="0" max="100">
|
|
10544
|
-
<span class="dtm-label" data-dtm="master-volume-label">50%</span>
|
|
10545
|
-
</div>
|
|
10546
10885
|
<div class="dtm-track-body" data-dtm="track-body"></div>
|
|
10547
10886
|
</div>
|
|
10548
10887
|
</details>
|
|
@@ -10575,6 +10914,29 @@ var buildUI = (target, options) => {
|
|
|
10575
10914
|
</div>
|
|
10576
10915
|
</details>
|
|
10577
10916
|
|
|
10917
|
+
<details class="dtm-panel" open>
|
|
10918
|
+
<summary>\u5168\u4F53\u30C8\u30E9\u30C3\u30AF\u8A2D\u5B9A</summary>
|
|
10919
|
+
<div class="dtm-panel-body">
|
|
10920
|
+
<div data-dtm="preset-select-slot"></div>
|
|
10921
|
+
<div class="dtm-row">
|
|
10922
|
+
<span class="dtm-label">\u5168\u4F53\u97F3\u91CF</span>
|
|
10923
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="master-volume" value="50" min="0" max="100">
|
|
10924
|
+
<span class="dtm-label" data-dtm="master-volume-label">50%</span>
|
|
10925
|
+
</div>
|
|
10926
|
+
<div class="dtm-row">
|
|
10927
|
+
<button class="dtm-btn dtm-btn--ghost dtm-btn--xs" data-dtm="auto-master" title="\u97F3\u5727\u30FB\u30B9\u30C6\u30EC\u30AA\u5E45\u30FB\u30EA\u30D0\u30FC\u30D6\u3092\u5546\u696D\u66F2\u5BC4\u308A\u306E\u5024\u306B\u4E00\u62EC\u8A2D\u5B9A\u3057\u307E\u3059">\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0</button>
|
|
10928
|
+
<button class="dtm-infobtn" data-dtm="auto-master-info" title="\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
10929
|
+
<span class="dtm-grow"></span>
|
|
10930
|
+
</div>
|
|
10931
|
+
<div class="dtm-row">
|
|
10932
|
+
<span class="dtm-label">\u30EA\u30D0\u30FC\u30D6</span>
|
|
10933
|
+
<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">
|
|
10934
|
+
<span class="dtm-label" data-dtm="reverb-amount-label">0%</span>
|
|
10935
|
+
<button class="dtm-infobtn" data-dtm="reverb-amount-info" title="\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
10936
|
+
</div>
|
|
10937
|
+
</div>
|
|
10938
|
+
</details>
|
|
10939
|
+
|
|
10578
10940
|
<details class="dtm-panel">
|
|
10579
10941
|
<summary>\u30C9\u30E9\u30E0\u8A2D\u5B9A</summary>
|
|
10580
10942
|
<div class="dtm-panel-body">
|
|
@@ -10740,6 +11102,7 @@ var buildUI = (target, options) => {
|
|
|
10740
11102
|
prevBarBtn: sel("prev-bar"),
|
|
10741
11103
|
nextBarBtn: sel("next-bar"),
|
|
10742
11104
|
soloCheckbox: sel("solo"),
|
|
11105
|
+
clipBadge: sel("clip-badge"),
|
|
10743
11106
|
toolPen: sel("tool-pen"),
|
|
10744
11107
|
toolSelect: sel("tool-select"),
|
|
10745
11108
|
toolEraser: sel("tool-eraser"),
|
|
@@ -10766,6 +11129,11 @@ var buildUI = (target, options) => {
|
|
|
10766
11129
|
hScrollThumb: sel("hscroll-thumb"),
|
|
10767
11130
|
masterVolume: sel("master-volume"),
|
|
10768
11131
|
masterVolumeLabel: sel("master-volume-label"),
|
|
11132
|
+
reverbAmount: sel("reverb-amount"),
|
|
11133
|
+
reverbAmountLabel: sel("reverb-amount-label"),
|
|
11134
|
+
reverbAmountInfoBtn: sel("reverb-amount-info"),
|
|
11135
|
+
autoMasterBtn: sel("auto-master"),
|
|
11136
|
+
autoMasterInfoBtn: sel("auto-master-info"),
|
|
10769
11137
|
trackTabs: sel("track-tabs"),
|
|
10770
11138
|
trackBody: sel("track-body"),
|
|
10771
11139
|
drumSelect: sel("drum-select"),
|
|
@@ -10934,16 +11302,16 @@ var generateRandomPattern = (core, options) => {
|
|
|
10934
11302
|
const scale = SCALES[Math.floor(Math.random() * SCALES.length)];
|
|
10935
11303
|
const rootOffset = Math.floor(Math.random() * 12);
|
|
10936
11304
|
const availablePitches = [];
|
|
10937
|
-
for (let
|
|
10938
|
-
const noteInOctave = (
|
|
10939
|
-
if (scale.includes(noteInOctave)) availablePitches.push(basePitch +
|
|
11305
|
+
for (let i2 = 0; i2 < 12; i2++) {
|
|
11306
|
+
const noteInOctave = (i2 - rootOffset + 12) % 12;
|
|
11307
|
+
if (scale.includes(noteInOctave)) availablePitches.push(basePitch + i2);
|
|
10940
11308
|
}
|
|
10941
11309
|
core.beginBatch();
|
|
10942
11310
|
for (let bar = 0; bar < numBars; bar++) {
|
|
10943
11311
|
const barStart = startStep + bar * stepsPerBar;
|
|
10944
11312
|
const numNotes = Math.floor(Math.random() * 4) + 2;
|
|
10945
11313
|
const occupied = /* @__PURE__ */ new Set();
|
|
10946
|
-
for (let
|
|
11314
|
+
for (let i2 = 0; i2 < numNotes; i2++) {
|
|
10947
11315
|
const stepInRange = Math.floor(Math.random() * (stepsPerBar / noteLength)) * noteLength;
|
|
10948
11316
|
const step = barStart + stepInRange;
|
|
10949
11317
|
if (occupied.has(step)) continue;
|
|
@@ -11044,10 +11412,10 @@ var STEPS_PER_BEAT3 = 48;
|
|
|
11044
11412
|
var analyzeMidiTracks = (midi) => {
|
|
11045
11413
|
const { tracks } = midi;
|
|
11046
11414
|
const result = [];
|
|
11047
|
-
for (let
|
|
11415
|
+
for (let i2 = 0; i2 < tracks.length; i2++) {
|
|
11048
11416
|
const notes = [];
|
|
11049
11417
|
let currentTime = 0;
|
|
11050
|
-
for (const event of tracks[
|
|
11418
|
+
for (const event of tracks[i2]) {
|
|
11051
11419
|
currentTime += event.delta;
|
|
11052
11420
|
if (event.noteOn && event.noteOn.velocity > 0) {
|
|
11053
11421
|
notes.push({
|
|
@@ -11070,8 +11438,8 @@ var analyzeMidiTracks = (midi) => {
|
|
|
11070
11438
|
const editableNotes = validNotes.filter((n) => n.channel !== 9);
|
|
11071
11439
|
if (validNotes.length > 0 && editableNotes.length === 0) continue;
|
|
11072
11440
|
result.push({
|
|
11073
|
-
index:
|
|
11074
|
-
name: `Ch${
|
|
11441
|
+
index: i2,
|
|
11442
|
+
name: `Ch${i2 + 1}`,
|
|
11075
11443
|
noteCount: editableNotes.length,
|
|
11076
11444
|
selected: editableNotes.length > 0
|
|
11077
11445
|
});
|
|
@@ -11118,8 +11486,8 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
11118
11486
|
const pitch = noteOff.noteNumber;
|
|
11119
11487
|
const channel = event.channel ?? 0;
|
|
11120
11488
|
if (channelNotes[channel]) {
|
|
11121
|
-
for (let
|
|
11122
|
-
const note = channelNotes[channel][
|
|
11489
|
+
for (let i2 = channelNotes[channel].length - 1; i2 >= 0; i2--) {
|
|
11490
|
+
const note = channelNotes[channel][i2];
|
|
11123
11491
|
if (note.pitch === pitch && note.end === null) {
|
|
11124
11492
|
note.end = currentTime;
|
|
11125
11493
|
break;
|
|
@@ -11149,10 +11517,10 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
11149
11517
|
const avgPitch = validNotes.reduce((sum, n) => sum + n.pitch, 0) / validNotes.length;
|
|
11150
11518
|
let maxSimultaneous = 0;
|
|
11151
11519
|
const sortedNotes = [...validNotes].sort((a, b) => a.start - b.start);
|
|
11152
|
-
for (let
|
|
11520
|
+
for (let i2 = 0; i2 < sortedNotes.length; i2++) {
|
|
11153
11521
|
let simultaneous = 1;
|
|
11154
|
-
for (let j =
|
|
11155
|
-
if (sortedNotes[j].start < sortedNotes[
|
|
11522
|
+
for (let j = i2 + 1; j < sortedNotes.length; j++) {
|
|
11523
|
+
if (sortedNotes[j].start < sortedNotes[i2].end) {
|
|
11156
11524
|
simultaneous++;
|
|
11157
11525
|
}
|
|
11158
11526
|
}
|
|
@@ -11163,14 +11531,14 @@ var extractMidiPlacements = (midi, selectedTrackIndices) => {
|
|
|
11163
11531
|
const blocks = [];
|
|
11164
11532
|
let blockStart = sortedNotes[0].start;
|
|
11165
11533
|
let blockEnd = sortedNotes[0].end;
|
|
11166
|
-
for (let
|
|
11167
|
-
const gap = sortedNotes[
|
|
11534
|
+
for (let i2 = 1; i2 < sortedNotes.length; i2++) {
|
|
11535
|
+
const gap = sortedNotes[i2].start - sortedNotes[i2 - 1].end;
|
|
11168
11536
|
if (gap >= ticksPerBar) {
|
|
11169
11537
|
blocks.push({ start: blockStart, end: blockEnd });
|
|
11170
|
-
blockStart = sortedNotes[
|
|
11171
|
-
blockEnd = sortedNotes[
|
|
11538
|
+
blockStart = sortedNotes[i2].start;
|
|
11539
|
+
blockEnd = sortedNotes[i2].end;
|
|
11172
11540
|
} else {
|
|
11173
|
-
blockEnd = sortedNotes[
|
|
11541
|
+
blockEnd = sortedNotes[i2].end;
|
|
11174
11542
|
}
|
|
11175
11543
|
}
|
|
11176
11544
|
blocks.push({ start: blockStart, end: blockEnd });
|
|
@@ -11284,9 +11652,9 @@ var extractMidiPlacementsByTrack = (midi, selectedIndices, trackIds) => {
|
|
|
11284
11652
|
const noteOff = event.noteOff || event.noteOn;
|
|
11285
11653
|
if (noteOff) {
|
|
11286
11654
|
const pitch = noteOff.noteNumber;
|
|
11287
|
-
for (let
|
|
11288
|
-
if (active[
|
|
11289
|
-
active[
|
|
11655
|
+
for (let i2 = active.length - 1; i2 >= 0; i2--) {
|
|
11656
|
+
if (active[i2].pitch === pitch && active[i2].end === null) {
|
|
11657
|
+
active[i2].end = currentTime;
|
|
11290
11658
|
break;
|
|
11291
11659
|
}
|
|
11292
11660
|
}
|
|
@@ -11451,17 +11819,17 @@ var extractDrumPatternFromNotes = (rawNotes, drumFont = "FluidR3_GM_sf2_file:0")
|
|
|
11451
11819
|
let prev = bList[0];
|
|
11452
11820
|
const parts = key.split("_");
|
|
11453
11821
|
const noteObj = { step: +parts[0], pitch: +parts[1], velocity: +parts[2] };
|
|
11454
|
-
for (let
|
|
11455
|
-
if (
|
|
11822
|
+
for (let i2 = 1; i2 <= bList.length; i2++) {
|
|
11823
|
+
if (i2 === bList.length || bList[i2] !== prev + 1) {
|
|
11456
11824
|
const rKey = `${start}-${prev}`;
|
|
11457
11825
|
if (!rangeMap[rKey]) rangeMap[rKey] = [];
|
|
11458
11826
|
rangeMap[rKey].push(noteObj);
|
|
11459
|
-
if (
|
|
11460
|
-
start = bList[
|
|
11461
|
-
prev = bList[
|
|
11827
|
+
if (i2 < bList.length) {
|
|
11828
|
+
start = bList[i2];
|
|
11829
|
+
prev = bList[i2];
|
|
11462
11830
|
}
|
|
11463
11831
|
} else {
|
|
11464
|
-
prev = bList[
|
|
11832
|
+
prev = bList[i2];
|
|
11465
11833
|
}
|
|
11466
11834
|
}
|
|
11467
11835
|
}
|
|
@@ -11838,8 +12206,8 @@ var drawHeader = () => {
|
|
|
11838
12206
|
(g_draw_offset_x + g_header_canvas.width) / (stepsPerBar * stepWidth)
|
|
11839
12207
|
);
|
|
11840
12208
|
for (let bar = startBar; bar <= endBar + 1; bar++) {
|
|
11841
|
-
const
|
|
11842
|
-
const screenX =
|
|
12209
|
+
const x2 = bar * stepsPerBar * stepWidth;
|
|
12210
|
+
const screenX = x2;
|
|
11843
12211
|
g_header_ctx.beginPath();
|
|
11844
12212
|
g_header_ctx.moveTo(screenX, 0);
|
|
11845
12213
|
g_header_ctx.lineTo(screenX, HEADER_HEIGHT);
|
|
@@ -11886,11 +12254,11 @@ var drawGrid = (noteLengthSteps = 1) => {
|
|
|
11886
12254
|
const startX = Math.floor(g_draw_offset_x / (stepWidth * gridStep)) * stepWidth * gridStep;
|
|
11887
12255
|
const endX = g_draw_offset_x + g_grid_canvas.width;
|
|
11888
12256
|
const lineStep = stepWidth * gridStep;
|
|
11889
|
-
for (let
|
|
11890
|
-
const step =
|
|
12257
|
+
for (let x2 = startX; x2 <= endX; x2 += lineStep) {
|
|
12258
|
+
const step = x2 / stepWidth;
|
|
11891
12259
|
const isBarLine = step % stepsPerBar === 0;
|
|
11892
12260
|
const isNoteLine = step % gridStep === 0;
|
|
11893
|
-
const screenX =
|
|
12261
|
+
const screenX = x2 - g_draw_offset_x;
|
|
11894
12262
|
g_grid_ctx.beginPath();
|
|
11895
12263
|
g_grid_ctx.strokeStyle = isBarLine ? "#3d405b" : isNoteLine ? "#242840" : "#1a1d30";
|
|
11896
12264
|
g_grid_ctx.lineWidth = isBarLine ? 2 : 1;
|
|
@@ -11952,26 +12320,26 @@ var drawSelectedNotes = (notes, selectedIds, baseColor = [59, 130, 246, 1]) => {
|
|
|
11952
12320
|
var getXY = (e) => {
|
|
11953
12321
|
const { clientX, clientY } = e;
|
|
11954
12322
|
const rect = g_grid_canvas.getBoundingClientRect();
|
|
11955
|
-
const
|
|
12323
|
+
const x2 = Math.floor(clientX - rect.left);
|
|
11956
12324
|
const y = Math.floor(clientY - rect.top);
|
|
11957
|
-
return [
|
|
12325
|
+
return [x2, y, e.buttons];
|
|
11958
12326
|
};
|
|
11959
12327
|
var getGridPosition = (e) => {
|
|
11960
|
-
const [
|
|
12328
|
+
const [x2, y] = getXY(e);
|
|
11961
12329
|
const { keyCount, pitchRangeStart, keyHeight, stepWidth } = g_config;
|
|
11962
|
-
const step = Math.floor((
|
|
12330
|
+
const step = Math.floor((x2 + g_draw_offset_x) / stepWidth);
|
|
11963
12331
|
const absoluteY = y + g_draw_offset_y;
|
|
11964
12332
|
const yIndex = Math.floor(absoluteY / keyHeight);
|
|
11965
12333
|
const pitch = keyCount - 1 - yIndex + pitchRangeStart;
|
|
11966
|
-
return { step, pitch, x, y };
|
|
12334
|
+
return { step, pitch, x: x2, y };
|
|
11967
12335
|
};
|
|
11968
12336
|
var onClick = (callback) => {
|
|
11969
12337
|
g_grid_canvas.addEventListener(
|
|
11970
12338
|
"click",
|
|
11971
12339
|
(e) => {
|
|
11972
|
-
const [
|
|
12340
|
+
const [x2, y] = getXY(e);
|
|
11973
12341
|
const { keyCount, pitchRangeStart, keyHeight, stepWidth } = g_config;
|
|
11974
|
-
const step = Math.floor((
|
|
12342
|
+
const step = Math.floor((x2 + g_draw_offset_x) / stepWidth);
|
|
11975
12343
|
const absoluteY = y + g_draw_offset_y;
|
|
11976
12344
|
const yIndex = Math.floor(absoluteY / keyHeight);
|
|
11977
12345
|
const pitch = keyCount - 1 - yIndex + pitchRangeStart;
|
|
@@ -11983,8 +12351,8 @@ var onClick = (callback) => {
|
|
|
11983
12351
|
);
|
|
11984
12352
|
g_grid_canvas.addEventListener("contextmenu", (e) => e.preventDefault());
|
|
11985
12353
|
};
|
|
11986
|
-
var setDrawOffset = (
|
|
11987
|
-
g_draw_offset_x =
|
|
12354
|
+
var setDrawOffset = (x2, y) => {
|
|
12355
|
+
g_draw_offset_x = x2;
|
|
11988
12356
|
g_draw_offset_y = y;
|
|
11989
12357
|
drawKeyboard();
|
|
11990
12358
|
drawHeader();
|
|
@@ -12299,12 +12667,12 @@ var MMLCore = class _MMLCore {
|
|
|
12299
12667
|
currentCursor += steps;
|
|
12300
12668
|
}
|
|
12301
12669
|
};
|
|
12302
|
-
for (let
|
|
12303
|
-
const startStep = sortedSteps[
|
|
12670
|
+
for (let i2 = 0; i2 < sortedSteps.length; i2++) {
|
|
12671
|
+
const startStep = sortedSteps[i2];
|
|
12304
12672
|
const notes = notesByStep.get(startStep);
|
|
12305
12673
|
if (!notes) continue;
|
|
12306
12674
|
fillRests(startStep);
|
|
12307
|
-
const nextStart = sortedSteps[
|
|
12675
|
+
const nextStart = sortedSteps[i2 + 1] ?? endStep;
|
|
12308
12676
|
const physicsLimit = nextStart - currentCursor;
|
|
12309
12677
|
if (physicsLimit < MIN_STEP) {
|
|
12310
12678
|
continue;
|
|
@@ -12369,10 +12737,10 @@ var decomposeToMonophonic = (notes) => {
|
|
|
12369
12737
|
for (const note of sorted) {
|
|
12370
12738
|
let assigned = -1;
|
|
12371
12739
|
let minEnd = Infinity;
|
|
12372
|
-
for (let
|
|
12373
|
-
if (trackEnds[
|
|
12374
|
-
minEnd = trackEnds[
|
|
12375
|
-
assigned =
|
|
12740
|
+
for (let i2 = 0; i2 < tracks.length; i2++) {
|
|
12741
|
+
if (trackEnds[i2] <= note.startStep && trackEnds[i2] < minEnd) {
|
|
12742
|
+
minEnd = trackEnds[i2];
|
|
12743
|
+
assigned = i2;
|
|
12376
12744
|
}
|
|
12377
12745
|
}
|
|
12378
12746
|
if (assigned === -1) {
|
|
@@ -12428,6 +12796,89 @@ var CHORD_INFO_HTML2 = `
|
|
|
12428
12796
|
</ul>
|
|
12429
12797
|
</div>
|
|
12430
12798
|
`;
|
|
12799
|
+
var VIBRATO_INFO_HTML = `
|
|
12800
|
+
<div class="dtm-modal-body-content">
|
|
12801
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12802
|
+
<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>
|
|
12803
|
+
<h4>\u77ED\u3044\u97F3\u7B26\u306B\u639B\u304B\u3089\u306A\u3044\u7406\u7531</h4>
|
|
12804
|
+
<p>1\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</p>
|
|
12805
|
+
<h4>\u4ED6\u306E\u8A2D\u5B9A\u3068\u306E\u517C\u306D\u5408\u3044</h4>
|
|
12806
|
+
<p>\u30D4\u30C3\u30C1\u3092\u63FA\u3089\u3059\u52B9\u679C\u306A\u306E\u3067\u3001\u58F0\u8CEA\u305D\u306E\u3082\u306E\u3092\u5909\u3048\u308B\u30B8\u30A7\u30F3\u30C0\u30FC/\u30D6\u30EC\u30B7\u30CD\u30B9\u3068\u306F\u72EC\u7ACB\u3057\u3066\u7D44\u307F\u5408\u308F\u305B\u3089\u308C\u307E\u3059\u3002\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\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</p>
|
|
12807
|
+
</div>
|
|
12808
|
+
`;
|
|
12809
|
+
var GENDER_INFO_HTML = `
|
|
12810
|
+
<div class="dtm-modal-body-content">
|
|
12811
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12812
|
+
<p>\u30D4\u30C3\u30C1\uFF08\u97F3\u306E\u9AD8\u3055\uFF09\u306F\u305D\u306E\u307E\u307E\u306B\u3001\u58F0\u306E\u592A\u3055/\u7D30\u3055\uFF08\u30D5\u30A9\u30EB\u30DE\u30F3\u30C8\uFF1D\u58F0\u9053\u306E\u5171\u9CF4\u3001\u5E74\u9F62\u30FB\u6027\u5225\u611F\u306E\u5370\u8C61\uFF09\u3060\u3051\u3092\u52D5\u304B\u3057\u307E\u3059\u300250\u304C\u7121\u5909\u5316\u300150\u672A\u6E80\u3067\u4F4E\u3081/\u592A\u3081\uFF08\u5927\u4EBA\u3073\u308B\uFF09\u300150\u8D85\u3067\u9AD8\u3081/\u7D30\u3081\uFF08\u82E5\u304F/\u660E\u308B\u304F\uFF09\u306B\u5BC4\u308A\u307E\u3059\u3002</p>
|
|
12813
|
+
<h4>\u30AA\u30AF\u30BF\u30FC\u30D6\u30B7\u30D5\u30C8\u3068\u306E\u9055\u3044</h4>
|
|
12814
|
+
<p>\u30AA\u30AF\u30BF\u30FC\u30D6\u306F\u97F3\u7A0B\u305D\u306E\u3082\u306E\u3092\u4E0A\u4E0B\u3055\u305B\u307E\u3059\u304C\u3001\u30B8\u30A7\u30F3\u30C0\u30FC\u306F\u97F3\u7A0B\u3092\u5909\u3048\u305A\u306B\u58F0\u8272\u3060\u3051\u3092\u52D5\u304B\u3057\u307E\u3059\u3002\u300C\u9AD8\u3044\u58F0\u306E\u307E\u307E\u5927\u4EBA\u3073\u3055\u305B\u308B\u300D\u300C\u4F4E\u3044\u58F0\u306E\u307E\u307E\u82E5\u3005\u3057\u304F\u3059\u308B\u300D\u3068\u3044\u3063\u305F\u3001\u97F3\u7A0B\u3068\u58F0\u8CEA\u3092\u5225\u3005\u306B\u8ABF\u6574\u3057\u305F\u3044\u3068\u304D\u306B\u4F7F\u3044\u307E\u3059\u3002</p>
|
|
12815
|
+
<h4>\u4ED6\u306E\u8A2D\u5B9A\u3068\u306E\u517C\u306D\u5408\u3044</h4>
|
|
12816
|
+
<p>\u30D6\u30EC\u30B7\u30CD\u30B9\u3068\u7D44\u307F\u5408\u308F\u305B\u3066\u58F0\u306E\u30AD\u30E3\u30E9\u30AF\u30BF\u30FC\u3092\u4F5C\u308A\u307E\u3059\uFF08\u4F8B: \u4F4E\u3081+\u606F\u591A\u3081\u3067\u6E0B\u3044/\u5927\u4EBA\u3063\u307D\u3044\u5370\u8C61\u3001\u9AD8\u3081+\u606F\u5C11\u306A\u3081\u3067\u5143\u6C17/\u82E5\u3005\u3057\u3044\u5370\u8C61\uFF09\u3002koe\u97F3\u6E90\uFF08UTAU\u7531\u6765\u306E.koe\u97F3\u6E90\uFF09\u9650\u5B9A\u306E\u52B9\u679C\u3067\u3001klatt\uFF08\u5185\u8535\u306E\u7C21\u6613\u5408\u6210\uFF09\u3067\u306F\u5909\u5316\u3057\u307E\u305B\u3093\u3002</p>
|
|
12817
|
+
</div>
|
|
12818
|
+
`;
|
|
12819
|
+
var BREATHINESS_INFO_HTML = `
|
|
12820
|
+
<div class="dtm-modal-body-content">
|
|
12821
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12822
|
+
<p>\u606F\u6210\u5206\u306E\u91CF\u3067\u3059\u300250\u304C\u7121\u5909\u5316\u3001\u5927\u304D\u3044\u307B\u3069\u606F\u3063\u307D\u304F\uFF08\u3055\u3055\u3084\u304D\u5BC4\u308A\uFF09\u3001\u5C0F\u3055\u3044\u307B\u3069\u82AF\u306E\u3042\u308B\u58F0\u306B\u306A\u308A\u307E\u3059\u3002</p>
|
|
12823
|
+
<h4>\u4E0A\u3052\u3059\u304E\u308B\u3068\u3069\u3046\u306A\u308B\u304B</h4>
|
|
12824
|
+
<p>\u30ED\u30F3\u30B0\u30C8\u30FC\u30F3\u3067\u97F3\u7A0B\u611F\u304C\u8584\u308C\u3066\u805E\u3053\u3048\u307E\u3059\uFF08\u606F\u306E\u97F3\u304C\u30D4\u30C3\u30C1\u611F\u3092\u96A0\u3059\u305F\u3081\uFF09\u3002\u56C1\u304F\u3088\u3046\u306A\u30D0\u30E9\u30FC\u30C9\u8868\u73FE\u306B\u306F\u52B9\u679C\u7684\u3067\u3059\u304C\u3001\u4E0A\u3052\u3059\u304E\u308B\u3068\u30E1\u30ED\u30C7\u30A3\u304C\u4F1D\u308F\u308A\u306B\u304F\u304F\u306A\u308A\u307E\u3059\u3002</p>
|
|
12825
|
+
<h4>\u4ED6\u306E\u8A2D\u5B9A\u3068\u306E\u517C\u306D\u5408\u3044</h4>
|
|
12826
|
+
<p>\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u3068\u7D44\u307F\u5408\u308F\u305B\u308B\u3068\u3001\u63FA\u308C\u306A\u304C\u3089\u606F\u3063\u307D\u3044\u3001\u3088\u308A\u30A8\u30E2\u30FC\u30B7\u30E7\u30CA\u30EB\u306A\u8868\u73FE\u306B\u306A\u308A\u3084\u3059\u3044\u3067\u3059\u3002koe\u97F3\u6E90\uFF08UTAU\u7531\u6765\u306E.koe\u97F3\u6E90\uFF09\u9650\u5B9A\u306E\u52B9\u679C\u3067\u3001klatt\uFF08\u5185\u8535\u306E\u7C21\u6613\u5408\u6210\uFF09\u3067\u306F\u5909\u5316\u3057\u307E\u305B\u3093\u3002</p>
|
|
12827
|
+
</div>
|
|
12828
|
+
`;
|
|
12829
|
+
var LYRIC_REVERB_INFO_HTML = `
|
|
12830
|
+
<div class="dtm-modal-body-content">
|
|
12831
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12832
|
+
<p>\u3053\u306E\u30DC\u30FC\u30AB\u30EB\u30C8\u30E9\u30C3\u30AF\u304B\u3089\u3001\u66F2\u5168\u4F53\u306B\u639B\u304B\u308B\u300C\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\u300D\u3078\u3069\u308C\u3060\u3051\u97F3\u3092\u9001\u308B\u304B\u3092\u6C7A\u3081\u307E\u3059\uFF080\u3067\u9001\u3089\u306A\u3044\uFF1D\u30C9\u30E9\u30A4\u3001100\u3067\u76EE\u4E00\u676F\u9001\u308B\uFF09\u3002</p>
|
|
12833
|
+
<h4>\u30DE\u30B9\u30BF\u306E\u300C\u30EA\u30D0\u30FC\u30D6\u300D\u3064\u307E\u307F\u3068\u306E\u95A2\u4FC2\uFF08\u91CD\u8981\uFF09</h4>
|
|
12834
|
+
<p>\u30C8\u30E9\u30C3\u30AF\u8A2D\u5B9A\u30D1\u30CD\u30EB\u306B\u3042\u308B\u30DE\u30B9\u30BF\u306E\u300C\u30EA\u30D0\u30FC\u30D6\u300D\u3064\u307E\u307F\u304C0%\u3060\u3068\u3001\u3053\u3053\u3092\u3044\u304F\u3089\u4E0A\u3052\u3066\u3082\u7121\u97F3\u306E\u307E\u307E\u3067\u3059\u3002\u300C\u9001\u308A\u91CF\uFF08\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u304C\u3069\u308C\u3060\u3051\u63D0\u4F9B\u3059\u308B\u304B\uFF09\u300D\u3068\u300C\u30DE\u30B9\u30BF\u306E\u6B8B\u97FF\u8A2D\u5B9A\uFF08\u5B9F\u969B\u306B\u3069\u3093\u306A\u97FF\u304D\u304C\u639B\u304B\u308B\u304B\uFF09\u300D\u306E\u4E8C\u6BB5\u69CB\u3048\u306B\u306A\u3063\u3066\u3044\u308B\u305F\u3081\u3067\u3059\u3002\u4E21\u65B9\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>
|
|
12835
|
+
<h4>\u639B\u3051\u3059\u304E\u308B\u3068\u3069\u3046\u306A\u308B\u304B</h4>
|
|
12836
|
+
<p>\u6B8B\u97FF\u3067\u97F3\u304C\u6EF2\u307F\u3001\u6B4C\u8A5E\u304C\u805E\u304D\u53D6\u308A\u306B\u304F\u304F\u306A\u308A\u307E\u3059\u3002\u30C9\u30E9\u30A4\u306A\u30DC\u30FC\u30AB\u30EB\u306F\u300C\u8FD1\u3044\u300D\u300C\u524D\u306B\u51FA\u308B\u300D\u5370\u8C61\u3001\u30EA\u30D0\u30FC\u30D6\u305F\u3063\u3077\u308A\u306E\u30DC\u30FC\u30AB\u30EB\u306F\u300C\u5965\u884C\u304D\u304C\u3042\u308B\u300D\u300C\u5E7B\u60F3\u7684\u300D\u306A\u5370\u8C61\u306B\u306A\u308A\u307E\u3059\u3002\u8868\u73FE\u3057\u305F\u3044\u8DDD\u96E2\u611F\u306B\u5408\u308F\u305B\u3066\u8ABF\u6574\u3057\u3066\u304F\u3060\u3055\u3044\u3002</p>
|
|
12837
|
+
</div>
|
|
12838
|
+
`;
|
|
12839
|
+
var MASTER_REVERB_INFO_HTML = `
|
|
12840
|
+
<div class="dtm-modal-body-content">
|
|
12841
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12842
|
+
<p>\u66F2\u5168\u4F53\u306B\u4E00\u5F8B\u3067\u639B\u304B\u308B\u6B8B\u97FF\uFF08\u90E8\u5C4B\u9CF4\u308A\u30FB\u7A7A\u9593\u306E\u97FF\u304D\uFF09\u3067\u3059\u30020%\u3067\u5B8C\u5168\u306B\u30C9\u30E9\u30A4\uFF08\u97FF\u304D\u306A\u3057\uFF09\u3001\u4E0A\u3052\u308B\u307B\u3069\u5E83\u3044\u7A7A\u9593\u3067\u9CF4\u3063\u3066\u3044\u308B\u3088\u3046\u306A\u5965\u884C\u304D\u304C\u51FA\u307E\u3059\u3002</p>
|
|
12843
|
+
<h4>\u5404\u30C8\u30E9\u30C3\u30AF\u306E\u300C\u30EA\u30D0\u30FC\u30D6\u9001\u308A\u300D\u3068\u306E\u95A2\u4FC2\uFF08\u91CD\u8981\uFF09</h4>
|
|
12844
|
+
<p>\u6B4C\u8A5E\u30C8\u30E9\u30C3\u30AF\u306B\u306F\u305D\u308C\u305E\u308C\u300C\u30EA\u30D0\u30FC\u30D6\u9001\u308A\u300D\u3068\u3044\u3046\u500B\u5225\u306E\u3064\u307E\u307F\u304C\u3042\u308A\u3001\u305D\u3061\u3089\u304C0%\u306E\u30C8\u30E9\u30C3\u30AF\u306F\u3053\u306E\u30DE\u30B9\u30BF\u306E\u5024\u3092\u3044\u304F\u3089\u4E0A\u3052\u3066\u3082\u7121\u97F3\u306E\u307E\u307E\u3067\u3059\u3002\u9006\u306B\u3053\u306E\u30DE\u30B9\u30BF\u304C0%\u306A\u3089\u3001\u3069\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u9001\u308A\u91CF\u3092\u4E0A\u3052\u3066\u3082\u52B9\u679C\u304C\u51FA\u307E\u305B\u3093\u3002\u300C\u30DE\u30B9\u30BF\uFF1D\u6B8B\u97FF\u306E\u8CEA\u3068\u91CF\u305D\u306E\u3082\u306E\u300D\u300C\u30C8\u30E9\u30C3\u30AF\u9001\u308A\uFF1D\u305D\u306E\u30C8\u30E9\u30C3\u30AF\u3092\u3069\u308C\u3060\u3051\u6DF7\u305C\u308B\u304B\u300D\u3068\u3044\u3046\u4E8C\u6BB5\u69CB\u3048\u3067\u3059\u3002\u697D\u5668\u30C8\u30E9\u30C3\u30AF\u306B\u306F\u73FE\u72B6\u30BB\u30F3\u30C9\u6A5F\u80FD\u304C\u7121\u3044\u305F\u3081\u3001\u5E38\u306B\u4E00\u5F8B\u3067\u639B\u304B\u308A\u307E\u3059\u3002</p>
|
|
12845
|
+
<h4>\u639B\u3051\u3059\u304E\u308B\u3068\u3069\u3046\u306A\u308B\u304B</h4>
|
|
12846
|
+
<p>\u30DF\u30C3\u30AF\u30B9\u5168\u4F53\u306E\u8F2A\u90ED\u304C\u307C\u3084\u3051\u3001\u9060\u304F\u30FB\u3053\u3082\u3063\u305F\u5370\u8C61\u306B\u306A\u308A\u307E\u3059\u300210\u301C30%\u7A0B\u5EA6\u3092\u51FA\u767A\u70B9\u306B\u3001\u66F2\u306E\u30B8\u30E3\u30F3\u30EB\u3084\u7A7A\u9593\u306E\u5E83\u3055\u306E\u30A4\u30E1\u30FC\u30B8\u306B\u5408\u308F\u305B\u3066\u8ABF\u6574\u3059\u308B\u306E\u304C\u304A\u3059\u3059\u3081\u3067\u3059\u3002</p>
|
|
12847
|
+
</div>
|
|
12848
|
+
`;
|
|
12849
|
+
var TRACK_COMPRESSION_INFO_HTML = `
|
|
12850
|
+
<div class="dtm-modal-body-content">
|
|
12851
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12852
|
+
<p>\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306B\u30B3\u30F3\u30D7\u30EC\u30C3\u30B5\u30FC\u3092\u639B\u3051\u3001\u97F3\u91CF\u306E\u5927\u5C0F\u5DEE\u3092\u7E2E\u3081\u3066\u300C\u524D\u306B\u51FA\u308B\u300D\u300C\u805E\u3053\u3048\u3084\u3059\u3044\u300D\u97F3\u306B\u3057\u307E\u3059\u3002\u5E02\u8CA9\u66F2\u306E\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u3084\u30DF\u30C3\u30AF\u30B9\u3067\u5B9A\u756A\u306E\u51E6\u7406\u3067\u3059\u30020\u3067\u7121\u5727\u7E2E\u3001100\u306B\u8FD1\u3065\u304F\u307B\u3069\u5F37\u304F\u5727\u7E2E\u3055\u308C\u307E\u3059\u3002</p>
|
|
12853
|
+
<h4>\u639B\u3051\u3059\u304E\u308B\u3068\u3069\u3046\u306A\u308B\u304B</h4>
|
|
12854
|
+
<p>\u5F37\u5F31\u306E\u8868\u60C5\uFF08\u30C0\u30A4\u30CA\u30DF\u30AF\u30B9\uFF09\u304C\u5931\u308F\u308C\u3066\u5358\u8ABF\u306B\u805E\u3053\u3048\u307E\u3059\u3002\u30DC\u30FC\u30AB\u30EB\u3084\u30EA\u30FC\u30C9\u697D\u5668\u306F\u63A7\u3048\u3081\uFF0820\u301C40\u7A0B\u5EA6\uFF09\u3001\u30C9\u30E9\u30E0\u3084\u30D9\u30FC\u30B9\u306F\u3084\u3084\u5F37\u3081\u3001\u304C\u4E00\u822C\u7684\u306A\u76EE\u5B89\u3067\u3059\u3002</p>
|
|
12855
|
+
<h4>\u4ED6\u306E\u8A2D\u5B9A\u3068\u306E\u517C\u306D\u5408\u3044</h4>
|
|
12856
|
+
<p>\u30DE\u30B9\u30BF\u306E\u300C\u5B89\u5168\u30EA\u30DF\u30C3\u30BF\u30FC\u300D\uFF08\u5E38\u6642ON\u3001[reverb]\u30D1\u30CD\u30EB\u306E\u5916\u5074\u3067\u81EA\u52D5\u7684\u306B\u50CD\u304F\u4FDD\u967A\uFF09\u3068\u306F\u5225\u7269\u3067\u3059\u3002\u3042\u3061\u3089\u306F\u97F3\u5272\u308C\u3092\u7269\u7406\u7684\u306B\u9632\u3050\u305F\u3081\u306E\u6700\u7D42\u9632\u885B\u30E9\u30A4\u30F3\u3067\u3001\u5E38\u306B\u63A7\u3048\u3081\u306B\u52D5\u3044\u3066\u3044\u307E\u3059\u3002\u3053\u3061\u3089\u306E\u30B3\u30F3\u30D7\u30EC\u30C3\u30B5\u30FC\u306F\u97F3\u4F5C\u308A\uFF08\u8868\u73FE\uFF09\u306E\u305F\u3081\u306E\u51E6\u7406\u3067\u3001\u30C8\u30E9\u30C3\u30AF\u3054\u3068\u306B\u597D\u304D\u306A\u3060\u3051\u5F37\u304F/\u5F31\u304F\u639B\u3051\u3089\u308C\u307E\u3059\u3002\u300C\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u300D\u306F\u5168\u30C8\u30E9\u30C3\u30AF\u4E00\u5F8B35%\u3092\u5F53\u3066\u308B\u3060\u3051\u306A\u306E\u3067\u3001\u30DC\u30FC\u30AB\u30EB\u306A\u3069\u76EE\u7ACB\u305F\u305B\u305F\u3044\u30D1\u30FC\u30C8\u306F\u5F8C\u3067\u500B\u5225\u306B\u4E0B\u3052\u308B\u3068\u8F2A\u90ED\u304C\u51FA\u3084\u3059\u304F\u306A\u308A\u307E\u3059\u3002</p>
|
|
12857
|
+
</div>
|
|
12858
|
+
`;
|
|
12859
|
+
var TRACK_WIDTH_INFO_HTML = `
|
|
12860
|
+
<div class="dtm-modal-body-content">
|
|
12861
|
+
<h4>\u4F55\u3092\u3059\u308B\u8A2D\u5B9A\u304B</h4>
|
|
12862
|
+
<p>\u5DE6\u53F3\u306E\u5E83\u304C\u308A\u3092\u8ABF\u6574\u3057\u307E\u3059\u3002100\u304C\u539F\u97F3\u306E\u307E\u307E\u30010\u3067\u5B8C\u5168\u30E2\u30CE\u30E9\u30EB\uFF08\u5DE6\u53F3\u304C\u540C\u3058\u97F3\uFF09\u3001100\u3092\u8D85\u3048\u308B\u3068\u5DE6\u53F3\u306E\u9055\u3044\u304C\u8A87\u5F35\u3055\u308C\u3066\u5E83\u304F\u805E\u3053\u3048\u307E\u3059\u3002</p>
|
|
12863
|
+
<h4>\u300C\u5B9A\u4F4D\uFF08\u30D1\u30F3\uFF09\u300D\u3068\u306E\u9055\u3044</h4>
|
|
12864
|
+
<p>\u5B9A\u4F4D\u306F\u300C\u97F3\u3092\u3069\u3053\u306B\u7F6E\u304F\u304B\u300D\uFF08\u5DE6\u5BC4\u308A/\u4E2D\u592E/\u53F3\u5BC4\u308A\uFF09\u3001\u30B9\u30C6\u30EC\u30AA\u5E45\u306F\u300C\u305D\u306E\u97F3\u81EA\u4F53\u304C\u3069\u308C\u3060\u3051\u5E83\u304C\u3063\u3066\u805E\u3053\u3048\u308B\u304B\u300D\u3067\u3001\u5F79\u5272\u304C\u7570\u306A\u308A\u307E\u3059\u3002\u4E21\u65B9\u3092\u5F37\u304F\u4F7F\u3046\u3068\u5B9A\u4F4D\u304C\u307C\u3084\u3051\u3066\u66D6\u6627\u306B\u306A\u308A\u304C\u3061\u3067\u3059\u3002</p>
|
|
12865
|
+
<h4>\u5E83\u3052\u3059\u304E\u308B\u3068\u3069\u3046\u306A\u308B\u304B</h4>
|
|
12866
|
+
<p>\u30B9\u30DE\u30DB\u306E\u30B9\u30D4\u30FC\u30AB\u30FC1\u500B\u306A\u3069\u3001\u30E2\u30CE\u30E9\u30EB\u306B\u8FD1\u3044\u74B0\u5883\u3067\u518D\u751F\u3059\u308B\u3068\u97F3\u304C\u8584\u304F/\u4F4D\u76F8\u304C\u4E71\u308C\u3066\u805E\u3053\u3048\u308B\u3053\u3068\u304C\u3042\u308A\u307E\u3059\uFF08\u5DE6\u53F3\u306E\u5DEE\u5206\u3092\u8A87\u5F35\u3057\u3066\u3044\u308B\u305F\u3081\u3001\u8DB3\u3057\u5408\u308F\u305B\u308B\u3068\u6253\u3061\u6D88\u3057\u5408\u3046\u6210\u5206\u304C\u5897\u3048\u308B\uFF09\u3002\u4E3B\u65CB\u5F8B\u3084\u30DC\u30FC\u30AB\u30EB\u306F\u4E2D\u592E\u4ED8\u8FD1\u3067\u72ED\u3081\u3001\u30D1\u30C3\u30C9\u3084\u30B7\u30F3\u30BB\u306E\u88C5\u98FE\u30D1\u30FC\u30C8\u306F\u5E83\u3052\u308B\u3001\u3068\u3044\u3046\u306E\u304C\u30DF\u30C3\u30AF\u30B9\u306E\u5B9A\u77F3\u3067\u3059\u3002</p>
|
|
12867
|
+
</div>
|
|
12868
|
+
`;
|
|
12869
|
+
var AUTO_MASTER_INFO_HTML = `
|
|
12870
|
+
<div class="dtm-modal-body-content">
|
|
12871
|
+
<h4>\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u3068\u306F</h4>
|
|
12872
|
+
<p>\u5E02\u8CA9\u66F2\u3067\u3088\u304F\u4F7F\u308F\u308C\u308B\u5024\u3092\u76EE\u5B89\u306B\u3001\u4EE5\u4E0B\u3092\u307E\u3068\u3081\u3066\u8A2D\u5B9A\u3059\u308B\u30DC\u30BF\u30F3\u3067\u3059\u3002</p>
|
|
12873
|
+
<ul>
|
|
12874
|
+
<li>\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6: 20%</li>
|
|
12875
|
+
<li>\u5168\u30C8\u30E9\u30C3\u30AF\u306E\u97F3\u5727\u5F37\u5316: 35%</li>
|
|
12876
|
+
<li>\u5168\u30C8\u30E9\u30C3\u30AF\u306E\u30B9\u30C6\u30EC\u30AA\u5E45: 115%\uFF08\u308F\u305A\u304B\u306B\u5E83\u3052\u308B\uFF09</li>
|
|
12877
|
+
<li>\u6B4C\u8A5E\u306E\u3042\u308B\u30C8\u30E9\u30C3\u30AF: \u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8ON\u3001\u30EA\u30D0\u30FC\u30D6\u9001\u308A25%</li>
|
|
12878
|
+
</ul>
|
|
12879
|
+
<p style="margin-top:4px;"><small>\u300C\u3044\u3044\u611F\u3058\u306E\u521D\u671F\u5024\u300D\u3092\u4E00\u62EC\u3067\u5F53\u3066\u308B\u3060\u3051\u3067\u3001\u66F2\u3084\u597D\u307F\u306B\u5FDC\u3058\u305F\u5FAE\u8ABF\u6574\u307E\u3067\u306F\u884C\u3044\u307E\u305B\u3093\u3002\u65E2\u5B58\u306E\u8A2D\u5B9A\u306F\u4E0A\u66F8\u304D\u3055\u308C\u308B\u306E\u3067\u3001\u6C17\u306B\u5165\u3089\u306A\u3051\u308C\u3070\u5404\u30B9\u30E9\u30A4\u30C0\u30FC\u304B\u3089\u500B\u5225\u306B\u623B\u3057\u3066\u304F\u3060\u3055\u3044\u3002</small></p>
|
|
12880
|
+
</div>
|
|
12881
|
+
`;
|
|
12431
12882
|
var MIDI_INFO_HTML = `
|
|
12432
12883
|
<div class="dtm-modal-body-content">
|
|
12433
12884
|
<h4>1. MIDI\u30D5\u30A1\u30A4\u30EB\u3068\u306F</h4>
|
|
@@ -12631,7 +13082,7 @@ var LYRIC_MODEL_CATEGORIES = [
|
|
|
12631
13082
|
},
|
|
12632
13083
|
{
|
|
12633
13084
|
label: "\u304A\u3093J",
|
|
12634
|
-
models: ["roze", "shiyo", "rino"]
|
|
13085
|
+
models: ["roze", "shiyo", "rino", "rino121", "uc"]
|
|
12635
13086
|
},
|
|
12636
13087
|
{
|
|
12637
13088
|
label: "\u4E00\u822C",
|
|
@@ -12699,6 +13150,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
12699
13150
|
});
|
|
12700
13151
|
refs.masterVolume.value = String(options.masterVolume ?? 50);
|
|
12701
13152
|
refs.masterVolumeLabel.textContent = `${options.masterVolume ?? 50}%`;
|
|
13153
|
+
refs.reverbAmount.value = String(options.reverbAmount ?? 0);
|
|
13154
|
+
refs.reverbAmountLabel.textContent = `${options.reverbAmount ?? 0}%`;
|
|
12702
13155
|
refs.drumVolume.value = String(options.drumVolume ?? 80);
|
|
12703
13156
|
refs.drumVolumeLabel.textContent = `${options.drumVolume ?? 80}%`;
|
|
12704
13157
|
const renderConfig = {
|
|
@@ -12714,6 +13167,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
12714
13167
|
let bpm = options.defaultBpm ?? DEFAULT_BPM;
|
|
12715
13168
|
let masterVolume = options.masterVolume ?? 50;
|
|
12716
13169
|
options.singingVoices?.setVolume(masterVolume / 100);
|
|
13170
|
+
let reverbAmount = options.reverbAmount ?? 0;
|
|
13171
|
+
let unsubscribeClip;
|
|
13172
|
+
options.onReverbChange?.(reverbAmount);
|
|
12717
13173
|
let drumVolume = options.drumVolume ?? 80;
|
|
12718
13174
|
let currentDrumPattern = refs.drumSelect.value;
|
|
12719
13175
|
let currentDrumFont = options.drumFont ?? "FluidR3_GM_sf2_file:0";
|
|
@@ -12791,7 +13247,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
12791
13247
|
vocalVolume: t.vocalVolume,
|
|
12792
13248
|
vocalGate: t.vocalGate,
|
|
12793
13249
|
vocalPan: t.vocalPan,
|
|
12794
|
-
vocalOctave: t.vocalOctave
|
|
13250
|
+
vocalOctave: t.vocalOctave,
|
|
13251
|
+
vocalVibrato: t.vocalVibrato,
|
|
13252
|
+
vocalReverb: t.vocalReverb,
|
|
13253
|
+
vocalGender: t.vocalGender,
|
|
13254
|
+
vocalBreathiness: t.vocalBreathiness
|
|
12795
13255
|
};
|
|
12796
13256
|
if (lyricsDebounceTimer) clearTimeout(lyricsDebounceTimer);
|
|
12797
13257
|
lyricsDebounceTimer = setTimeout(() => {
|
|
@@ -12851,25 +13311,35 @@ var mountDAW = (target, options = {}) => {
|
|
|
12851
13311
|
vocalGate: 100,
|
|
12852
13312
|
vocalPan: 64,
|
|
12853
13313
|
vocalOctave: 0,
|
|
12854
|
-
|
|
13314
|
+
vocalVibrato: false,
|
|
13315
|
+
vocalReverb: 0,
|
|
13316
|
+
vocalGender: 50,
|
|
13317
|
+
vocalBreathiness: 50,
|
|
13318
|
+
trackInstrument: "",
|
|
13319
|
+
trackCompression: 0,
|
|
13320
|
+
trackWidth: 100
|
|
12855
13321
|
};
|
|
12856
13322
|
});
|
|
12857
13323
|
};
|
|
12858
13324
|
const buildLyricsMap = () => {
|
|
12859
13325
|
const map = /* @__PURE__ */ new Map();
|
|
12860
|
-
trackStates.forEach((t,
|
|
13326
|
+
trackStates.forEach((t, i2) => {
|
|
12861
13327
|
const model = t.lyricModel.trim();
|
|
12862
13328
|
const text = t.lyrics.trim();
|
|
12863
13329
|
if (!model || !text) return;
|
|
12864
13330
|
const syllables = normalizeLyrics(text);
|
|
12865
13331
|
if (syllables.length === 0) return;
|
|
12866
|
-
map.set(
|
|
12867
|
-
trackId:
|
|
13332
|
+
map.set(i2, {
|
|
13333
|
+
trackId: i2,
|
|
12868
13334
|
model: model.toLowerCase(),
|
|
12869
13335
|
volume: t.vocalVolume,
|
|
12870
13336
|
gate: t.vocalGate,
|
|
12871
13337
|
pan: t.vocalPan,
|
|
12872
13338
|
octave: t.vocalOctave,
|
|
13339
|
+
vibrato: t.vocalVibrato,
|
|
13340
|
+
reverb: t.vocalReverb,
|
|
13341
|
+
gender: t.vocalGender,
|
|
13342
|
+
breathiness: t.vocalBreathiness,
|
|
12873
13343
|
syllables
|
|
12874
13344
|
});
|
|
12875
13345
|
});
|
|
@@ -12909,15 +13379,15 @@ var mountDAW = (target, options = {}) => {
|
|
|
12909
13379
|
const ctx = getGridContext();
|
|
12910
13380
|
const canvas = getGridCanvas();
|
|
12911
13381
|
if (!ctx) return;
|
|
12912
|
-
const
|
|
12913
|
-
if (
|
|
13382
|
+
const x2 = playStartStep * renderConfig.stepWidth - currentOffsetX;
|
|
13383
|
+
if (x2 < -10 || x2 > canvas.width + 10) return;
|
|
12914
13384
|
ctx.save();
|
|
12915
13385
|
ctx.strokeStyle = "#ffec27";
|
|
12916
13386
|
ctx.lineWidth = 2;
|
|
12917
13387
|
ctx.setLineDash([4, 4]);
|
|
12918
13388
|
ctx.beginPath();
|
|
12919
|
-
ctx.moveTo(
|
|
12920
|
-
ctx.lineTo(
|
|
13389
|
+
ctx.moveTo(x2, 0);
|
|
13390
|
+
ctx.lineTo(x2, canvas.height);
|
|
12921
13391
|
ctx.stroke();
|
|
12922
13392
|
ctx.restore();
|
|
12923
13393
|
};
|
|
@@ -12925,14 +13395,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
12925
13395
|
const ctx = getGridContext();
|
|
12926
13396
|
const canvas = getGridCanvas();
|
|
12927
13397
|
if (!ctx) return;
|
|
12928
|
-
const
|
|
12929
|
-
if (
|
|
13398
|
+
const x2 = currentPlayStep * renderConfig.stepWidth - currentOffsetX;
|
|
13399
|
+
if (x2 < 0 || x2 > canvas.width) return;
|
|
12930
13400
|
ctx.save();
|
|
12931
13401
|
ctx.strokeStyle = "#ff004d";
|
|
12932
13402
|
ctx.lineWidth = 2;
|
|
12933
13403
|
ctx.beginPath();
|
|
12934
|
-
ctx.moveTo(
|
|
12935
|
-
ctx.lineTo(
|
|
13404
|
+
ctx.moveTo(x2, 0);
|
|
13405
|
+
ctx.lineTo(x2, canvas.height);
|
|
12936
13406
|
ctx.stroke();
|
|
12937
13407
|
ctx.restore();
|
|
12938
13408
|
};
|
|
@@ -13060,8 +13530,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
13060
13530
|
if (maxOffsetX <= 0) return;
|
|
13061
13531
|
const rect = refs.hScroll.getBoundingClientRect();
|
|
13062
13532
|
const thumbW = Number.parseFloat(refs.hScrollThumb.style.width) || 40;
|
|
13063
|
-
const
|
|
13064
|
-
const ratio =
|
|
13533
|
+
const x2 = clamp3(clientX - rect.left - thumbW / 2, 0, rect.width - thumbW);
|
|
13534
|
+
const ratio = x2 / (rect.width - thumbW);
|
|
13065
13535
|
currentOffsetX = clamp3(ratio * maxOffsetX, 0, maxOffsetX);
|
|
13066
13536
|
setDrawOffset(currentOffsetX, currentOffsetY);
|
|
13067
13537
|
redrawAll();
|
|
@@ -13088,13 +13558,60 @@ var mountDAW = (target, options = {}) => {
|
|
|
13088
13558
|
let selectionStart = null;
|
|
13089
13559
|
let selectedOriginal = [];
|
|
13090
13560
|
let lastMultiPreviewPitch = null;
|
|
13561
|
+
const AUTO_SCROLL_MARGIN = 30;
|
|
13562
|
+
const AUTO_SCROLL_MAX_SPEED = 22;
|
|
13563
|
+
let autoScrollRAF = null;
|
|
13564
|
+
let lastMoveEvent = null;
|
|
13565
|
+
const computeEdgeSpeed = (pos, size) => {
|
|
13566
|
+
if (pos < AUTO_SCROLL_MARGIN) {
|
|
13567
|
+
const t = (AUTO_SCROLL_MARGIN - pos) / AUTO_SCROLL_MARGIN;
|
|
13568
|
+
return -Math.ceil(t * AUTO_SCROLL_MAX_SPEED);
|
|
13569
|
+
}
|
|
13570
|
+
if (pos > size - AUTO_SCROLL_MARGIN) {
|
|
13571
|
+
const t = (pos - (size - AUTO_SCROLL_MARGIN)) / AUTO_SCROLL_MARGIN;
|
|
13572
|
+
return Math.ceil(t * AUTO_SCROLL_MAX_SPEED);
|
|
13573
|
+
}
|
|
13574
|
+
return 0;
|
|
13575
|
+
};
|
|
13576
|
+
const stopAutoScroll = () => {
|
|
13577
|
+
if (autoScrollRAF !== null) {
|
|
13578
|
+
cancelAnimationFrame(autoScrollRAF);
|
|
13579
|
+
autoScrollRAF = null;
|
|
13580
|
+
}
|
|
13581
|
+
lastMoveEvent = null;
|
|
13582
|
+
};
|
|
13583
|
+
const autoScrollTick = () => {
|
|
13584
|
+
autoScrollRAF = null;
|
|
13585
|
+
if (!isSelecting || !lastMoveEvent) return;
|
|
13586
|
+
const canvas = getGridCanvas();
|
|
13587
|
+
const { x: x2, y } = getGridPosition(lastMoveEvent);
|
|
13588
|
+
const dx = computeEdgeSpeed(x2, canvas.width);
|
|
13589
|
+
const dy = computeEdgeSpeed(y, canvas.height);
|
|
13590
|
+
if (dx !== 0 || dy !== 0) {
|
|
13591
|
+
const maxOffsetX = getMaxOffsetX();
|
|
13592
|
+
const maxOffsetY = getMaxOffsetY();
|
|
13593
|
+
currentOffsetX = clamp3(currentOffsetX + dx, 0, maxOffsetX);
|
|
13594
|
+
currentOffsetY = clamp3(currentOffsetY + dy, 0, maxOffsetY);
|
|
13595
|
+
setDrawOffset(currentOffsetX, currentOffsetY);
|
|
13596
|
+
onPointerMove(lastMoveEvent);
|
|
13597
|
+
}
|
|
13598
|
+
if (isSelecting) {
|
|
13599
|
+
autoScrollRAF = requestAnimationFrame(autoScrollTick);
|
|
13600
|
+
}
|
|
13601
|
+
};
|
|
13602
|
+
const ensureAutoScroll = (event) => {
|
|
13603
|
+
lastMoveEvent = event;
|
|
13604
|
+
if (autoScrollRAF === null) {
|
|
13605
|
+
autoScrollRAF = requestAnimationFrame(autoScrollTick);
|
|
13606
|
+
}
|
|
13607
|
+
};
|
|
13091
13608
|
const playPreview = (pitch) => {
|
|
13092
13609
|
if (isLoading) return;
|
|
13093
13610
|
options.onResumeAudio?.();
|
|
13094
13611
|
const active = getActive();
|
|
13095
13612
|
dispatchNote(active.config.id, pitch, active.volume, 100, 0, 0.5);
|
|
13096
13613
|
};
|
|
13097
|
-
const findActiveNoteAt = (
|
|
13614
|
+
const findActiveNoteAt = (x2, y, margin = 0) => {
|
|
13098
13615
|
const active = getActive();
|
|
13099
13616
|
const { stepWidth, keyHeight, keyCount, pitchRangeStart } = renderConfig;
|
|
13100
13617
|
const offset = getDrawOffset();
|
|
@@ -13105,7 +13622,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13105
13622
|
const w = note.durationSteps * stepWidth;
|
|
13106
13623
|
const renderX = logicalX - offset.x;
|
|
13107
13624
|
const renderY = logicalY - offset.y;
|
|
13108
|
-
if (
|
|
13625
|
+
if (x2 >= renderX - margin && x2 <= renderX + w + margin && y >= renderY - margin && y <= renderY + keyHeight + margin)
|
|
13109
13626
|
return note;
|
|
13110
13627
|
}
|
|
13111
13628
|
return null;
|
|
@@ -13124,17 +13641,17 @@ var mountDAW = (target, options = {}) => {
|
|
|
13124
13641
|
const onGridPointerDown = (event) => {
|
|
13125
13642
|
event.preventDefault();
|
|
13126
13643
|
options.onResumeAudio?.();
|
|
13127
|
-
const { x, y, step, pitch } = getGridPosition(event);
|
|
13644
|
+
const { x: x2, y, step, pitch } = getGridPosition(event);
|
|
13128
13645
|
const active = getActive();
|
|
13129
13646
|
if (activeToolMode === "eraser") {
|
|
13130
13647
|
if (isActiveLocked()) return;
|
|
13131
|
-
const note = findActiveNoteAt(
|
|
13648
|
+
const note = findActiveNoteAt(x2, y);
|
|
13132
13649
|
if (note) active.core.deleteNoteById(note.id);
|
|
13133
13650
|
return;
|
|
13134
13651
|
}
|
|
13135
13652
|
if (activeToolMode === "select") {
|
|
13136
13653
|
if (selectedNotes.length > 0) {
|
|
13137
|
-
const clicked2 = findActiveNoteAt(
|
|
13654
|
+
const clicked2 = findActiveNoteAt(x2, y);
|
|
13138
13655
|
if (clicked2 && selectedNotes.some((n) => n.id === clicked2.id)) {
|
|
13139
13656
|
selectedOriginal = selectedNotes.map((n) => ({
|
|
13140
13657
|
id: n.id,
|
|
@@ -13143,7 +13660,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13143
13660
|
}));
|
|
13144
13661
|
isSelecting = true;
|
|
13145
13662
|
dragMode = "move";
|
|
13146
|
-
selectionStart = { x, y, step, pitch };
|
|
13663
|
+
selectionStart = { x: x2, y, step, pitch };
|
|
13147
13664
|
hasDragged = false;
|
|
13148
13665
|
lastMultiPreviewPitch = null;
|
|
13149
13666
|
return;
|
|
@@ -13151,7 +13668,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13151
13668
|
selectedNotes = [];
|
|
13152
13669
|
selectionRect = null;
|
|
13153
13670
|
}
|
|
13154
|
-
const clicked = findActiveNoteAt(
|
|
13671
|
+
const clicked = findActiveNoteAt(x2, y);
|
|
13155
13672
|
if (clicked) {
|
|
13156
13673
|
selectedNotes = [clicked];
|
|
13157
13674
|
selectedOriginal = [
|
|
@@ -13169,19 +13686,19 @@ var mountDAW = (target, options = {}) => {
|
|
|
13169
13686
|
isSelecting = true;
|
|
13170
13687
|
dragMode = "rect";
|
|
13171
13688
|
}
|
|
13172
|
-
selectionStart = { x, y, step, pitch };
|
|
13689
|
+
selectionStart = { x: x2, y, step, pitch };
|
|
13173
13690
|
hasDragged = false;
|
|
13174
13691
|
return;
|
|
13175
13692
|
}
|
|
13176
13693
|
hasDragged = false;
|
|
13177
|
-
const existing = findActiveNoteAt(
|
|
13694
|
+
const existing = findActiveNoteAt(x2, y, TOUCH_HIT_MARGIN);
|
|
13178
13695
|
if (existing) {
|
|
13179
13696
|
playPreview(existing.pitch);
|
|
13180
13697
|
const { stepWidth } = renderConfig;
|
|
13181
13698
|
const offset = getDrawOffset();
|
|
13182
13699
|
const renderX = existing.startStep * stepWidth - offset.x;
|
|
13183
13700
|
const w = existing.durationSteps * stepWidth;
|
|
13184
|
-
if (
|
|
13701
|
+
if (x2 >= renderX + w - resizeHandleWidth && x2 <= renderX + w) {
|
|
13185
13702
|
dragState = {
|
|
13186
13703
|
noteId: existing.id,
|
|
13187
13704
|
mode: "resize",
|
|
@@ -13260,12 +13777,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
13260
13777
|
return;
|
|
13261
13778
|
}
|
|
13262
13779
|
if (activeToolMode === "select" && isSelecting && selectionStart) {
|
|
13263
|
-
|
|
13780
|
+
ensureAutoScroll(event);
|
|
13781
|
+
const { x: x2, y, step, pitch } = getGridPosition(event);
|
|
13264
13782
|
if (dragMode === "rect") {
|
|
13265
13783
|
const rect = {
|
|
13266
|
-
x: Math.min(
|
|
13784
|
+
x: Math.min(x2, selectionStart.x),
|
|
13267
13785
|
y: Math.min(y, selectionStart.y),
|
|
13268
|
-
width: Math.abs(
|
|
13786
|
+
width: Math.abs(x2 - selectionStart.x),
|
|
13269
13787
|
height: Math.abs(y - selectionStart.y)
|
|
13270
13788
|
};
|
|
13271
13789
|
selectionRect = rect;
|
|
@@ -13278,7 +13796,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
13278
13796
|
const nx = logicalX - offset.x;
|
|
13279
13797
|
const ny = logicalY - offset.y;
|
|
13280
13798
|
const nw = note.durationSteps * stepWidth;
|
|
13281
|
-
return rect.x
|
|
13799
|
+
return nx >= rect.x && nx + nw <= rect.x + rect.width && ny >= rect.y && ny + keyHeight <= rect.y + rect.height;
|
|
13282
13800
|
});
|
|
13283
13801
|
redrawAll();
|
|
13284
13802
|
} else {
|
|
@@ -13335,8 +13853,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
13335
13853
|
selectionStart = null;
|
|
13336
13854
|
hasDragged = false;
|
|
13337
13855
|
lastMultiPreviewPitch = null;
|
|
13338
|
-
|
|
13856
|
+
if (dragMode !== "rect" || selectedNotes.length === 0) {
|
|
13857
|
+
selectionRect = null;
|
|
13858
|
+
}
|
|
13339
13859
|
selectedOriginal = [];
|
|
13860
|
+
stopAutoScroll();
|
|
13340
13861
|
redrawAll();
|
|
13341
13862
|
}
|
|
13342
13863
|
};
|
|
@@ -13484,8 +14005,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
13484
14005
|
headerCanvas.addEventListener("click", (event) => {
|
|
13485
14006
|
if (playbackState === "playing") return;
|
|
13486
14007
|
const rect = headerCanvas.getBoundingClientRect();
|
|
13487
|
-
const
|
|
13488
|
-
const step = Math.floor((
|
|
14008
|
+
const x2 = event.clientX - rect.left;
|
|
14009
|
+
const step = Math.floor((x2 + currentOffsetX) / renderConfig.stepWidth);
|
|
13489
14010
|
playStartStep = Math.max(
|
|
13490
14011
|
0,
|
|
13491
14012
|
Math.floor(step / snapGridSteps) * snapGridSteps
|
|
@@ -13606,11 +14127,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
13606
14127
|
const semis = (lt.octave ?? 0) * 12;
|
|
13607
14128
|
const count = Math.min(sorted.length, lt.syllables.length);
|
|
13608
14129
|
const notes = [];
|
|
13609
|
-
for (let
|
|
13610
|
-
const n = sorted[
|
|
14130
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
14131
|
+
const n = sorted[i2];
|
|
13611
14132
|
if (n.startStep < fromStep) continue;
|
|
13612
14133
|
notes.push({
|
|
13613
|
-
syllable: lt.syllables[
|
|
14134
|
+
syllable: lt.syllables[i2],
|
|
13614
14135
|
pitch: n.pitch + semis,
|
|
13615
14136
|
startSec: (n.startStep - fromStep) * secondsPerStep,
|
|
13616
14137
|
durationSec: n.durationSteps * secondsPerStep * gate
|
|
@@ -13621,6 +14142,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
13621
14142
|
model: lt.model,
|
|
13622
14143
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
13623
14144
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
14145
|
+
vibrato: lt.vibrato,
|
|
14146
|
+
reverbSend: (lt.reverb ?? 0) / 100,
|
|
14147
|
+
gender: (lt.gender ?? 50) / 100,
|
|
14148
|
+
breathiness: (lt.breathiness ?? 50) / 100,
|
|
13624
14149
|
notes
|
|
13625
14150
|
};
|
|
13626
14151
|
}) : [];
|
|
@@ -13709,13 +14234,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
13709
14234
|
const updateTrackPanel = () => {
|
|
13710
14235
|
refs.trackTabs.innerHTML = "";
|
|
13711
14236
|
trackPillEls.clear();
|
|
13712
|
-
for (const [
|
|
14237
|
+
for (const [i2, t] of trackStates.entries()) {
|
|
13713
14238
|
const [r, g, b] = t.config.color;
|
|
13714
14239
|
const btn = document.createElement("button");
|
|
13715
14240
|
btn.className = `dtm-pill ${t.config.id === activeTrackId ? "dtm-pill--active" : ""}`;
|
|
13716
14241
|
btn.style.setProperty("--dtm-pill-color", `rgb(${r},${g},${b})`);
|
|
13717
14242
|
btn.title = t.config.name;
|
|
13718
|
-
btn.textContent = String(
|
|
14243
|
+
btn.textContent = String(i2 + 1);
|
|
13719
14244
|
btn.addEventListener("click", () => switchTrack(t.config.id));
|
|
13720
14245
|
refs.trackTabs.appendChild(btn);
|
|
13721
14246
|
trackPillEls.set(t.config.id, btn);
|
|
@@ -13726,7 +14251,22 @@ var mountDAW = (target, options = {}) => {
|
|
|
13726
14251
|
<span class="dtm-label">\u30D9\u30ED\u30B7\u30C6\u30A3</span>
|
|
13727
14252
|
<input type="range" class="dtm-range dtm-grow" data-dtm="track-vol" min="0" max="127" value="${active.volume}">
|
|
13728
14253
|
<span class="dtm-label" data-dtm="track-vol-label">${active.volume}</span>
|
|
13729
|
-
</div
|
|
14254
|
+
</div>
|
|
14255
|
+
<details class="dtm-advanced" data-dtm="track-fx-advanced">
|
|
14256
|
+
<summary>\u8A73\u7D30\u8A2D\u5B9A\uFF08\u97F3\u5727\u30FB\u30B9\u30C6\u30EC\u30AA\u5E45\uFF09</summary>
|
|
14257
|
+
<div class="dtm-row">
|
|
14258
|
+
<span class="dtm-label">\u97F3\u5727\u5F37\u5316</span>
|
|
14259
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="track-comp" min="0" max="100" aria-label="\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u30B3\u30F3\u30D7\u30EC\u30C3\u30B5\u30FC\u91CF\uFF08\u97F3\u5727\u5F37\u5316\uFF09">
|
|
14260
|
+
<span class="dtm-label" data-dtm="track-comp-label"></span>
|
|
14261
|
+
<button class="dtm-infobtn" data-dtm="track-comp-info" title="\u97F3\u5727\u5F37\u5316\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
14262
|
+
</div>
|
|
14263
|
+
<div class="dtm-row">
|
|
14264
|
+
<span class="dtm-label">\u30B9\u30C6\u30EC\u30AA\u5E45</span>
|
|
14265
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="track-width" min="0" max="200" aria-label="\u3053\u306E\u30C8\u30E9\u30C3\u30AF\u306E\u30B9\u30C6\u30EC\u30AA\u5E45\uFF08100=\u539F\u97F3\u30010=\u30E2\u30CE\u30E9\u30EB\uFF09">
|
|
14266
|
+
<span class="dtm-label" data-dtm="track-width-label"></span>
|
|
14267
|
+
<button class="dtm-infobtn" data-dtm="track-width-info" title="\u30B9\u30C6\u30EC\u30AA\u5E45\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
14268
|
+
</div>
|
|
14269
|
+
</details>`;
|
|
13730
14270
|
const volInput = refs.trackBody.querySelector(
|
|
13731
14271
|
'[data-dtm="track-vol"]'
|
|
13732
14272
|
);
|
|
@@ -13743,6 +14283,47 @@ var mountDAW = (target, options = {}) => {
|
|
|
13743
14283
|
volInput.title = active.lyricModel ? "\u6B4C\u8A5E\u30E2\u30FC\u30C9\u306E\u3068\u304D\u306F\u30D9\u30ED\u30B7\u30C6\u30A3\u304C\u518D\u751F\u306B\u53CD\u6620\u3055\u308C\u307E\u305B\u3093\uFF08\u58F0\u91CF\u3067\u8ABF\u6574\u3057\u3066\u304F\u3060\u3055\u3044\uFF09" : "";
|
|
13744
14284
|
};
|
|
13745
14285
|
syncVelocityDisabled();
|
|
14286
|
+
const trackCompInput = refs.trackBody.querySelector(
|
|
14287
|
+
'[data-dtm="track-comp"]'
|
|
14288
|
+
);
|
|
14289
|
+
const trackCompLabel = refs.trackBody.querySelector(
|
|
14290
|
+
'[data-dtm="track-comp-label"]'
|
|
14291
|
+
);
|
|
14292
|
+
const trackWidthInput = refs.trackBody.querySelector(
|
|
14293
|
+
'[data-dtm="track-width"]'
|
|
14294
|
+
);
|
|
14295
|
+
const trackWidthLabel = refs.trackBody.querySelector(
|
|
14296
|
+
'[data-dtm="track-width-label"]'
|
|
14297
|
+
);
|
|
14298
|
+
const trackCompInfo = refs.trackBody.querySelector(
|
|
14299
|
+
'[data-dtm="track-comp-info"]'
|
|
14300
|
+
);
|
|
14301
|
+
const trackWidthInfo = refs.trackBody.querySelector(
|
|
14302
|
+
'[data-dtm="track-width-info"]'
|
|
14303
|
+
);
|
|
14304
|
+
trackCompInput.value = String(active.trackCompression);
|
|
14305
|
+
trackCompLabel.textContent = `${active.trackCompression}%`;
|
|
14306
|
+
trackWidthInput.value = String(active.trackWidth);
|
|
14307
|
+
trackWidthLabel.textContent = `${active.trackWidth}%`;
|
|
14308
|
+
trackCompInput.addEventListener("input", () => {
|
|
14309
|
+
active.trackCompression = Number.parseInt(trackCompInput.value, 10);
|
|
14310
|
+
trackCompLabel.textContent = `${active.trackCompression}%`;
|
|
14311
|
+
options.onTrackCompressionChange?.(
|
|
14312
|
+
active.config.id,
|
|
14313
|
+
active.trackCompression
|
|
14314
|
+
);
|
|
14315
|
+
});
|
|
14316
|
+
trackWidthInput.addEventListener("input", () => {
|
|
14317
|
+
active.trackWidth = Number.parseInt(trackWidthInput.value, 10);
|
|
14318
|
+
trackWidthLabel.textContent = `${active.trackWidth}%`;
|
|
14319
|
+
options.onTrackWidthChange?.(active.config.id, active.trackWidth);
|
|
14320
|
+
});
|
|
14321
|
+
trackCompInfo.addEventListener("click", () => {
|
|
14322
|
+
showModal("\u97F3\u5727\u5F37\u5316\u306E\u89E3\u8AAC", TRACK_COMPRESSION_INFO_HTML);
|
|
14323
|
+
});
|
|
14324
|
+
trackWidthInfo.addEventListener("click", () => {
|
|
14325
|
+
showModal("\u30B9\u30C6\u30EC\u30AA\u5E45\u306E\u89E3\u8AAC", TRACK_WIDTH_INFO_HTML);
|
|
14326
|
+
});
|
|
13746
14327
|
const instRow = document.createElement("div");
|
|
13747
14328
|
instRow.className = "dtm-row";
|
|
13748
14329
|
instRow.innerHTML = `<span class="dtm-label">\u697D\u5668</span>`;
|
|
@@ -13806,13 +14387,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
13806
14387
|
<span class="dtm-label">\u266A UTAU</span>
|
|
13807
14388
|
<select class="dtm-select" data-dtm="lyric-model" aria-label="\u6B4C\u5531\u30E2\u30C7\u30EB"></select>
|
|
13808
14389
|
<img class="dtm-lyric-icon dtm-hidden" data-dtm="lyric-icon" width="20" height="20" alt="" draggable="false">
|
|
13809
|
-
<select class="dtm-select" data-dtm="lyric-octave" aria-label="\u30AA\u30AF\u30BF\u30FC\u30D6\uFF08\u97F3\u6E90\u306E\u5F97\u610F\u97F3\u57DF\u306B\u5408\u308F\u305B\u308B\uFF09" title="\u30AA\u30AF\u30BF\u30FC\u30D6">
|
|
13810
|
-
<option value="2">+2 oct</option>
|
|
13811
|
-
<option value="1">+1 oct</option>
|
|
13812
|
-
<option value="0">\xB10 oct</option>
|
|
13813
|
-
<option value="-1">-1 oct</option>
|
|
13814
|
-
<option value="-2">-2 oct</option>
|
|
13815
|
-
</select>
|
|
13816
14390
|
<span class="dtm-label dtm-grow" data-dtm="lyric-count" style="text-align:right"></span>
|
|
13817
14391
|
</div>
|
|
13818
14392
|
<div class="dtm-row dtm-hidden" data-dtm="lyric-terms" style="font-size:10px;gap:4px;color:var(--dtm-warn)">
|
|
@@ -13838,11 +14412,48 @@ var mountDAW = (target, options = {}) => {
|
|
|
13838
14412
|
<input type="range" class="dtm-range dtm-grow" data-dtm="lyric-vol" min="0" max="${MAX_VOCAL_VOLUME}" aria-label="\u6B4C\u5531\u306E\u58F0\u91CF\uFF08100=\u7B49\u500D\u3001100\u8D85\u3067\u30D6\u30FC\u30B9\u30C8\u3001\u65E2\u5B9A200\uFF09">
|
|
13839
14413
|
<span class="dtm-label" data-dtm="lyric-vol-label"></span>
|
|
13840
14414
|
</div>
|
|
13841
|
-
<
|
|
13842
|
-
<
|
|
13843
|
-
<
|
|
13844
|
-
|
|
13845
|
-
|
|
14415
|
+
<details class="dtm-advanced" data-dtm="lyric-advanced">
|
|
14416
|
+
<summary>\u8A73\u7D30\u8A2D\u5B9A</summary>
|
|
14417
|
+
<div class="dtm-row">
|
|
14418
|
+
<span class="dtm-label">\u30AA\u30AF\u30BF\u30FC\u30D6</span>
|
|
14419
|
+
<select class="dtm-select" data-dtm="lyric-octave" aria-label="\u30AA\u30AF\u30BF\u30FC\u30D6\uFF08\u97F3\u6E90\u306E\u5F97\u610F\u97F3\u57DF\u306B\u5408\u308F\u305B\u308B\uFF09" title="\u30AA\u30AF\u30BF\u30FC\u30D6">
|
|
14420
|
+
<option value="2">+2 oct</option>
|
|
14421
|
+
<option value="1">+1 oct</option>
|
|
14422
|
+
<option value="0">\xB10 oct</option>
|
|
14423
|
+
<option value="-1">-1 oct</option>
|
|
14424
|
+
<option value="-2">-2 oct</option>
|
|
14425
|
+
</select>
|
|
14426
|
+
</div>
|
|
14427
|
+
<div class="dtm-row">
|
|
14428
|
+
<span class="dtm-label">\u5B9A\u4F4D</span>
|
|
14429
|
+
<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">
|
|
14430
|
+
<span class="dtm-label" data-dtm="lyric-pan-label"></span>
|
|
14431
|
+
</div>
|
|
14432
|
+
<div class="dtm-row">
|
|
14433
|
+
<span class="dtm-label">\u30EA\u30D0\u30FC\u30D6\u9001\u308A</span>
|
|
14434
|
+
<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">
|
|
14435
|
+
<span class="dtm-label" data-dtm="lyric-reverb-label"></span>
|
|
14436
|
+
<button class="dtm-infobtn" data-dtm="lyric-reverb-info" title="\u30EA\u30D0\u30FC\u30D6\u9001\u308A\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
14437
|
+
</div>
|
|
14438
|
+
<div class="dtm-row">
|
|
14439
|
+
<span class="dtm-label">\u30B8\u30A7\u30F3\u30C0\u30FC</span>
|
|
14440
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="lyric-gender" min="0" max="100" aria-label="\u30D5\u30A9\u30EB\u30DE\u30F3\u30C8/\u30B8\u30A7\u30F3\u30C0\u30FC\u30D5\u30A1\u30AF\u30BF\u30FC\uFF08koe\u97F3\u6E90\u9650\u5B9A\uFF09">
|
|
14441
|
+
<span class="dtm-label" data-dtm="lyric-gender-label"></span>
|
|
14442
|
+
<button class="dtm-infobtn" data-dtm="lyric-gender-info" title="\u30B8\u30A7\u30F3\u30C0\u30FC\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
14443
|
+
</div>
|
|
14444
|
+
<div class="dtm-row">
|
|
14445
|
+
<span class="dtm-label">\u30D6\u30EC\u30B7\u30CD\u30B9</span>
|
|
14446
|
+
<input type="range" class="dtm-range dtm-grow" data-dtm="lyric-breathiness" min="0" max="100" aria-label="\u30D6\u30EC\u30B7\u30CD\u30B9\uFF08\u606F\u6210\u5206\u3001koe\u97F3\u6E90\u9650\u5B9A\uFF09">
|
|
14447
|
+
<span class="dtm-label" data-dtm="lyric-breathiness-label"></span>
|
|
14448
|
+
<button class="dtm-infobtn" data-dtm="lyric-breathiness-info" title="\u30D6\u30EC\u30B7\u30CD\u30B9\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
14449
|
+
</div>
|
|
14450
|
+
<div class="dtm-row">
|
|
14451
|
+
<span class="dtm-label" style="display:inline-flex;align-items:center;gap:2px">
|
|
14452
|
+
<input type="checkbox" data-dtm="lyric-vibrato" aria-label="\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8">\u30D3\u30D6\u30E9\u30FC\u30C8
|
|
14453
|
+
</span>
|
|
14454
|
+
<button class="dtm-infobtn" data-dtm="lyric-vibrato-info" title="\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u306E\u89E3\u8AAC">${icon("info", 12)}</button>
|
|
14455
|
+
</div>
|
|
14456
|
+
</details>
|
|
13846
14457
|
<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>
|
|
13847
14458
|
</div>`;
|
|
13848
14459
|
refs.trackBody.appendChild(lyricDiv);
|
|
@@ -13876,6 +14487,51 @@ var mountDAW = (target, options = {}) => {
|
|
|
13876
14487
|
const lyricPanLabel = lyricDiv.querySelector(
|
|
13877
14488
|
'[data-dtm="lyric-pan-label"]'
|
|
13878
14489
|
);
|
|
14490
|
+
const lyricReverb = lyricDiv.querySelector(
|
|
14491
|
+
'[data-dtm="lyric-reverb"]'
|
|
14492
|
+
);
|
|
14493
|
+
const lyricReverbLabel = lyricDiv.querySelector(
|
|
14494
|
+
'[data-dtm="lyric-reverb-label"]'
|
|
14495
|
+
);
|
|
14496
|
+
const lyricReverbInfo = lyricDiv.querySelector(
|
|
14497
|
+
'[data-dtm="lyric-reverb-info"]'
|
|
14498
|
+
);
|
|
14499
|
+
lyricReverbInfo.addEventListener("click", () => {
|
|
14500
|
+
showModal("\u30EA\u30D0\u30FC\u30D6\u9001\u308A\u306E\u89E3\u8AAC", LYRIC_REVERB_INFO_HTML);
|
|
14501
|
+
});
|
|
14502
|
+
const lyricGender = lyricDiv.querySelector(
|
|
14503
|
+
'[data-dtm="lyric-gender"]'
|
|
14504
|
+
);
|
|
14505
|
+
const lyricGenderLabel = lyricDiv.querySelector(
|
|
14506
|
+
'[data-dtm="lyric-gender-label"]'
|
|
14507
|
+
);
|
|
14508
|
+
const lyricGenderInfo = lyricDiv.querySelector(
|
|
14509
|
+
'[data-dtm="lyric-gender-info"]'
|
|
14510
|
+
);
|
|
14511
|
+
lyricGenderInfo.addEventListener("click", () => {
|
|
14512
|
+
showModal("\u30B8\u30A7\u30F3\u30C0\u30FC\u306E\u89E3\u8AAC", GENDER_INFO_HTML);
|
|
14513
|
+
});
|
|
14514
|
+
const lyricBreathiness = lyricDiv.querySelector(
|
|
14515
|
+
'[data-dtm="lyric-breathiness"]'
|
|
14516
|
+
);
|
|
14517
|
+
const lyricBreathinessLabel = lyricDiv.querySelector(
|
|
14518
|
+
'[data-dtm="lyric-breathiness-label"]'
|
|
14519
|
+
);
|
|
14520
|
+
const lyricBreathinessInfo = lyricDiv.querySelector(
|
|
14521
|
+
'[data-dtm="lyric-breathiness-info"]'
|
|
14522
|
+
);
|
|
14523
|
+
lyricBreathinessInfo.addEventListener("click", () => {
|
|
14524
|
+
showModal("\u30D6\u30EC\u30B7\u30CD\u30B9\u306E\u89E3\u8AAC", BREATHINESS_INFO_HTML);
|
|
14525
|
+
});
|
|
14526
|
+
const lyricVibrato = lyricDiv.querySelector(
|
|
14527
|
+
'[data-dtm="lyric-vibrato"]'
|
|
14528
|
+
);
|
|
14529
|
+
const lyricVibratoInfo = lyricDiv.querySelector(
|
|
14530
|
+
'[data-dtm="lyric-vibrato-info"]'
|
|
14531
|
+
);
|
|
14532
|
+
lyricVibratoInfo.addEventListener("click", () => {
|
|
14533
|
+
showModal("\u81EA\u52D5\u30D3\u30D6\u30E9\u30FC\u30C8\u89E3\u8AAC", VIBRATO_INFO_HTML);
|
|
14534
|
+
});
|
|
13879
14535
|
const lyricTerms = lyricDiv.querySelector(
|
|
13880
14536
|
'[data-dtm="lyric-terms"]'
|
|
13881
14537
|
);
|
|
@@ -13937,6 +14593,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
13937
14593
|
lyricVolLabel.textContent = String(active.vocalVolume);
|
|
13938
14594
|
lyricPan.value = String(active.vocalPan);
|
|
13939
14595
|
lyricPanLabel.textContent = fmtPan(active.vocalPan);
|
|
14596
|
+
lyricReverb.value = String(active.vocalReverb);
|
|
14597
|
+
lyricReverbLabel.textContent = `${active.vocalReverb}%`;
|
|
14598
|
+
lyricGender.value = String(active.vocalGender);
|
|
14599
|
+
lyricGenderLabel.textContent = `${active.vocalGender}`;
|
|
14600
|
+
lyricBreathiness.value = String(active.vocalBreathiness);
|
|
14601
|
+
lyricBreathinessLabel.textContent = `${active.vocalBreathiness}`;
|
|
14602
|
+
lyricVibrato.checked = active.vocalVibrato;
|
|
13940
14603
|
const updateLyricCount = () => {
|
|
13941
14604
|
const n = normalizeLyrics(lyricInput.value).length;
|
|
13942
14605
|
lyricCount.textContent = active.lyricModel && n > 0 ? `${n}\u97F3\u7BC0` : "";
|
|
@@ -13986,7 +14649,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
13986
14649
|
};
|
|
13987
14650
|
const syncLyricVisibility = () => {
|
|
13988
14651
|
lyricBody.style.display = active.lyricModel ? "" : "none";
|
|
13989
|
-
lyricOctaveSel.style.display = active.lyricModel ? "" : "none";
|
|
13990
14652
|
updateLyricCount();
|
|
13991
14653
|
syncLyricTerms();
|
|
13992
14654
|
syncLyricIcon();
|
|
@@ -14055,6 +14717,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14055
14717
|
active.vocalOctave = Number.parseInt(lyricOctaveSel.value, 10);
|
|
14056
14718
|
fireLyricsChange(active);
|
|
14057
14719
|
});
|
|
14720
|
+
lyricVibrato.addEventListener("change", () => {
|
|
14721
|
+
active.vocalVibrato = lyricVibrato.checked;
|
|
14722
|
+
fireLyricsChange(active);
|
|
14723
|
+
});
|
|
14058
14724
|
lyricInput.addEventListener("input", () => {
|
|
14059
14725
|
active.lyrics = lyricInput.value;
|
|
14060
14726
|
updateLyricCount();
|
|
@@ -14078,6 +14744,21 @@ var mountDAW = (target, options = {}) => {
|
|
|
14078
14744
|
lyricPanLabel.textContent = fmtPan(64);
|
|
14079
14745
|
fireLyricsChange(active);
|
|
14080
14746
|
});
|
|
14747
|
+
lyricReverb.addEventListener("input", () => {
|
|
14748
|
+
active.vocalReverb = Number.parseInt(lyricReverb.value, 10);
|
|
14749
|
+
lyricReverbLabel.textContent = `${active.vocalReverb}%`;
|
|
14750
|
+
fireLyricsChange(active);
|
|
14751
|
+
});
|
|
14752
|
+
lyricGender.addEventListener("input", () => {
|
|
14753
|
+
active.vocalGender = Number.parseInt(lyricGender.value, 10);
|
|
14754
|
+
lyricGenderLabel.textContent = `${active.vocalGender}`;
|
|
14755
|
+
fireLyricsChange(active);
|
|
14756
|
+
});
|
|
14757
|
+
lyricBreathiness.addEventListener("input", () => {
|
|
14758
|
+
active.vocalBreathiness = Number.parseInt(lyricBreathiness.value, 10);
|
|
14759
|
+
lyricBreathinessLabel.textContent = `${active.vocalBreathiness}`;
|
|
14760
|
+
fireLyricsChange(active);
|
|
14761
|
+
});
|
|
14081
14762
|
}
|
|
14082
14763
|
if (active.config.id === "chord" && showChord) {
|
|
14083
14764
|
const div = document.createElement("div");
|
|
@@ -14161,18 +14842,28 @@ var mountDAW = (target, options = {}) => {
|
|
|
14161
14842
|
const limitSteps = barLimitBars > 0 ? barLimitBars * renderConfig.stepsPerBar : Infinity;
|
|
14162
14843
|
const clipNotes = (notes) => limitSteps === Infinity ? notes : notes.filter((n) => n.startStep < limitSteps);
|
|
14163
14844
|
const trackInstrumentsForMeta = {};
|
|
14164
|
-
|
|
14165
|
-
|
|
14845
|
+
const trackCompressionForMeta = {};
|
|
14846
|
+
const trackWidthForMeta = {};
|
|
14847
|
+
trackStates.forEach((t, i2) => {
|
|
14848
|
+
if (t.trackInstrument) trackInstrumentsForMeta[i2] = t.trackInstrument;
|
|
14849
|
+
if (t.trackCompression !== 0)
|
|
14850
|
+
trackCompressionForMeta[i2] = t.trackCompression;
|
|
14851
|
+
if (t.trackWidth !== 100) trackWidthForMeta[i2] = t.trackWidth;
|
|
14166
14852
|
});
|
|
14167
14853
|
const trackInstMeta = Object.keys(trackInstrumentsForMeta).length > 0 ? trackInstrumentsForMeta : void 0;
|
|
14854
|
+
const trackCompMeta = Object.keys(trackCompressionForMeta).length > 0 ? trackCompressionForMeta : void 0;
|
|
14855
|
+
const trackWidthMeta = Object.keys(trackWidthForMeta).length > 0 ? trackWidthForMeta : void 0;
|
|
14168
14856
|
const metaLineFull = formatMmlMeta(
|
|
14169
14857
|
{
|
|
14170
14858
|
instrument: currentInstrument || void 0,
|
|
14171
14859
|
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
14172
14860
|
volume: masterVolume,
|
|
14173
14861
|
drumVolume,
|
|
14862
|
+
reverb: reverbAmount,
|
|
14174
14863
|
mode,
|
|
14175
|
-
trackInstruments: trackInstMeta
|
|
14864
|
+
trackInstruments: trackInstMeta,
|
|
14865
|
+
trackCompression: trackCompMeta,
|
|
14866
|
+
trackWidth: trackWidthMeta
|
|
14176
14867
|
},
|
|
14177
14868
|
" "
|
|
14178
14869
|
);
|
|
@@ -14182,8 +14873,11 @@ var mountDAW = (target, options = {}) => {
|
|
|
14182
14873
|
drum: currentDrumPattern !== "none" ? currentDrumPattern : void 0,
|
|
14183
14874
|
volume: masterVolume,
|
|
14184
14875
|
drumVolume,
|
|
14876
|
+
reverb: reverbAmount,
|
|
14185
14877
|
mode,
|
|
14186
|
-
trackInstruments: trackInstMeta
|
|
14878
|
+
trackInstruments: trackInstMeta,
|
|
14879
|
+
trackCompression: trackCompMeta,
|
|
14880
|
+
trackWidth: trackWidthMeta
|
|
14187
14881
|
},
|
|
14188
14882
|
""
|
|
14189
14883
|
);
|
|
@@ -14197,10 +14891,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14197
14891
|
const monoTracks = decomposeToMonophonic(allNotes);
|
|
14198
14892
|
const refCore = trackStates[0].core;
|
|
14199
14893
|
const decomposedFull = monoTracks.map(
|
|
14200
|
-
(notes,
|
|
14894
|
+
(notes, i2) => `@${i2} ${refCore.getMMLFromNotes(notes, bpm, 100).trim()}`
|
|
14201
14895
|
);
|
|
14202
14896
|
const decomposedMini = monoTracks.map(
|
|
14203
|
-
(notes,
|
|
14897
|
+
(notes, i2) => `@${i2}${refCore.getMMLFromNotes(notes, bpm, 100).trim().replace(/\s+/g, "")}`
|
|
14204
14898
|
);
|
|
14205
14899
|
const full2 = [metaLineFull, ...decomposedFull, MML_END_MARKER].filter((s) => s.length > 0).join(";\n");
|
|
14206
14900
|
const minified2 = [metaLineMini, ...decomposedMini, MML_END_MARKER].filter((s) => s.length > 0).join(";");
|
|
@@ -14214,34 +14908,42 @@ var mountDAW = (target, options = {}) => {
|
|
|
14214
14908
|
}
|
|
14215
14909
|
const trackLines = [];
|
|
14216
14910
|
const trackLinesMini = [];
|
|
14217
|
-
trackStates.forEach((t,
|
|
14911
|
+
trackStates.forEach((t, i2) => {
|
|
14218
14912
|
const notes = clipNotes(t.core.getNotes());
|
|
14219
14913
|
if (notes.length > 0) {
|
|
14220
14914
|
const mml = t.core.getMMLFromNotes(notes, bpm, t.volume).trim();
|
|
14221
|
-
trackLines.push(`@${
|
|
14222
|
-
trackLinesMini.push(`@${
|
|
14915
|
+
trackLines.push(`@${i2} ${mml}`);
|
|
14916
|
+
trackLinesMini.push(`@${i2}${mml.replace(/\s+/g, "")}`);
|
|
14223
14917
|
}
|
|
14224
14918
|
});
|
|
14225
|
-
const lyricLines = trackStates.map((t,
|
|
14226
|
-
i,
|
|
14919
|
+
const lyricLines = trackStates.map((t, i2) => ({
|
|
14920
|
+
i: i2,
|
|
14227
14921
|
notes: clipNotes(t.core.getNotes()),
|
|
14228
14922
|
text: t.lyrics.replace(/[\r\n]+/g, " ").trim(),
|
|
14229
14923
|
model: t.lyricModel.trim(),
|
|
14230
14924
|
vol: t.vocalVolume,
|
|
14231
14925
|
gate: t.vocalGate,
|
|
14232
14926
|
pan: t.vocalPan,
|
|
14233
|
-
oct: t.vocalOctave
|
|
14927
|
+
oct: t.vocalOctave,
|
|
14928
|
+
vib: t.vocalVibrato,
|
|
14929
|
+
rev: t.vocalReverb,
|
|
14930
|
+
gen: t.vocalGender,
|
|
14931
|
+
bre: t.vocalBreathiness
|
|
14234
14932
|
})).filter(
|
|
14235
|
-
(
|
|
14236
|
-
).map((
|
|
14933
|
+
(x2) => x2.model.length > 0 && x2.text.length > 0 && x2.notes.length > 0
|
|
14934
|
+
).map((x2) => {
|
|
14237
14935
|
const params = [
|
|
14238
|
-
|
|
14239
|
-
|
|
14240
|
-
|
|
14241
|
-
|
|
14936
|
+
x2.vol === DEFAULT_VOCAL_VOLUME ? "" : `v${x2.vol}`,
|
|
14937
|
+
x2.gate === 100 ? "" : `q${x2.gate}`,
|
|
14938
|
+
x2.pan === 64 ? "" : `p${x2.pan}`,
|
|
14939
|
+
x2.oct === 0 ? "" : `o${x2.oct}`,
|
|
14940
|
+
x2.vib ? "b1" : "",
|
|
14941
|
+
x2.rev === 0 ? "" : `r${x2.rev}`,
|
|
14942
|
+
x2.gen === 50 ? "" : `g${x2.gen}`,
|
|
14943
|
+
x2.bre === 50 ? "" : `h${x2.bre}`
|
|
14242
14944
|
].filter((s) => s.length > 0).join(" ");
|
|
14243
|
-
const head = params ? `${
|
|
14244
|
-
return `@@${
|
|
14945
|
+
const head = params ? `${x2.model} ${params}` : x2.model;
|
|
14946
|
+
return `@@${x2.i} ${head} ${x2.text}`;
|
|
14245
14947
|
});
|
|
14246
14948
|
const customVocalDecls = [];
|
|
14247
14949
|
for (const [key, def] of customVocalsMap) {
|
|
@@ -14378,18 +15080,37 @@ var mountDAW = (target, options = {}) => {
|
|
|
14378
15080
|
refs.drumVolume.value = String(meta.drumVolume);
|
|
14379
15081
|
refs.drumVolumeLabel.textContent = `${drumVolume}%`;
|
|
14380
15082
|
}
|
|
15083
|
+
if (meta.reverb !== void 0) {
|
|
15084
|
+
reverbAmount = meta.reverb;
|
|
15085
|
+
refs.reverbAmount.value = String(meta.reverb);
|
|
15086
|
+
refs.reverbAmountLabel.textContent = `${meta.reverb}%`;
|
|
15087
|
+
options.onReverbChange?.(meta.reverb);
|
|
15088
|
+
}
|
|
14381
15089
|
}
|
|
14382
|
-
trackStates.forEach((t,
|
|
14383
|
-
if (applyActiveOnly &&
|
|
14384
|
-
const name = normalizeInstrumentName(meta.trackInstruments?.[
|
|
15090
|
+
trackStates.forEach((t, i2) => {
|
|
15091
|
+
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
15092
|
+
const name = normalizeInstrumentName(meta.trackInstruments?.[i2] ?? "");
|
|
14385
15093
|
if (t.trackInstrument !== name) {
|
|
14386
15094
|
t.trackInstrument = name;
|
|
14387
|
-
options.onTrackInstrumentChange?.(
|
|
15095
|
+
options.onTrackInstrumentChange?.(i2, name);
|
|
15096
|
+
}
|
|
15097
|
+
});
|
|
15098
|
+
trackStates.forEach((t, i2) => {
|
|
15099
|
+
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
15100
|
+
const comp = meta.trackCompression?.[i2] ?? 0;
|
|
15101
|
+
if (t.trackCompression !== comp) {
|
|
15102
|
+
t.trackCompression = comp;
|
|
15103
|
+
options.onTrackCompressionChange?.(t.config.id, comp);
|
|
15104
|
+
}
|
|
15105
|
+
const width = meta.trackWidth?.[i2] ?? 100;
|
|
15106
|
+
if (t.trackWidth !== width) {
|
|
15107
|
+
t.trackWidth = width;
|
|
15108
|
+
options.onTrackWidthChange?.(t.config.id, width);
|
|
14388
15109
|
}
|
|
14389
15110
|
});
|
|
14390
|
-
trackStates.forEach((t,
|
|
14391
|
-
if (applyActiveOnly &&
|
|
14392
|
-
const v = trackVelocity.get(
|
|
15111
|
+
trackStates.forEach((t, i2) => {
|
|
15112
|
+
if (applyActiveOnly && i2 !== activeTrackIndex) return;
|
|
15113
|
+
const v = trackVelocity.get(i2);
|
|
14393
15114
|
if (v !== void 0 && v !== t.volume) {
|
|
14394
15115
|
t.volume = v;
|
|
14395
15116
|
t.core.setVolume(v);
|
|
@@ -14403,6 +15124,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14403
15124
|
active.vocalGate = 100;
|
|
14404
15125
|
active.vocalPan = 64;
|
|
14405
15126
|
active.vocalOctave = 0;
|
|
15127
|
+
active.vocalVibrato = false;
|
|
15128
|
+
active.vocalReverb = 0;
|
|
15129
|
+
active.vocalGender = 50;
|
|
15130
|
+
active.vocalBreathiness = 50;
|
|
14406
15131
|
} else {
|
|
14407
15132
|
for (const t of trackStates) {
|
|
14408
15133
|
t.lyrics = "";
|
|
@@ -14411,6 +15136,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14411
15136
|
t.vocalGate = 100;
|
|
14412
15137
|
t.vocalPan = 64;
|
|
14413
15138
|
t.vocalOctave = 0;
|
|
15139
|
+
t.vocalVibrato = false;
|
|
15140
|
+
t.vocalReverb = 0;
|
|
15141
|
+
t.vocalGender = 50;
|
|
15142
|
+
t.vocalBreathiness = 50;
|
|
14414
15143
|
}
|
|
14415
15144
|
}
|
|
14416
15145
|
lyrics?.forEach((lt) => {
|
|
@@ -14423,6 +15152,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14423
15152
|
t.vocalGate = lt.gate;
|
|
14424
15153
|
t.vocalPan = lt.pan;
|
|
14425
15154
|
t.vocalOctave = lt.octave ?? 0;
|
|
15155
|
+
t.vocalVibrato = lt.vibrato ?? false;
|
|
15156
|
+
t.vocalReverb = lt.reverb ?? 0;
|
|
15157
|
+
t.vocalGender = lt.gender ?? 50;
|
|
15158
|
+
t.vocalBreathiness = lt.breathiness ?? 50;
|
|
14426
15159
|
});
|
|
14427
15160
|
for (const p of placements) {
|
|
14428
15161
|
if (applyActiveOnly && p.trackIndex !== activeTrackIndex) continue;
|
|
@@ -14501,6 +15234,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14501
15234
|
active.vocalGate = 100;
|
|
14502
15235
|
active.vocalPan = 64;
|
|
14503
15236
|
active.vocalOctave = 0;
|
|
15237
|
+
active.vocalVibrato = false;
|
|
15238
|
+
active.vocalReverb = 0;
|
|
15239
|
+
active.vocalGender = 50;
|
|
15240
|
+
active.vocalBreathiness = 50;
|
|
14504
15241
|
} else {
|
|
14505
15242
|
clearAll();
|
|
14506
15243
|
for (const t of trackStates) t.core.setLoadMode(true);
|
|
@@ -14511,6 +15248,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
14511
15248
|
t.vocalGate = 100;
|
|
14512
15249
|
t.vocalPan = 64;
|
|
14513
15250
|
t.vocalOctave = 0;
|
|
15251
|
+
t.vocalVibrato = false;
|
|
15252
|
+
t.vocalReverb = 0;
|
|
15253
|
+
t.vocalGender = 50;
|
|
15254
|
+
t.vocalBreathiness = 50;
|
|
14514
15255
|
}
|
|
14515
15256
|
}
|
|
14516
15257
|
const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
|
|
@@ -14645,6 +15386,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
14645
15386
|
isSolo = refs.soloCheckbox.checked;
|
|
14646
15387
|
redrawAll();
|
|
14647
15388
|
});
|
|
15389
|
+
unsubscribeClip = options.clipMeter?.onClipChange((clipping) => {
|
|
15390
|
+
refs.clipBadge.classList.toggle("dtm-hidden", !clipping);
|
|
15391
|
+
});
|
|
15392
|
+
refs.clipBadge.addEventListener("click", () => {
|
|
15393
|
+
options.clipMeter?.reset();
|
|
15394
|
+
});
|
|
14648
15395
|
refs.toolPen.addEventListener("click", () => setToolMode("pen"));
|
|
14649
15396
|
refs.toolSelect.addEventListener("click", () => setToolMode("select"));
|
|
14650
15397
|
refs.toolEraser.addEventListener("click", () => setToolMode("eraser"));
|
|
@@ -14720,6 +15467,35 @@ var mountDAW = (target, options = {}) => {
|
|
|
14720
15467
|
refs.masterVolumeLabel.textContent = `${masterVolume}%`;
|
|
14721
15468
|
options.singingVoices?.setVolume(masterVolume / 100);
|
|
14722
15469
|
});
|
|
15470
|
+
refs.reverbAmount.addEventListener("input", () => {
|
|
15471
|
+
reverbAmount = Number.parseInt(refs.reverbAmount.value, 10) || 0;
|
|
15472
|
+
refs.reverbAmountLabel.textContent = `${reverbAmount}%`;
|
|
15473
|
+
options.onReverbChange?.(reverbAmount);
|
|
15474
|
+
});
|
|
15475
|
+
refs.reverbAmountInfoBtn.addEventListener("click", () => {
|
|
15476
|
+
showModal("\u30DE\u30B9\u30BF\u30EA\u30D0\u30FC\u30D6\u306E\u89E3\u8AAC", MASTER_REVERB_INFO_HTML);
|
|
15477
|
+
});
|
|
15478
|
+
refs.autoMasterInfoBtn.addEventListener("click", () => {
|
|
15479
|
+
showModal("\u304A\u307E\u304B\u305B\u30DE\u30B9\u30BF\u30EA\u30F3\u30B0\u89E3\u8AAC", AUTO_MASTER_INFO_HTML);
|
|
15480
|
+
});
|
|
15481
|
+
refs.autoMasterBtn.addEventListener("click", () => {
|
|
15482
|
+
reverbAmount = 20;
|
|
15483
|
+
refs.reverbAmount.value = "20";
|
|
15484
|
+
refs.reverbAmountLabel.textContent = "20%";
|
|
15485
|
+
options.onReverbChange?.(20);
|
|
15486
|
+
for (const t of trackStates) {
|
|
15487
|
+
t.trackCompression = 35;
|
|
15488
|
+
t.trackWidth = 115;
|
|
15489
|
+
options.onTrackCompressionChange?.(t.config.id, 35);
|
|
15490
|
+
options.onTrackWidthChange?.(t.config.id, 115);
|
|
15491
|
+
if (t.lyricModel) {
|
|
15492
|
+
t.vocalVibrato = true;
|
|
15493
|
+
t.vocalReverb = 25;
|
|
15494
|
+
fireLyricsChange(t);
|
|
15495
|
+
}
|
|
15496
|
+
}
|
|
15497
|
+
updateTrackPanel();
|
|
15498
|
+
});
|
|
14723
15499
|
refs.drumSelect.addEventListener("change", () => {
|
|
14724
15500
|
currentDrumPattern = refs.drumSelect.value;
|
|
14725
15501
|
options.onDrumChange?.(currentDrumPattern);
|
|
@@ -15000,7 +15776,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15000
15776
|
console.error(e);
|
|
15001
15777
|
}
|
|
15002
15778
|
refs.midiTrackSelection.innerHTML = `<span class="dtm-label">\u30C8\u30E9\u30C3\u30AF</span>`;
|
|
15003
|
-
detectedTracks.forEach((t,
|
|
15779
|
+
detectedTracks.forEach((t, i2) => {
|
|
15004
15780
|
const btn = document.createElement("button");
|
|
15005
15781
|
btn.className = `dtm-btn ${t.selected ? "dtm-btn--primary" : "dtm-btn--ghost"}`;
|
|
15006
15782
|
btn.dataset.selected = String(t.selected);
|
|
@@ -15012,7 +15788,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15012
15788
|
btn.classList.toggle("dtm-btn--ghost", !on);
|
|
15013
15789
|
});
|
|
15014
15790
|
refs.midiTrackSelection.appendChild(btn);
|
|
15015
|
-
if (
|
|
15791
|
+
if (i2 === 0) refs.midiTrackSelection.dataset.ready = "1";
|
|
15016
15792
|
});
|
|
15017
15793
|
refs.midiTrackSelection.classList.remove("dtm-hidden");
|
|
15018
15794
|
refs.overlay.hidden = true;
|
|
@@ -15022,9 +15798,9 @@ var mountDAW = (target, options = {}) => {
|
|
|
15022
15798
|
if (!pendingMidi) return;
|
|
15023
15799
|
const selected = [];
|
|
15024
15800
|
const btns = refs.midiTrackSelection.querySelectorAll("button");
|
|
15025
|
-
btns.forEach((b,
|
|
15801
|
+
btns.forEach((b, i2) => {
|
|
15026
15802
|
if (b.dataset.selected === "true")
|
|
15027
|
-
selected.push(detectedTracks[
|
|
15803
|
+
selected.push(detectedTracks[i2].index);
|
|
15028
15804
|
});
|
|
15029
15805
|
if (selected.length === 0) return;
|
|
15030
15806
|
if (!isAdvanced && options.onRequestAdvancedMode && selected.length > trackStates.length) {
|
|
@@ -15058,7 +15834,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
15058
15834
|
const refCore = trackStates[0].core;
|
|
15059
15835
|
const tempo = Math.round(parsedBpm) || bpm;
|
|
15060
15836
|
const lines = [];
|
|
15061
|
-
let
|
|
15837
|
+
let i2 = 0;
|
|
15062
15838
|
for (const notes of byTrack.values()) {
|
|
15063
15839
|
const asNotes = notes.map((p) => ({
|
|
15064
15840
|
id: 0,
|
|
@@ -15068,8 +15844,8 @@ var mountDAW = (target, options = {}) => {
|
|
|
15068
15844
|
velocity: p.velocity
|
|
15069
15845
|
}));
|
|
15070
15846
|
const mml = refCore.getMMLFromNotes(asNotes, tempo, 100).trim();
|
|
15071
|
-
lines.push(`@${
|
|
15072
|
-
|
|
15847
|
+
lines.push(`@${i2} ${mml}`);
|
|
15848
|
+
i2++;
|
|
15073
15849
|
}
|
|
15074
15850
|
return [...lines, MML_END_MARKER].join(";\n");
|
|
15075
15851
|
};
|
|
@@ -15684,6 +16460,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
15684
16460
|
refs.drumVolume.value = String(drumVolume);
|
|
15685
16461
|
refs.drumVolumeLabel.textContent = `${drumVolume}%`;
|
|
15686
16462
|
},
|
|
16463
|
+
setReverbAmount: (amount) => {
|
|
16464
|
+
reverbAmount = clamp3(amount, 0, 100);
|
|
16465
|
+
refs.reverbAmount.value = String(reverbAmount);
|
|
16466
|
+
refs.reverbAmountLabel.textContent = `${reverbAmount}%`;
|
|
16467
|
+
options.onReverbChange?.(reverbAmount);
|
|
16468
|
+
},
|
|
15687
16469
|
applyPatch: (trackId, added, removed) => {
|
|
15688
16470
|
const track = trackStates.find((t) => t.config.id === trackId);
|
|
15689
16471
|
if (!track) return;
|
|
@@ -15723,6 +16505,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
15723
16505
|
t.vocalGate = data.vocalGate;
|
|
15724
16506
|
t.vocalPan = data.vocalPan;
|
|
15725
16507
|
t.vocalOctave = data.vocalOctave;
|
|
16508
|
+
t.vocalVibrato = data.vocalVibrato ?? false;
|
|
16509
|
+
t.vocalReverb = data.vocalReverb ?? 0;
|
|
16510
|
+
t.vocalGender = data.vocalGender ?? 50;
|
|
16511
|
+
t.vocalBreathiness = data.vocalBreathiness ?? 50;
|
|
15726
16512
|
},
|
|
15727
16513
|
applyTrackInstrument: (trackIndex, instrumentName) => {
|
|
15728
16514
|
const t = trackStates[trackIndex];
|
|
@@ -15733,21 +16519,22 @@ var mountDAW = (target, options = {}) => {
|
|
|
15733
16519
|
},
|
|
15734
16520
|
noteToCanvas: (step, pitch) => {
|
|
15735
16521
|
const canvas = getGridCanvas();
|
|
15736
|
-
const
|
|
16522
|
+
const x2 = step * renderConfig.stepWidth - currentOffsetX;
|
|
15737
16523
|
const y = (renderConfig.keyCount - 1 - pitch) * renderConfig.keyHeight - currentOffsetY;
|
|
15738
|
-
const onScreen =
|
|
16524
|
+
const onScreen = x2 >= 0 && x2 <= canvas.width && y >= 0 && y <= canvas.height;
|
|
15739
16525
|
let side = null;
|
|
15740
16526
|
if (!onScreen) {
|
|
15741
|
-
if (
|
|
15742
|
-
else if (
|
|
16527
|
+
if (x2 < 0) side = "left";
|
|
16528
|
+
else if (x2 > canvas.width) side = "right";
|
|
15743
16529
|
else if (y < 0) side = "top";
|
|
15744
16530
|
else side = "bottom";
|
|
15745
16531
|
}
|
|
15746
|
-
return { x, y, onScreen, side };
|
|
16532
|
+
return { x: x2, y, onScreen, side };
|
|
15747
16533
|
},
|
|
15748
16534
|
destroy: () => {
|
|
15749
16535
|
sequencer.stop();
|
|
15750
16536
|
options.singingVoices?.stopStream();
|
|
16537
|
+
unsubscribeClip?.();
|
|
15751
16538
|
resizeObserver.disconnect();
|
|
15752
16539
|
document.removeEventListener("pointermove", onPointerMove);
|
|
15753
16540
|
document.removeEventListener("pointerup", onPointerUp);
|
|
@@ -15823,11 +16610,11 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
15823
16610
|
const semis = (lt.octave ?? 0) * 12;
|
|
15824
16611
|
const count = Math.min(sorted.length, lt.syllables.length);
|
|
15825
16612
|
const notes = [];
|
|
15826
|
-
for (let
|
|
15827
|
-
const n = sorted[
|
|
16613
|
+
for (let i2 = 0; i2 < count; i2++) {
|
|
16614
|
+
const n = sorted[i2];
|
|
15828
16615
|
if (n.startStep < fromStep) continue;
|
|
15829
16616
|
notes.push({
|
|
15830
|
-
syllable: lt.syllables[
|
|
16617
|
+
syllable: lt.syllables[i2],
|
|
15831
16618
|
pitch: n.pitch + semis,
|
|
15832
16619
|
startSec: (n.startStep - fromStep) * secondsPerStep,
|
|
15833
16620
|
durationSec: n.durationSteps * secondsPerStep * gate
|
|
@@ -15838,6 +16625,10 @@ var playSingingMML = async (mml, options = {}) => {
|
|
|
15838
16625
|
model: lt.model,
|
|
15839
16626
|
volume: vocalVolumeToGain(lt.volume ?? DEFAULT_VOCAL_VOLUME),
|
|
15840
16627
|
pan: panToStereo(lt.pan ?? DEFAULT_PAN),
|
|
16628
|
+
vibrato: lt.vibrato,
|
|
16629
|
+
reverbSend: (lt.reverb ?? 0) / 100,
|
|
16630
|
+
gender: (lt.gender ?? 50) / 100,
|
|
16631
|
+
breathiness: (lt.breathiness ?? 50) / 100,
|
|
15841
16632
|
notes
|
|
15842
16633
|
};
|
|
15843
16634
|
});
|
|
@@ -16052,7 +16843,7 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16052
16843
|
let dragState = null;
|
|
16053
16844
|
let hasDragged = false;
|
|
16054
16845
|
let lastPreviewPitch = null;
|
|
16055
|
-
const findNoteAtPosition = (
|
|
16846
|
+
const findNoteAtPosition = (x2, y) => {
|
|
16056
16847
|
const { stepWidth, keyHeight, keyCount, pitchRangeStart } = getRenderConfig();
|
|
16057
16848
|
const offset = getDrawOffset();
|
|
16058
16849
|
for (const note of core.getNotes()) {
|
|
@@ -16063,7 +16854,7 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16063
16854
|
const h = keyHeight;
|
|
16064
16855
|
const renderX = logicalX - offset.x;
|
|
16065
16856
|
const renderY = logicalY - offset.y;
|
|
16066
|
-
if (
|
|
16857
|
+
if (x2 >= renderX && x2 <= renderX + w && y >= renderY && y <= renderY + h) {
|
|
16067
16858
|
return note;
|
|
16068
16859
|
}
|
|
16069
16860
|
}
|
|
@@ -16071,10 +16862,10 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16071
16862
|
};
|
|
16072
16863
|
const handlePointerMove = (e) => {
|
|
16073
16864
|
if (core.getToolMode() === "select" && isSelecting && selectionStart) {
|
|
16074
|
-
const { x, y } = getGridPosition(e);
|
|
16075
|
-
const minX = Math.min(
|
|
16865
|
+
const { x: x2, y } = getGridPosition(e);
|
|
16866
|
+
const minX = Math.min(x2, selectionStart.x);
|
|
16076
16867
|
const minY = Math.min(y, selectionStart.y);
|
|
16077
|
-
const width2 = Math.abs(
|
|
16868
|
+
const width2 = Math.abs(x2 - selectionStart.x);
|
|
16078
16869
|
const height2 = Math.abs(y - selectionStart.y);
|
|
16079
16870
|
selectionRect = { x: minX, y: minY, width: width2, height: height2 };
|
|
16080
16871
|
selectedNotes = getNotesInRect(selectionRect);
|
|
@@ -16132,10 +16923,10 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16132
16923
|
}
|
|
16133
16924
|
};
|
|
16134
16925
|
gridCanvas.addEventListener("pointerdown", (e) => {
|
|
16135
|
-
const { x, y, step, pitch } = getGridPosition(e);
|
|
16926
|
+
const { x: x2, y, step, pitch } = getGridPosition(e);
|
|
16136
16927
|
const currentMode = core.getToolMode();
|
|
16137
16928
|
if (currentMode === "select") {
|
|
16138
|
-
const clickedNote = findNoteAtPosition(
|
|
16929
|
+
const clickedNote = findNoteAtPosition(x2, y);
|
|
16139
16930
|
if (selectionRect && clickedNote) {
|
|
16140
16931
|
const notesInRect = getNotesInRect(selectionRect);
|
|
16141
16932
|
if (notesInRect.some((n) => n.id === clickedNote.id)) {
|
|
@@ -16156,10 +16947,10 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16156
16947
|
selectedNotes = [];
|
|
16157
16948
|
selectionRect = null;
|
|
16158
16949
|
isSelecting = true;
|
|
16159
|
-
selectionStart = { x, y, step, pitch };
|
|
16950
|
+
selectionStart = { x: x2, y, step, pitch };
|
|
16160
16951
|
return;
|
|
16161
16952
|
}
|
|
16162
|
-
const note = findNoteAtPosition(
|
|
16953
|
+
const note = findNoteAtPosition(x2, y);
|
|
16163
16954
|
if (!note) return;
|
|
16164
16955
|
const { stepWidth, keyHeight, keyCount, pitchRangeStart } = getRenderConfig();
|
|
16165
16956
|
const offset = getDrawOffset();
|
|
@@ -16169,7 +16960,7 @@ var createPianoRoll = (options, handlers) => {
|
|
|
16169
16960
|
const renderX = logicalX - offset.x;
|
|
16170
16961
|
const renderY = logicalY - offset.y;
|
|
16171
16962
|
const w = note.durationSteps * stepWidth;
|
|
16172
|
-
if (
|
|
16963
|
+
if (x2 >= renderX + w - resizeHandleWidth && x2 <= renderX + w && y >= renderY && y <= renderY + keyHeight) {
|
|
16173
16964
|
dragState = {
|
|
16174
16965
|
noteId: note.id,
|
|
16175
16966
|
mode: "resize",
|
|
@@ -16445,6 +17236,166 @@ var isSupported = midiJsonParser.isSupported;
|
|
|
16445
17236
|
var parseArrayBuffer = midiJsonParser.parseArrayBuffer;
|
|
16446
17237
|
URL.revokeObjectURL(url);
|
|
16447
17238
|
|
|
17239
|
+
// src/channel-strip.ts
|
|
17240
|
+
var clamp4 = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
|
17241
|
+
var compressionParams = (amount) => {
|
|
17242
|
+
const t = clamp4(amount, 0, 100) / 100;
|
|
17243
|
+
return {
|
|
17244
|
+
threshold: 0 + (-24 - 0) * t,
|
|
17245
|
+
ratio: 1 + (12 - 1) * t,
|
|
17246
|
+
knee: 0 + (6 - 0) * t,
|
|
17247
|
+
attack: 0.02 + (3e-3 - 0.02) * t,
|
|
17248
|
+
release: 0.25 + (0.15 - 0.25) * t
|
|
17249
|
+
};
|
|
17250
|
+
};
|
|
17251
|
+
var createChannelStrip = (ctx, destination, options = {}) => {
|
|
17252
|
+
const input = ctx.createGain();
|
|
17253
|
+
const compressor = ctx.createDynamicsCompressor();
|
|
17254
|
+
const applyCompression = (amount) => {
|
|
17255
|
+
const p = compressionParams(amount);
|
|
17256
|
+
const now = ctx.currentTime;
|
|
17257
|
+
compressor.threshold.setValueAtTime(p.threshold, now);
|
|
17258
|
+
compressor.ratio.setValueAtTime(p.ratio, now);
|
|
17259
|
+
compressor.knee.setValueAtTime(p.knee, now);
|
|
17260
|
+
compressor.attack.setValueAtTime(p.attack, now);
|
|
17261
|
+
compressor.release.setValueAtTime(p.release, now);
|
|
17262
|
+
};
|
|
17263
|
+
applyCompression(options.compression ?? 0);
|
|
17264
|
+
const splitter = ctx.createChannelSplitter(2);
|
|
17265
|
+
const mid = ctx.createGain();
|
|
17266
|
+
mid.gain.value = 0.5;
|
|
17267
|
+
splitter.connect(mid, 0);
|
|
17268
|
+
splitter.connect(mid, 1);
|
|
17269
|
+
const sideSum = ctx.createGain();
|
|
17270
|
+
sideSum.gain.value = 1;
|
|
17271
|
+
const sideL = ctx.createGain();
|
|
17272
|
+
sideL.gain.value = 0.5;
|
|
17273
|
+
const sideR = ctx.createGain();
|
|
17274
|
+
sideR.gain.value = -0.5;
|
|
17275
|
+
splitter.connect(sideL, 0);
|
|
17276
|
+
splitter.connect(sideR, 1);
|
|
17277
|
+
sideL.connect(sideSum);
|
|
17278
|
+
sideR.connect(sideSum);
|
|
17279
|
+
const widthGain = ctx.createGain();
|
|
17280
|
+
sideSum.connect(widthGain);
|
|
17281
|
+
const widthInv = ctx.createGain();
|
|
17282
|
+
widthInv.gain.value = -1;
|
|
17283
|
+
widthGain.connect(widthInv);
|
|
17284
|
+
const outL = ctx.createGain();
|
|
17285
|
+
mid.connect(outL);
|
|
17286
|
+
widthGain.connect(outL);
|
|
17287
|
+
const outR = ctx.createGain();
|
|
17288
|
+
mid.connect(outR);
|
|
17289
|
+
widthInv.connect(outR);
|
|
17290
|
+
const merger = ctx.createChannelMerger(2);
|
|
17291
|
+
outL.connect(merger, 0, 0);
|
|
17292
|
+
outR.connect(merger, 0, 1);
|
|
17293
|
+
const setWidth = (width) => {
|
|
17294
|
+
widthGain.gain.setTargetAtTime(
|
|
17295
|
+
clamp4(width, 0, 200) / 100,
|
|
17296
|
+
ctx.currentTime,
|
|
17297
|
+
0.02
|
|
17298
|
+
);
|
|
17299
|
+
};
|
|
17300
|
+
setWidth(options.width ?? 100);
|
|
17301
|
+
input.connect(compressor);
|
|
17302
|
+
compressor.connect(splitter);
|
|
17303
|
+
merger.connect(destination);
|
|
17304
|
+
return {
|
|
17305
|
+
input,
|
|
17306
|
+
setCompression: applyCompression,
|
|
17307
|
+
setWidth,
|
|
17308
|
+
dispose: () => {
|
|
17309
|
+
input.disconnect();
|
|
17310
|
+
compressor.disconnect();
|
|
17311
|
+
splitter.disconnect();
|
|
17312
|
+
mid.disconnect();
|
|
17313
|
+
sideSum.disconnect();
|
|
17314
|
+
sideL.disconnect();
|
|
17315
|
+
sideR.disconnect();
|
|
17316
|
+
widthGain.disconnect();
|
|
17317
|
+
widthInv.disconnect();
|
|
17318
|
+
outL.disconnect();
|
|
17319
|
+
outR.disconnect();
|
|
17320
|
+
merger.disconnect();
|
|
17321
|
+
}
|
|
17322
|
+
};
|
|
17323
|
+
};
|
|
17324
|
+
|
|
17325
|
+
// src/clip-meter.ts
|
|
17326
|
+
var createClipMeter = (ctx, source, options = {}) => {
|
|
17327
|
+
const threshold = options.threshold ?? 0.98;
|
|
17328
|
+
const holdMs = options.holdMs ?? 800;
|
|
17329
|
+
const analyser = ctx.createAnalyser();
|
|
17330
|
+
analyser.fftSize = 512;
|
|
17331
|
+
source.connect(analyser);
|
|
17332
|
+
const buf = new Float32Array(analyser.fftSize);
|
|
17333
|
+
let clipping = false;
|
|
17334
|
+
let clipUntil = 0;
|
|
17335
|
+
let peakLevel = 0;
|
|
17336
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
17337
|
+
let rafId = null;
|
|
17338
|
+
const tick = () => {
|
|
17339
|
+
analyser.getFloatTimeDomainData(buf);
|
|
17340
|
+
let peak = 0;
|
|
17341
|
+
let clipped = false;
|
|
17342
|
+
for (let i2 = 0; i2 < buf.length; i2++) {
|
|
17343
|
+
const v = Math.abs(buf[i2]);
|
|
17344
|
+
if (v > peak) peak = v;
|
|
17345
|
+
if (v >= threshold) clipped = true;
|
|
17346
|
+
}
|
|
17347
|
+
peakLevel = peak;
|
|
17348
|
+
const now = performance.now();
|
|
17349
|
+
if (clipped) clipUntil = now + holdMs;
|
|
17350
|
+
const nextClipping = now < clipUntil;
|
|
17351
|
+
if (nextClipping !== clipping) {
|
|
17352
|
+
clipping = nextClipping;
|
|
17353
|
+
for (const cb of listeners) cb(clipping);
|
|
17354
|
+
}
|
|
17355
|
+
rafId = requestAnimationFrame(tick);
|
|
17356
|
+
};
|
|
17357
|
+
rafId = requestAnimationFrame(tick);
|
|
17358
|
+
return {
|
|
17359
|
+
onClipChange: (cb) => {
|
|
17360
|
+
listeners.add(cb);
|
|
17361
|
+
return () => listeners.delete(cb);
|
|
17362
|
+
},
|
|
17363
|
+
getPeakLevel: () => peakLevel,
|
|
17364
|
+
reset: () => {
|
|
17365
|
+
clipUntil = 0;
|
|
17366
|
+
if (clipping) {
|
|
17367
|
+
clipping = false;
|
|
17368
|
+
for (const cb of listeners) cb(false);
|
|
17369
|
+
}
|
|
17370
|
+
},
|
|
17371
|
+
dispose: () => {
|
|
17372
|
+
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
17373
|
+
rafId = null;
|
|
17374
|
+
analyser.disconnect();
|
|
17375
|
+
listeners.clear();
|
|
17376
|
+
}
|
|
17377
|
+
};
|
|
17378
|
+
};
|
|
17379
|
+
|
|
17380
|
+
// src/reverb.ts
|
|
17381
|
+
var IMPULSE_DURATION_SEC = 2.2;
|
|
17382
|
+
var IMPULSE_DECAY = 2.5;
|
|
17383
|
+
var createReverbImpulse = (ctx) => {
|
|
17384
|
+
const rate = ctx.sampleRate;
|
|
17385
|
+
const length = Math.max(1, Math.floor(rate * IMPULSE_DURATION_SEC));
|
|
17386
|
+
const impulse = ctx.createBuffer(2, length, rate);
|
|
17387
|
+
for (let ch = 0; ch < impulse.numberOfChannels; ch++) {
|
|
17388
|
+
const data = impulse.getChannelData(ch);
|
|
17389
|
+
for (let i2 = 0; i2 < length; i2++) {
|
|
17390
|
+
const envelope = (1 - i2 / length) ** IMPULSE_DECAY;
|
|
17391
|
+
data[i2] = (Math.random() * 2 - 1) * envelope;
|
|
17392
|
+
}
|
|
17393
|
+
}
|
|
17394
|
+
return impulse;
|
|
17395
|
+
};
|
|
17396
|
+
var REVERB_MAX_WET = 0.6;
|
|
17397
|
+
var reverbAmountToGain = (amount) => Math.max(0, Math.min(100, amount)) / 100 * REVERB_MAX_WET;
|
|
17398
|
+
|
|
16448
17399
|
// src/sf/SoundFont_drum.ts
|
|
16449
17400
|
var touch = (map, key, ctor) => {
|
|
16450
17401
|
if (!map.has(key)) map.set(key, new ctor());
|
|
@@ -16597,10 +17548,44 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16597
17548
|
const audioCtx = options.audioContext ?? new AudioContext({ sampleRate: 44100 });
|
|
16598
17549
|
const masterGain = audioCtx.createGain();
|
|
16599
17550
|
masterGain.gain.value = options.masterVolume ?? 1;
|
|
16600
|
-
masterGain.connect(audioCtx.destination);
|
|
16601
17551
|
const drumGain = audioCtx.createGain();
|
|
16602
17552
|
drumGain.gain.value = options.drumVolume ?? 1;
|
|
16603
17553
|
drumGain.connect(masterGain);
|
|
17554
|
+
const reverbConvolver = audioCtx.createConvolver();
|
|
17555
|
+
reverbConvolver.buffer = createReverbImpulse(audioCtx);
|
|
17556
|
+
reverbConvolver.normalize = true;
|
|
17557
|
+
const reverbWetGain = audioCtx.createGain();
|
|
17558
|
+
reverbWetGain.gain.value = reverbAmountToGain(options.reverbAmount ?? 0);
|
|
17559
|
+
masterGain.connect(reverbConvolver);
|
|
17560
|
+
reverbConvolver.connect(reverbWetGain);
|
|
17561
|
+
const setReverbAmount = (amount) => {
|
|
17562
|
+
reverbWetGain.gain.setTargetAtTime(
|
|
17563
|
+
reverbAmountToGain(amount),
|
|
17564
|
+
audioCtx.currentTime,
|
|
17565
|
+
0.02
|
|
17566
|
+
);
|
|
17567
|
+
};
|
|
17568
|
+
const finalMix = audioCtx.createGain();
|
|
17569
|
+
masterGain.connect(finalMix);
|
|
17570
|
+
reverbWetGain.connect(finalMix);
|
|
17571
|
+
const safetyLimiter = audioCtx.createDynamicsCompressor();
|
|
17572
|
+
safetyLimiter.threshold.value = -1;
|
|
17573
|
+
safetyLimiter.knee.value = 0;
|
|
17574
|
+
safetyLimiter.ratio.value = 20;
|
|
17575
|
+
safetyLimiter.attack.value = 1e-3;
|
|
17576
|
+
safetyLimiter.release.value = 0.1;
|
|
17577
|
+
finalMix.connect(safetyLimiter);
|
|
17578
|
+
safetyLimiter.connect(options.destination ?? audioCtx.destination);
|
|
17579
|
+
const clipMeter = createClipMeter(audioCtx, finalMix);
|
|
17580
|
+
const channelStrips = /* @__PURE__ */ new Map();
|
|
17581
|
+
const getChannelStrip = (trackId) => {
|
|
17582
|
+
let strip = channelStrips.get(trackId);
|
|
17583
|
+
if (!strip) {
|
|
17584
|
+
strip = createChannelStrip(audioCtx, masterGain);
|
|
17585
|
+
channelStrips.set(trackId, strip);
|
|
17586
|
+
}
|
|
17587
|
+
return strip;
|
|
17588
|
+
};
|
|
16604
17589
|
const resumeAudio = () => {
|
|
16605
17590
|
if (audioCtx.state === "closed") return Promise.resolve();
|
|
16606
17591
|
return audioCtx.resume();
|
|
@@ -16631,7 +17616,14 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16631
17616
|
const singingVoices = createSingingVoices(audioCtx, masterGain, {
|
|
16632
17617
|
voiceWorkerUrl,
|
|
16633
17618
|
voicebanks,
|
|
16634
|
-
worldlineScriptUrl: options.worldlineScriptUrl
|
|
17619
|
+
worldlineScriptUrl: options.worldlineScriptUrl,
|
|
17620
|
+
// ボーカルトラック個別のリバーブセンド(`r`トークン)先。マスタリバーブの
|
|
17621
|
+
// Convolver 入力へ直接センドする(masterGain 経由のドライ段は素通り)。
|
|
17622
|
+
reverbBus: reverbConvolver,
|
|
17623
|
+
// トラック単位チャンネルストリップ(コンプレッサー/ステレオワイド)の入口。
|
|
17624
|
+
// 楽器と同じ getChannelStrip キャッシュを共有するので、演奏トラックと歌詞トラックが
|
|
17625
|
+
// 同じ trackId を指していれば同じ処理が掛かる。
|
|
17626
|
+
getTrackDestination: (trackId) => getChannelStrip(trackId).input
|
|
16635
17627
|
});
|
|
16636
17628
|
const listReady = new Promise((resolve) => {
|
|
16637
17629
|
sfList.init();
|
|
@@ -16861,7 +17853,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16861
17853
|
if (!sfInst) return;
|
|
16862
17854
|
sfInst.play({
|
|
16863
17855
|
ctx: audioCtx,
|
|
16864
|
-
destination:
|
|
17856
|
+
destination: getChannelStrip(e.trackId).input,
|
|
16865
17857
|
pitch: e.pitch,
|
|
16866
17858
|
volume: e.volume,
|
|
16867
17859
|
when: e.when,
|
|
@@ -16906,6 +17898,11 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16906
17898
|
void handleTrackInstrumentChange(idx, name);
|
|
16907
17899
|
externalOnTrackInstrumentChange?.(idx, name);
|
|
16908
17900
|
},
|
|
17901
|
+
reverbAmount: options.reverbAmount,
|
|
17902
|
+
onReverbChange: setReverbAmount,
|
|
17903
|
+
onTrackCompressionChange: (trackId, amount) => getChannelStrip(trackId).setCompression(amount),
|
|
17904
|
+
onTrackWidthChange: (trackId, width) => getChannelStrip(trackId).setWidth(width),
|
|
17905
|
+
clipMeter,
|
|
16909
17906
|
...dawOverrides,
|
|
16910
17907
|
// dawOverrides で上書きされないよう、スプレッドの後に配置して合成する
|
|
16911
17908
|
onDrumChange: (name) => {
|
|
@@ -16932,17 +17929,22 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16932
17929
|
mountedEditors.push(daw);
|
|
16933
17930
|
const wantPresetUI = presetUI ?? features.presetUI;
|
|
16934
17931
|
const rollEl = target.querySelector('[data-dtm="roll"]');
|
|
17932
|
+
const presetSlot = target.querySelector(
|
|
17933
|
+
'[data-dtm="preset-select-slot"]'
|
|
17934
|
+
);
|
|
16935
17935
|
if (wantPresetUI) {
|
|
16936
17936
|
editorPresetSelects.get(target)?.destroy();
|
|
16937
|
-
presetSelect = mountPresetSelect(target, {
|
|
17937
|
+
presetSelect = mountPresetSelect(presetSlot ?? target, {
|
|
16938
17938
|
getDaw: () => daw,
|
|
16939
17939
|
getTrackIds: () => trackIds,
|
|
16940
17940
|
value: initialPreset,
|
|
16941
17941
|
loadingTarget: rollEl ?? target,
|
|
16942
|
-
position: "prepend",
|
|
16943
|
-
//
|
|
17942
|
+
position: presetSlot ? "append" : "prepend",
|
|
17943
|
+
// 楽器変更時、このエディタの発音解決が使うプリセットも追従させ、
|
|
17944
|
+
// 外部の onInstrumentChange(呼び出し側の永続化フック等)へも通知する。
|
|
17945
|
+
// #inst= 付きMML読込時の通知経路(handleInstrumentChange)と揃える。
|
|
16944
17946
|
onChange: (key) => {
|
|
16945
|
-
|
|
17947
|
+
handleInstrumentChange(key);
|
|
16946
17948
|
}
|
|
16947
17949
|
});
|
|
16948
17950
|
editorPresetSelects.set(target, presetSelect);
|
|
@@ -16963,8 +17965,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
16963
17965
|
presetSelect?.destroy();
|
|
16964
17966
|
if (editorPresetSelects.get(target) === presetSelect)
|
|
16965
17967
|
editorPresetSelects.delete(target);
|
|
16966
|
-
const
|
|
16967
|
-
if (
|
|
17968
|
+
const i2 = mountedEditors.indexOf(daw);
|
|
17969
|
+
if (i2 >= 0) mountedEditors.splice(i2, 1);
|
|
16968
17970
|
};
|
|
16969
17971
|
return {
|
|
16970
17972
|
...daw,
|
|
@@ -17067,8 +18069,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17067
18069
|
destroy: () => {
|
|
17068
18070
|
doUnmount();
|
|
17069
18071
|
wrapper.remove();
|
|
17070
|
-
const
|
|
17071
|
-
if (
|
|
18072
|
+
const i2 = mountedModeSwitches.indexOf(instance);
|
|
18073
|
+
if (i2 >= 0) mountedModeSwitches.splice(i2, 1);
|
|
17072
18074
|
}
|
|
17073
18075
|
};
|
|
17074
18076
|
mountedModeSwitches.push(instance);
|
|
@@ -17125,7 +18127,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17125
18127
|
if (!sfInst) return;
|
|
17126
18128
|
sfInst.play({
|
|
17127
18129
|
ctx: audioCtx,
|
|
17128
|
-
destination:
|
|
18130
|
+
destination: getChannelStrip(e.trackId).input,
|
|
17129
18131
|
pitch: e.pitch,
|
|
17130
18132
|
volume: e.volume,
|
|
17131
18133
|
when: e.when,
|
|
@@ -17155,8 +18157,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17155
18157
|
mountedPlayers.push(player);
|
|
17156
18158
|
const destroy = () => {
|
|
17157
18159
|
player.destroy();
|
|
17158
|
-
const
|
|
17159
|
-
if (
|
|
18160
|
+
const i2 = mountedPlayers.indexOf(player);
|
|
18161
|
+
if (i2 >= 0) mountedPlayers.splice(i2, 1);
|
|
17160
18162
|
};
|
|
17161
18163
|
return { ...player, destroy };
|
|
17162
18164
|
};
|
|
@@ -17211,7 +18213,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17211
18213
|
if (!sfInst) return;
|
|
17212
18214
|
sfInst.play({
|
|
17213
18215
|
ctx: audioCtx,
|
|
17214
|
-
destination:
|
|
18216
|
+
destination: getChannelStrip(e.trackId).input,
|
|
17215
18217
|
pitch: e.pitch,
|
|
17216
18218
|
volume: e.volume,
|
|
17217
18219
|
when: e.when,
|
|
@@ -17290,7 +18292,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17290
18292
|
if (!sfInst) return;
|
|
17291
18293
|
sfInst.play({
|
|
17292
18294
|
ctx: audioCtx,
|
|
17293
|
-
destination:
|
|
18295
|
+
destination: getChannelStrip(e.trackId).input,
|
|
17294
18296
|
pitch: e.pitch,
|
|
17295
18297
|
volume: e.volume,
|
|
17296
18298
|
when: e.when,
|
|
@@ -17329,7 +18331,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17329
18331
|
if (!sfInst) return;
|
|
17330
18332
|
sfInst.play({
|
|
17331
18333
|
ctx: audioCtx,
|
|
17332
|
-
destination:
|
|
18334
|
+
destination: getChannelStrip(e.trackId).input,
|
|
17333
18335
|
pitch: e.pitch,
|
|
17334
18336
|
volume: e.volume,
|
|
17335
18337
|
when: e.when,
|
|
@@ -17385,7 +18387,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17385
18387
|
if (!sfInst) return;
|
|
17386
18388
|
sfInst.play({
|
|
17387
18389
|
ctx: audioCtx,
|
|
17388
|
-
destination:
|
|
18390
|
+
destination: getChannelStrip("chord").input,
|
|
17389
18391
|
pitch: e.pitch,
|
|
17390
18392
|
volume: e.volume,
|
|
17391
18393
|
when: e.when,
|
|
@@ -17417,8 +18419,8 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17417
18419
|
mountedChordPlayers.push(player);
|
|
17418
18420
|
const destroy = () => {
|
|
17419
18421
|
player.destroy();
|
|
17420
|
-
const
|
|
17421
|
-
if (
|
|
18422
|
+
const i2 = mountedChordPlayers.indexOf(player);
|
|
18423
|
+
if (i2 >= 0) mountedChordPlayers.splice(i2, 1);
|
|
17422
18424
|
};
|
|
17423
18425
|
return {
|
|
17424
18426
|
...player,
|
|
@@ -17435,6 +18437,9 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17435
18437
|
mountedPlayers.length = 0;
|
|
17436
18438
|
mountedChordPlayers.length = 0;
|
|
17437
18439
|
mountedEditors.length = 0;
|
|
18440
|
+
clipMeter.dispose();
|
|
18441
|
+
for (const strip of channelStrips.values()) strip.dispose();
|
|
18442
|
+
channelStrips.clear();
|
|
17438
18443
|
void audioCtx.close();
|
|
17439
18444
|
};
|
|
17440
18445
|
const setMasterVolume = (volume) => {
|
|
@@ -17473,6 +18478,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17473
18478
|
mountModeSwitch,
|
|
17474
18479
|
setMasterVolume,
|
|
17475
18480
|
setVolume: setMasterVolume,
|
|
18481
|
+
setReverbAmount,
|
|
17476
18482
|
dispose
|
|
17477
18483
|
};
|
|
17478
18484
|
};
|
|
@@ -17504,6 +18510,7 @@ var createDtmStudio = async (options = {}) => {
|
|
|
17504
18510
|
PREWARM_NOTES,
|
|
17505
18511
|
TRACKS_ADVANCED,
|
|
17506
18512
|
TRACKS_SIMPLE,
|
|
18513
|
+
VIBRATO_MIN_SEC,
|
|
17507
18514
|
VOICE_IMAGES,
|
|
17508
18515
|
VOICE_IMAGE_KEY,
|
|
17509
18516
|
analyzeMidiTracks,
|