@onjmin/dtm 0.1.23 → 0.1.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +445 -123
- package/dist/index.mjs +445 -123
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1107,6 +1107,9 @@ var ICONS = {
|
|
|
1107
1107
|
},
|
|
1108
1108
|
info: {
|
|
1109
1109
|
d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"
|
|
1110
|
+
},
|
|
1111
|
+
more: {
|
|
1112
|
+
d: "M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
|
1110
1113
|
}
|
|
1111
1114
|
};
|
|
1112
1115
|
var icon = (name, size = 20) => {
|
|
@@ -1233,6 +1236,7 @@ var buildUI = (target, options) => {
|
|
|
1233
1236
|
<textarea class="dtm-textarea dtm-grow" data-dtm="mml-input" placeholder="MML\u3092\u5165\u529B"></textarea>
|
|
1234
1237
|
<button class="dtm-btn dtm-btn--primary" data-dtm="mml-load">\u8AAD\u8FBC</button>
|
|
1235
1238
|
</div>
|
|
1239
|
+
<p class="dtm-load-note dtm-hidden" data-dtm="mml-load-note"></p>
|
|
1236
1240
|
</div>
|
|
1237
1241
|
</details>
|
|
1238
1242
|
|
|
@@ -1358,6 +1362,7 @@ var buildUI = (target, options) => {
|
|
|
1358
1362
|
midiPanel: sel("midi-panel"),
|
|
1359
1363
|
mmlInput: sel("mml-input"),
|
|
1360
1364
|
mmlLoadBtn: sel("mml-load"),
|
|
1365
|
+
mmlLoadNote: sel("mml-load-note"),
|
|
1361
1366
|
shiftSelect: sel("shift-select"),
|
|
1362
1367
|
shiftApplyBtn: sel("shift-apply"),
|
|
1363
1368
|
macroClear: sel("macro-clear"),
|
|
@@ -1511,6 +1516,110 @@ var DRUM_PATTERNS = {
|
|
|
1511
1516
|
]
|
|
1512
1517
|
};
|
|
1513
1518
|
|
|
1519
|
+
// src/instrument-presets.ts
|
|
1520
|
+
var INSTRUMENT_PRESETS = {
|
|
1521
|
+
// --- STANDARD: 汎用性と完成度重視 ---
|
|
1522
|
+
piano: {
|
|
1523
|
+
displayName: "\u30B0\u30E9\u30F3\u30C9\u30D4\u30A2\u30CE",
|
|
1524
|
+
description: "\u6700\u3082\u7834\u7DBB\u3057\u306B\u304F\u3044\u69CB\u6210\u3002\u697D\u66F2\u5236\u4F5C\u306E\u30B9\u30B1\u30C3\u30C1\u306B\u3082\u6700\u9069\u3002",
|
|
1525
|
+
melody: "Acoustic Grand Piano",
|
|
1526
|
+
submelody: "Vibraphone",
|
|
1527
|
+
bass: "Electric Bass (finger)",
|
|
1528
|
+
chord: "Pad 2 (warm)"
|
|
1529
|
+
},
|
|
1530
|
+
acoustic: {
|
|
1531
|
+
displayName: "\u30A2\u30B3\u30FC\u30B9\u30C6\u30A3\u30C3\u30AF",
|
|
1532
|
+
description: "\u751F\u697D\u5668\u306E\u6E29\u304B\u307F\u3092\u91CD\u8996\u3002\u30D5\u30A9\u30FC\u30AF\u3084\u30DD\u30C3\u30D7\u30B9\u306B\u3002",
|
|
1533
|
+
melody: "Acoustic Guitar (steel)",
|
|
1534
|
+
submelody: "Harmonica",
|
|
1535
|
+
bass: "Acoustic Bass",
|
|
1536
|
+
chord: "Acoustic Guitar (nylon)"
|
|
1537
|
+
},
|
|
1538
|
+
jazz_night: {
|
|
1539
|
+
displayName: "\u30B8\u30E3\u30BA\u30FB\u30CA\u30A4\u30C8",
|
|
1540
|
+
description: "Rhodes\u98A8\u306EEP\u3068\u30A6\u30C3\u30C9\u30D9\u30FC\u30B9\u306B\u3088\u308B\u3001\u5927\u4EBA\u3073\u305F\u30A2\u30F3\u30B5\u30F3\u30D6\u30EB\u3002",
|
|
1541
|
+
melody: "Electric Piano 1",
|
|
1542
|
+
submelody: "Flute",
|
|
1543
|
+
bass: "Acoustic Bass",
|
|
1544
|
+
chord: "Electric Guitar (jazz)"
|
|
1545
|
+
},
|
|
1546
|
+
// --- MODERN & VIBE: エッジの効いた現代的な響き ---
|
|
1547
|
+
synth_pop: {
|
|
1548
|
+
displayName: "\u30B7\u30F3\u30BB\u30DD\u30C3\u30D7",
|
|
1549
|
+
description: "80s\u301C\u73FE\u4EE3\u307E\u3067\u3002\u629C\u3051\u308B\u30EA\u30FC\u30C9\u3068\u592A\u3044\u30D9\u30FC\u30B9\u306E\u738B\u9053\u3002",
|
|
1550
|
+
melody: "Lead 2 (sawtooth)",
|
|
1551
|
+
submelody: "Lead 4 (chiff)",
|
|
1552
|
+
bass: "Synth Bass 2",
|
|
1553
|
+
chord: "Pad 3 (polysynth)"
|
|
1554
|
+
},
|
|
1555
|
+
cyber_punk: {
|
|
1556
|
+
displayName: "\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF",
|
|
1557
|
+
description: "\u30C7\u30B8\u30BF\u30EB\u306A\u51B7\u305F\u3055\u3068\u6B6A\u307F\u304C\u6DF7\u3056\u308A\u5408\u3046\u3001\u672A\u6765\u7684\u306A\u97FF\u304D\u3002",
|
|
1558
|
+
melody: "Lead 8 (bass + lead)",
|
|
1559
|
+
submelody: "Lead 5 (charang)",
|
|
1560
|
+
bass: "Synth Bass 2",
|
|
1561
|
+
chord: "Pad 8 (sweep)"
|
|
1562
|
+
},
|
|
1563
|
+
rock: {
|
|
1564
|
+
displayName: "\u30CF\u30FC\u30C9\u30ED\u30C3\u30AF",
|
|
1565
|
+
description: "\u6B6A\u307F\u30AE\u30BF\u30FC\u3068\u91CD\u539A\u306A\u30D9\u30FC\u30B9\u3067\u3001\u30D1\u30EF\u30FC\u3092\u524D\u9762\u306B\u3002",
|
|
1566
|
+
melody: "Distortion Guitar",
|
|
1567
|
+
submelody: "Rock Organ",
|
|
1568
|
+
bass: "Electric Bass (pick)",
|
|
1569
|
+
chord: "Overdriven Guitar"
|
|
1570
|
+
},
|
|
1571
|
+
// --- WORLD & CLASSIC: 特定のジャンル・地域 ---
|
|
1572
|
+
orchestra: {
|
|
1573
|
+
displayName: "\u30AA\u30FC\u30B1\u30B9\u30C8\u30E9",
|
|
1574
|
+
description: "\u58EE\u5927\u306A\u7269\u8A9E\u3092\u4E88\u611F\u3055\u305B\u308B\u3001\u7BA1\u5F26\u697D\u5668\u306E\u91CD\u539A\u306A\u97FF\u304D\u3002",
|
|
1575
|
+
melody: "French Horn",
|
|
1576
|
+
submelody: "Pizzicato Strings",
|
|
1577
|
+
bass: "Cello",
|
|
1578
|
+
chord: "Tremolo Strings"
|
|
1579
|
+
},
|
|
1580
|
+
japanese_wa: {
|
|
1581
|
+
displayName: "\u548C\u98A8\u30FB\u96C5",
|
|
1582
|
+
description: "\u7434\u3068\u4E09\u5473\u7DDA\u306E\u7E4A\u7D30\u306A\u8ABF\u3079\u306B\u3001\u5C3A\u516B\u306E\u60C5\u7DD2\u3092\u6DFB\u3048\u3066\u3002",
|
|
1583
|
+
melody: "Koto",
|
|
1584
|
+
submelody: "Shamisen",
|
|
1585
|
+
bass: "Taiko Drum",
|
|
1586
|
+
chord: "Shakuhachi"
|
|
1587
|
+
},
|
|
1588
|
+
arabic_exotic: {
|
|
1589
|
+
displayName: "\u30A8\u30AD\u30BE\u30C1\u30C3\u30AF",
|
|
1590
|
+
description: "\u30B7\u30BF\u30FC\u30EB\u3084\u30D0\u30B0\u30D1\u30A4\u30D7\u306B\u3088\u308B\u3001\u7570\u56FD\u60C5\u7DD2\u6EA2\u308C\u308B\u30B5\u30A6\u30F3\u30C9\u3002",
|
|
1591
|
+
melody: "Sitar",
|
|
1592
|
+
submelody: "Bagpipe",
|
|
1593
|
+
bass: "Fretless Bass",
|
|
1594
|
+
chord: "Kalimba"
|
|
1595
|
+
},
|
|
1596
|
+
// --- FANTASY & ATMOSPHERE: 雰囲気と余韻 ---
|
|
1597
|
+
fantasy_rpg: {
|
|
1598
|
+
displayName: "\u30D5\u30A1\u30F3\u30BF\u30B8\u30FCRPG",
|
|
1599
|
+
description: "\u30AA\u30AB\u30EA\u30CA\u3068\u30CF\u30FC\u30D7\u304C\u7D21\u3050\u3001\u5192\u967A\u3068\u9B54\u6CD5\u306E\u4E16\u754C\u89B3\u3002",
|
|
1600
|
+
melody: "Ocarina",
|
|
1601
|
+
submelody: "Celesta",
|
|
1602
|
+
bass: "Timpani",
|
|
1603
|
+
chord: "Orchestral Harp"
|
|
1604
|
+
},
|
|
1605
|
+
ambient_cloud: {
|
|
1606
|
+
displayName: "\u30A2\u30F3\u30D3\u30A8\u30F3\u30C8",
|
|
1607
|
+
description: "\u8F2A\u90ED\u3092\u307C\u304B\u3057\u305F\u97F3\u8272\u3067\u3001\u6DF1\u3044\u6CA1\u5165\u611F\u3068\u4F59\u97FB\u3092\u6F14\u51FA\u3002",
|
|
1608
|
+
melody: "Lead 6 (voice)",
|
|
1609
|
+
submelody: "Music Box",
|
|
1610
|
+
bass: "Synth Bass 1",
|
|
1611
|
+
chord: "Pad 7 (halo)"
|
|
1612
|
+
},
|
|
1613
|
+
retro_game: {
|
|
1614
|
+
displayName: "8-bit \u30EC\u30C8\u30ED",
|
|
1615
|
+
description: "\u77E9\u5F62\u6CE2\u3092\u60F3\u8D77\u3055\u305B\u308B\u3001\u521D\u671F\u30B2\u30FC\u30E0\u6A5F\u306E\u3088\u3046\u306A\u61D0\u304B\u3057\u3044\u97FF\u304D\u3002",
|
|
1616
|
+
melody: "Lead 1 (square)",
|
|
1617
|
+
submelody: "Lead 2 (sawtooth)",
|
|
1618
|
+
bass: "Synth Bass 1",
|
|
1619
|
+
chord: "Clavinet"
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
|
|
1514
1623
|
// node_modules/.pnpm/@onjmin+koe@1.0.3/node_modules/@onjmin/koe/dist/index.js
|
|
1515
1624
|
var MAGIC = 1263486208;
|
|
1516
1625
|
function parseKoeHeader(headerBytes) {
|
|
@@ -3960,6 +4069,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
3960
4069
|
bpm,
|
|
3961
4070
|
tokenTracks: collectTokens ? tokenTracks : void 0,
|
|
3962
4071
|
lyrics: collectLyrics ? /* @__PURE__ */ new Map() : void 0,
|
|
4072
|
+
mergedTrackCount: 0,
|
|
3963
4073
|
meta: {}
|
|
3964
4074
|
};
|
|
3965
4075
|
}
|
|
@@ -3972,13 +4082,24 @@ var parseMML = (mml, options = {}) => {
|
|
|
3972
4082
|
const fullMML = stripLyrics(noMeta).replace(endRegex, "").replace(/[\n\r]+/g, " ").trim();
|
|
3973
4083
|
const parts = fullMML.split(/(@\d+)/).filter((p) => p.trim().length > 0);
|
|
3974
4084
|
let trackIndex = 0;
|
|
4085
|
+
let sourceTrackIndex = 0;
|
|
3975
4086
|
let octave = 4;
|
|
3976
4087
|
let currentStep = 0;
|
|
3977
4088
|
let baseLength = 16;
|
|
4089
|
+
const contributors = /* @__PURE__ */ new Map();
|
|
4090
|
+
const recordContributor = () => {
|
|
4091
|
+
let set = contributors.get(trackIndex);
|
|
4092
|
+
if (!set) {
|
|
4093
|
+
set = /* @__PURE__ */ new Set();
|
|
4094
|
+
contributors.set(trackIndex, set);
|
|
4095
|
+
}
|
|
4096
|
+
set.add(sourceTrackIndex);
|
|
4097
|
+
};
|
|
3978
4098
|
for (const rawPart of parts) {
|
|
3979
4099
|
const part = rawPart.trim();
|
|
3980
4100
|
if (part.startsWith("@")) {
|
|
3981
4101
|
let idx = Number.parseInt(part.substring(1), 10);
|
|
4102
|
+
sourceTrackIndex = idx;
|
|
3982
4103
|
if (clampTrackCount !== void 0 && idx >= clampTrackCount)
|
|
3983
4104
|
idx = clampTrackCount - 1;
|
|
3984
4105
|
trackIndex = idx;
|
|
@@ -4102,6 +4223,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4102
4223
|
}
|
|
4103
4224
|
if (j < body.length && body[j] === "]") j++;
|
|
4104
4225
|
const steps = parseLength();
|
|
4226
|
+
if (chordNotes.length > 0) recordContributor();
|
|
4105
4227
|
for (const p of chordNotes) {
|
|
4106
4228
|
placements.push({
|
|
4107
4229
|
trackIndex,
|
|
@@ -4125,6 +4247,7 @@ var parseMML = (mml, options = {}) => {
|
|
|
4125
4247
|
}
|
|
4126
4248
|
const midiPitch = (octave + 1) * 12 + pitch;
|
|
4127
4249
|
const steps = parseLength();
|
|
4250
|
+
recordContributor();
|
|
4128
4251
|
placements.push({
|
|
4129
4252
|
trackIndex,
|
|
4130
4253
|
startStep: currentStep,
|
|
@@ -4138,11 +4261,16 @@ var parseMML = (mml, options = {}) => {
|
|
|
4138
4261
|
}
|
|
4139
4262
|
}
|
|
4140
4263
|
}
|
|
4264
|
+
let mergedTrackCount = 0;
|
|
4265
|
+
for (const set of contributors.values()) {
|
|
4266
|
+
if (set.size >= 2) mergedTrackCount++;
|
|
4267
|
+
}
|
|
4141
4268
|
return {
|
|
4142
4269
|
placements,
|
|
4143
4270
|
bpm,
|
|
4144
4271
|
tokenTracks: collectTokens ? tokenTracks : void 0,
|
|
4145
4272
|
lyrics,
|
|
4273
|
+
mergedTrackCount,
|
|
4146
4274
|
meta
|
|
4147
4275
|
};
|
|
4148
4276
|
};
|
|
@@ -4204,6 +4332,8 @@ var createSequencer = (options) => {
|
|
|
4204
4332
|
let active = false;
|
|
4205
4333
|
let fromStepValue = 0;
|
|
4206
4334
|
let trackVolumeMap = /* @__PURE__ */ new Map();
|
|
4335
|
+
let lastRealTime = -1;
|
|
4336
|
+
let lastAudioTime = -1;
|
|
4207
4337
|
let isLooping = false;
|
|
4208
4338
|
let loopStartStep = 0;
|
|
4209
4339
|
let loopEndStep = 0;
|
|
@@ -4277,6 +4407,21 @@ var createSequencer = (options) => {
|
|
|
4277
4407
|
const sps = secondsPerStep();
|
|
4278
4408
|
const time = options.getAudioTime() - startTime;
|
|
4279
4409
|
const soloId = options.getSoloTrackId();
|
|
4410
|
+
const nowReal = performance.now() / 1e3;
|
|
4411
|
+
if (lastRealTime > 0 && lastAudioTime >= 0) {
|
|
4412
|
+
const realDelta = nowReal - lastRealTime;
|
|
4413
|
+
const audioDelta = time - lastAudioTime;
|
|
4414
|
+
if (realDelta > 0.5 || audioDelta > 0.5) {
|
|
4415
|
+
console.warn(
|
|
4416
|
+
`[sequencer] Interruption detected (realDelta: ${realDelta.toFixed(3)}s, audioDelta: ${audioDelta.toFixed(3)}s). Stopping playback.`
|
|
4417
|
+
);
|
|
4418
|
+
stop();
|
|
4419
|
+
options.onEnd(true);
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
}
|
|
4423
|
+
lastRealTime = nowReal;
|
|
4424
|
+
lastAudioTime = time;
|
|
4280
4425
|
for (const track of options.getTracks()) {
|
|
4281
4426
|
trackVolumeMap.set(track.id, track.volume);
|
|
4282
4427
|
}
|
|
@@ -4353,7 +4498,7 @@ var createSequencer = (options) => {
|
|
|
4353
4498
|
const lastDuration = last?.duration ?? 0;
|
|
4354
4499
|
if (nowIndex >= timeline.length && time > lastWhen + lastDuration + 0.1) {
|
|
4355
4500
|
stop();
|
|
4356
|
-
options.onEnd();
|
|
4501
|
+
options.onEnd(false);
|
|
4357
4502
|
}
|
|
4358
4503
|
}
|
|
4359
4504
|
};
|
|
@@ -4394,6 +4539,8 @@ var createSequencer = (options) => {
|
|
|
4394
4539
|
}
|
|
4395
4540
|
loopBase = 0;
|
|
4396
4541
|
lastPlayStep = fromStepValue - 1e-4;
|
|
4542
|
+
lastRealTime = -1;
|
|
4543
|
+
lastAudioTime = -1;
|
|
4397
4544
|
intervalId = setInterval(scheduleTick, TICK_INTERVAL_MS);
|
|
4398
4545
|
animationId = requestAnimationFrame(animate);
|
|
4399
4546
|
};
|
|
@@ -4591,11 +4738,11 @@ var DAW_CSS = `
|
|
|
4591
4738
|
}
|
|
4592
4739
|
.dtm-btn:active { transform: translate(3px,3px); box-shadow: none; }
|
|
4593
4740
|
.dtm-btn:disabled { opacity: .3; cursor: default; box-shadow: none; }
|
|
4741
|
+
.dtm-btn--ghost { background: transparent; border-color: var(--dtm-border2); }
|
|
4594
4742
|
.dtm-btn--primary { border-color: var(--dtm-primary); background: var(--dtm-primary); color: var(--dtm-pfg); }
|
|
4595
4743
|
.dtm-btn--success { border-color: var(--dtm-success); background: var(--dtm-success); color: var(--c-black); }
|
|
4596
4744
|
.dtm-btn--danger { border-color: var(--dtm-danger); background: var(--dtm-danger); color: var(--c-white); }
|
|
4597
4745
|
.dtm-btn--accent { border-color: var(--dtm-accent); background: var(--dtm-accent); color: var(--c-black); }
|
|
4598
|
-
.dtm-btn--ghost { background: transparent; border-color: var(--dtm-border2); }
|
|
4599
4746
|
.dtm-btn--icon { padding: 0; }
|
|
4600
4747
|
|
|
4601
4748
|
/* \u2500\u2500\u2500 \u30A2\u30A4\u30B3\u30F3\u30DC\u30BF\u30F3 \u2500\u2500\u2500 */
|
|
@@ -5229,6 +5376,18 @@ var DAW_CSS = `
|
|
|
5229
5376
|
}
|
|
5230
5377
|
|
|
5231
5378
|
.dtm-hidden { display: none !important; }
|
|
5379
|
+
/* \u8AAD\u8FBC\u6642\u306E\u63A7\u3048\u3081\u306A\u304A\u77E5\u3089\u305B\uFF08\u4F8B: \u30B7\u30F3\u30D7\u30EB\u30E2\u30FC\u30C9\u3067\u306E\u30C8\u30E9\u30C3\u30AF\u5408\u7B97\uFF09\u3002\u4E3B\u5F35\u3057\u3059\u304E\u306A\u3044 muted \u8868\u793A\u3002 */
|
|
5380
|
+
.dtm-load-note {
|
|
5381
|
+
margin: 6px 0 0;
|
|
5382
|
+
padding: 0 2px;
|
|
5383
|
+
font-family: var(--dtm-font);
|
|
5384
|
+
font-size: 10px;
|
|
5385
|
+
line-height: 1.5;
|
|
5386
|
+
letter-spacing: .04em;
|
|
5387
|
+
color: var(--dtm-muted);
|
|
5388
|
+
opacity: .85;
|
|
5389
|
+
}
|
|
5390
|
+
.dtm-load-note::before { content: "\u24D8 "; }
|
|
5232
5391
|
.dtm-grow { flex: 1 1 auto; }
|
|
5233
5392
|
.dtm-lyric-icon {
|
|
5234
5393
|
flex: 0 0 auto;
|
|
@@ -5328,6 +5487,62 @@ var DAW_CSS = `
|
|
|
5328
5487
|
white-space: nowrap;
|
|
5329
5488
|
}
|
|
5330
5489
|
.dtm-player-mml-link:hover { color: var(--dtm-primary); }
|
|
5490
|
+
.dtm-player-more-container {
|
|
5491
|
+
position: relative;
|
|
5492
|
+
display: inline-flex;
|
|
5493
|
+
align-items: center;
|
|
5494
|
+
}
|
|
5495
|
+
.dtm-player-more-btn {
|
|
5496
|
+
background: transparent;
|
|
5497
|
+
border: none;
|
|
5498
|
+
color: var(--dtm-muted);
|
|
5499
|
+
cursor: pointer;
|
|
5500
|
+
padding: 2px;
|
|
5501
|
+
display: flex;
|
|
5502
|
+
align-items: center;
|
|
5503
|
+
justify-content: center;
|
|
5504
|
+
border-radius: 50%;
|
|
5505
|
+
width: 24px;
|
|
5506
|
+
height: 24px;
|
|
5507
|
+
transition: color 0.15s, background-color 0.15s;
|
|
5508
|
+
}
|
|
5509
|
+
.dtm-player-more-btn:hover,
|
|
5510
|
+
.dtm-player-more-btn.is-active {
|
|
5511
|
+
color: var(--dtm-text);
|
|
5512
|
+
background: var(--dtm-border2);
|
|
5513
|
+
}
|
|
5514
|
+
.dtm-player-menu {
|
|
5515
|
+
position: absolute;
|
|
5516
|
+
top: calc(100% + 4px);
|
|
5517
|
+
right: 0;
|
|
5518
|
+
background: var(--dtm-deep);
|
|
5519
|
+
border: 2px solid var(--dtm-border2);
|
|
5520
|
+
box-shadow: 4px 4px 0 var(--c-black);
|
|
5521
|
+
z-index: 200;
|
|
5522
|
+
display: flex;
|
|
5523
|
+
flex-direction: column;
|
|
5524
|
+
padding: 4px 0;
|
|
5525
|
+
min-width: 130px;
|
|
5526
|
+
font-family: var(--dtm-font);
|
|
5527
|
+
}
|
|
5528
|
+
.dtm-player-menu-item {
|
|
5529
|
+
background: transparent;
|
|
5530
|
+
border: none;
|
|
5531
|
+
color: var(--dtm-text);
|
|
5532
|
+
padding: 6px 12px;
|
|
5533
|
+
text-align: left;
|
|
5534
|
+
cursor: pointer;
|
|
5535
|
+
font-size: 11px;
|
|
5536
|
+
font-family: inherit;
|
|
5537
|
+
white-space: nowrap;
|
|
5538
|
+
width: 100%;
|
|
5539
|
+
box-sizing: border-box;
|
|
5540
|
+
transition: background-color 0.1s, color 0.1s;
|
|
5541
|
+
}
|
|
5542
|
+
.dtm-player-menu-item:hover {
|
|
5543
|
+
background: var(--dtm-primary);
|
|
5544
|
+
color: var(--dtm-pfg);
|
|
5545
|
+
}
|
|
5331
5546
|
.dtm-player-emoji {
|
|
5332
5547
|
position: relative;
|
|
5333
5548
|
display: inline-flex;
|
|
@@ -5603,6 +5818,75 @@ var showBalloon = (balloonEl) => {
|
|
|
5603
5818
|
hideActiveBalloon();
|
|
5604
5819
|
}, 3e3);
|
|
5605
5820
|
};
|
|
5821
|
+
var copyToClipboard = async (doc, text) => {
|
|
5822
|
+
try {
|
|
5823
|
+
await navigator.clipboard.writeText(text);
|
|
5824
|
+
return true;
|
|
5825
|
+
} catch {
|
|
5826
|
+
try {
|
|
5827
|
+
const textarea = doc.createElement("textarea");
|
|
5828
|
+
textarea.value = text;
|
|
5829
|
+
textarea.style.position = "fixed";
|
|
5830
|
+
textarea.style.opacity = "0";
|
|
5831
|
+
doc.body.appendChild(textarea);
|
|
5832
|
+
textarea.select();
|
|
5833
|
+
const ok = doc.execCommand("copy");
|
|
5834
|
+
doc.body.removeChild(textarea);
|
|
5835
|
+
return ok;
|
|
5836
|
+
} catch {
|
|
5837
|
+
return false;
|
|
5838
|
+
}
|
|
5839
|
+
}
|
|
5840
|
+
};
|
|
5841
|
+
var toBase64Url = (bytes) => {
|
|
5842
|
+
let bin = "";
|
|
5843
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
5844
|
+
bin += String.fromCharCode(bytes[i]);
|
|
5845
|
+
}
|
|
5846
|
+
return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
5847
|
+
};
|
|
5848
|
+
var HIRAGANA_START = 12353;
|
|
5849
|
+
var HIRAGANA_END = 12447;
|
|
5850
|
+
var KATAKANA_START = 12449;
|
|
5851
|
+
var KATAKANA_END = 12543;
|
|
5852
|
+
var PROLONGED_MARK = 12540;
|
|
5853
|
+
var SHIFT_KATAKANA = 255;
|
|
5854
|
+
var VALUE_PROLONGED = 223;
|
|
5855
|
+
var customEncode = (str) => {
|
|
5856
|
+
const bytes = [];
|
|
5857
|
+
for (let i = 0; i < str.length; i++) {
|
|
5858
|
+
const code = str.charCodeAt(i);
|
|
5859
|
+
if (code <= 127) {
|
|
5860
|
+
bytes.push(code);
|
|
5861
|
+
} else if (code === PROLONGED_MARK) {
|
|
5862
|
+
bytes.push(VALUE_PROLONGED);
|
|
5863
|
+
} else if (code >= HIRAGANA_START && code <= HIRAGANA_END) {
|
|
5864
|
+
bytes.push(128 + (code - HIRAGANA_START));
|
|
5865
|
+
} else if (code >= KATAKANA_START && code <= KATAKANA_END) {
|
|
5866
|
+
bytes.push(SHIFT_KATAKANA);
|
|
5867
|
+
bytes.push(128 + (code - 96 - HIRAGANA_START));
|
|
5868
|
+
}
|
|
5869
|
+
}
|
|
5870
|
+
return new Uint8Array(bytes);
|
|
5871
|
+
};
|
|
5872
|
+
var encodeMml = async (mml) => {
|
|
5873
|
+
try {
|
|
5874
|
+
if (typeof CompressionStream !== "undefined") {
|
|
5875
|
+
const cs = new CompressionStream("gzip");
|
|
5876
|
+
const w = cs.writable.getWriter();
|
|
5877
|
+
w.write(customEncode(mml));
|
|
5878
|
+
w.close();
|
|
5879
|
+
const buf = await new Response(cs.readable).arrayBuffer();
|
|
5880
|
+
return `z.${toBase64Url(new Uint8Array(buf))}`;
|
|
5881
|
+
}
|
|
5882
|
+
} catch (e) {
|
|
5883
|
+
console.warn(
|
|
5884
|
+
"[dtm] CompressionStream failed, fallback to encodeURIComponent",
|
|
5885
|
+
e
|
|
5886
|
+
);
|
|
5887
|
+
}
|
|
5888
|
+
return `u.${encodeURIComponent(mml)}`;
|
|
5889
|
+
};
|
|
5606
5890
|
var mountMmlPlayer = (target, mml, options = {}) => {
|
|
5607
5891
|
injectStyles(target.ownerDocument ?? document);
|
|
5608
5892
|
const {
|
|
@@ -5748,6 +6032,83 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
5748
6032
|
emojiEls.push(em);
|
|
5749
6033
|
emojiByTrack.set(index, em);
|
|
5750
6034
|
}
|
|
6035
|
+
const menuContainer = doc.createElement("div");
|
|
6036
|
+
menuContainer.className = "dtm-player-more-container";
|
|
6037
|
+
const moreBtn = doc.createElement("button");
|
|
6038
|
+
moreBtn.type = "button";
|
|
6039
|
+
moreBtn.className = "dtm-player-more-btn";
|
|
6040
|
+
moreBtn.innerHTML = icon("more", 14);
|
|
6041
|
+
moreBtn.title = "\u30E1\u30CB\u30E5\u30FC";
|
|
6042
|
+
menuContainer.appendChild(moreBtn);
|
|
6043
|
+
const menuDropdown = doc.createElement("div");
|
|
6044
|
+
menuDropdown.className = "dtm-player-menu";
|
|
6045
|
+
menuDropdown.style.display = "none";
|
|
6046
|
+
const copyMmlItem = doc.createElement("button");
|
|
6047
|
+
copyMmlItem.type = "button";
|
|
6048
|
+
copyMmlItem.className = "dtm-player-menu-item";
|
|
6049
|
+
copyMmlItem.textContent = "MML\u30B3\u30D4\u30FC";
|
|
6050
|
+
const embedItem = doc.createElement("button");
|
|
6051
|
+
embedItem.type = "button";
|
|
6052
|
+
embedItem.className = "dtm-player-menu-item";
|
|
6053
|
+
embedItem.textContent = "\u57CB\u3081\u8FBC\u3080";
|
|
6054
|
+
menuDropdown.appendChild(copyMmlItem);
|
|
6055
|
+
menuDropdown.appendChild(embedItem);
|
|
6056
|
+
menuContainer.appendChild(menuDropdown);
|
|
6057
|
+
mmlHeader.appendChild(menuContainer);
|
|
6058
|
+
const toggleMenu = (show) => {
|
|
6059
|
+
const visible = show !== void 0 ? show : menuDropdown.style.display === "none";
|
|
6060
|
+
menuDropdown.style.display = visible ? "flex" : "none";
|
|
6061
|
+
if (visible) {
|
|
6062
|
+
moreBtn.classList.add("is-active");
|
|
6063
|
+
doc.addEventListener("click", handleOutsideClick);
|
|
6064
|
+
} else {
|
|
6065
|
+
moreBtn.classList.remove("is-active");
|
|
6066
|
+
doc.removeEventListener("click", handleOutsideClick);
|
|
6067
|
+
}
|
|
6068
|
+
};
|
|
6069
|
+
const handleOutsideClick = (e) => {
|
|
6070
|
+
if (!menuContainer.contains(e.target)) {
|
|
6071
|
+
toggleMenu(false);
|
|
6072
|
+
}
|
|
6073
|
+
};
|
|
6074
|
+
moreBtn.addEventListener("click", (e) => {
|
|
6075
|
+
e.stopPropagation();
|
|
6076
|
+
toggleMenu();
|
|
6077
|
+
});
|
|
6078
|
+
copyMmlItem.addEventListener("click", async (e) => {
|
|
6079
|
+
e.stopPropagation();
|
|
6080
|
+
const success = await copyToClipboard(doc, mml);
|
|
6081
|
+
if (success) {
|
|
6082
|
+
copyMmlItem.textContent = "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\uFF01";
|
|
6083
|
+
} else {
|
|
6084
|
+
copyMmlItem.textContent = "\u30B3\u30D4\u30FC\u5931\u6557";
|
|
6085
|
+
}
|
|
6086
|
+
setTimeout(() => {
|
|
6087
|
+
copyMmlItem.textContent = "MML\u30B3\u30D4\u30FC";
|
|
6088
|
+
}, 2e3);
|
|
6089
|
+
});
|
|
6090
|
+
embedItem.addEventListener("click", async (e) => {
|
|
6091
|
+
e.stopPropagation();
|
|
6092
|
+
embedItem.textContent = "\u751F\u6210\u4E2D...";
|
|
6093
|
+
try {
|
|
6094
|
+
const embedBase = options.embedUrl ?? "https://onjmin.github.io/dtm/demo/embed.html";
|
|
6095
|
+
const payload = await encodeMml(mml);
|
|
6096
|
+
const url2 = `${embedBase}#${payload}`;
|
|
6097
|
+
const snippet = `<iframe src="${url2}" width="100%" height="260" frameborder="0" loading="lazy" title="@onjmin/dtm player"></iframe>`;
|
|
6098
|
+
const success = await copyToClipboard(doc, snippet);
|
|
6099
|
+
if (success) {
|
|
6100
|
+
embedItem.textContent = "\u30B3\u30D4\u30FC\u3057\u307E\u3057\u305F\uFF01";
|
|
6101
|
+
} else {
|
|
6102
|
+
embedItem.textContent = "\u30B3\u30D4\u30FC\u5931\u6557";
|
|
6103
|
+
}
|
|
6104
|
+
} catch (err2) {
|
|
6105
|
+
console.error("[dtm] failed to generate embed snippet", err2);
|
|
6106
|
+
embedItem.textContent = "\u751F\u6210\u5931\u6557";
|
|
6107
|
+
}
|
|
6108
|
+
setTimeout(() => {
|
|
6109
|
+
embedItem.textContent = "\u57CB\u3081\u8FBC\u3080";
|
|
6110
|
+
}, 2e3);
|
|
6111
|
+
});
|
|
5751
6112
|
const promotedToImage = /* @__PURE__ */ new Set();
|
|
5752
6113
|
for (const [index, lt] of lyricTracks) {
|
|
5753
6114
|
const em = emojiByTrack.get(index);
|
|
@@ -6056,7 +6417,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6056
6417
|
onTick: (step) => {
|
|
6057
6418
|
renderPlayhead(step);
|
|
6058
6419
|
},
|
|
6059
|
-
onEnd: () => finish(),
|
|
6420
|
+
onEnd: (interrupted) => finish(),
|
|
6060
6421
|
stepsPerBar: STEPS_PER_BAR
|
|
6061
6422
|
});
|
|
6062
6423
|
let playing = false;
|
|
@@ -6151,6 +6512,7 @@ var mountMmlPlayer = (target, mml, options = {}) => {
|
|
|
6151
6512
|
else play();
|
|
6152
6513
|
});
|
|
6153
6514
|
const destroy = () => {
|
|
6515
|
+
doc.removeEventListener("click", handleOutsideClick);
|
|
6154
6516
|
seq.stop();
|
|
6155
6517
|
peekVoices()?.stopStream();
|
|
6156
6518
|
if (activePlayer === instance) activePlayer = null;
|
|
@@ -7069,6 +7431,10 @@ var mountDAW = (target, options = {}) => {
|
|
|
7069
7431
|
0,
|
|
7070
7432
|
Math.floor(step / snapGridSteps) * snapGridSteps
|
|
7071
7433
|
);
|
|
7434
|
+
if (playbackState === "paused") {
|
|
7435
|
+
playbackState = "stopped";
|
|
7436
|
+
updateTransport();
|
|
7437
|
+
}
|
|
7072
7438
|
redrawAll();
|
|
7073
7439
|
});
|
|
7074
7440
|
setDrawOffset(currentOffsetX, currentOffsetY);
|
|
@@ -7144,9 +7510,14 @@ var mountDAW = (target, options = {}) => {
|
|
|
7144
7510
|
}
|
|
7145
7511
|
redrawAll();
|
|
7146
7512
|
},
|
|
7147
|
-
onEnd: () => {
|
|
7148
|
-
|
|
7149
|
-
|
|
7513
|
+
onEnd: (interrupted) => {
|
|
7514
|
+
if (interrupted) {
|
|
7515
|
+
playbackState = "paused";
|
|
7516
|
+
pausedPlayStep = currentPlayStep;
|
|
7517
|
+
} else {
|
|
7518
|
+
playbackState = "stopped";
|
|
7519
|
+
currentPlayStep = 0;
|
|
7520
|
+
}
|
|
7150
7521
|
updateTransport();
|
|
7151
7522
|
redrawAll();
|
|
7152
7523
|
},
|
|
@@ -7236,13 +7607,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
7236
7607
|
redrawAll();
|
|
7237
7608
|
};
|
|
7238
7609
|
const togglePlay = () => {
|
|
7239
|
-
if (playbackState === "playing")
|
|
7610
|
+
if (playbackState === "playing") pause();
|
|
7240
7611
|
else play();
|
|
7241
7612
|
};
|
|
7242
7613
|
const updateTransport = () => {
|
|
7243
7614
|
const playing = playbackState === "playing";
|
|
7244
|
-
const label = playing ? "\u505C\u6B62" : playbackState === "paused" ? "\u518D\u958B" : "\u8A66\u8074";
|
|
7245
|
-
refs.playBtn.innerHTML = `${icon(playing ? "
|
|
7615
|
+
const label = playing ? "\u4E00\u6642\u505C\u6B62" : playbackState === "paused" ? "\u518D\u958B" : "\u8A66\u8074";
|
|
7616
|
+
refs.playBtn.innerHTML = `${icon(playing ? "pause" : "play")}<span>${label}</span>`;
|
|
7246
7617
|
refs.playBtn.classList.toggle("dtm-play--stop", playing);
|
|
7247
7618
|
};
|
|
7248
7619
|
const updateUndoRedo = () => {
|
|
@@ -7631,20 +8002,25 @@ var mountDAW = (target, options = {}) => {
|
|
|
7631
8002
|
};
|
|
7632
8003
|
const loadMML = (mml) => {
|
|
7633
8004
|
if (!mml) return;
|
|
8005
|
+
stop();
|
|
7634
8006
|
clearAll();
|
|
7635
8007
|
for (const t of trackStates) t.core.setLoadMode(true);
|
|
7636
8008
|
const {
|
|
7637
8009
|
placements,
|
|
7638
8010
|
bpm: parsedBpm,
|
|
7639
8011
|
lyrics,
|
|
7640
|
-
meta
|
|
8012
|
+
meta,
|
|
8013
|
+
mergedTrackCount
|
|
7641
8014
|
} = parseMML(mml, {
|
|
7642
8015
|
stepsPerBar: renderConfig.stepsPerBar,
|
|
7643
8016
|
collectLyrics: true,
|
|
7644
8017
|
// このDAWのトラック数を超えるチャンネルはベースへ畳み込む(従来挙動)
|
|
7645
8018
|
clampTrackCount: trackStates.length
|
|
7646
8019
|
});
|
|
7647
|
-
|
|
8020
|
+
if (meta.instrument && INSTRUMENT_PRESETS[meta.instrument]) {
|
|
8021
|
+
currentInstrument = meta.instrument;
|
|
8022
|
+
options.onInstrumentChange?.(meta.instrument);
|
|
8023
|
+
}
|
|
7648
8024
|
if (meta.drum && drumPatterns[meta.drum]) {
|
|
7649
8025
|
currentDrumPattern = meta.drum;
|
|
7650
8026
|
refs.drumSelect.value = meta.drum;
|
|
@@ -7696,6 +8072,13 @@ var mountDAW = (target, options = {}) => {
|
|
|
7696
8072
|
redrawAll();
|
|
7697
8073
|
updateTrackPanel();
|
|
7698
8074
|
updateUndoRedo();
|
|
8075
|
+
if (!isAdvanced && mergedTrackCount > 0) {
|
|
8076
|
+
refs.mmlLoadNote.textContent = "\u30B7\u30F3\u30D7\u30EB\u30E2\u30FC\u30C9\u306E\u305F\u3081\u3001\u4E00\u90E8\u306E\u30C8\u30E9\u30C3\u30AF\u3092\u5408\u7B97\u3057\u3066\u8AAD\u307F\u8FBC\u307F\u307E\u3057\u305F";
|
|
8077
|
+
refs.mmlLoadNote.classList.remove("dtm-hidden");
|
|
8078
|
+
} else {
|
|
8079
|
+
refs.mmlLoadNote.textContent = "";
|
|
8080
|
+
refs.mmlLoadNote.classList.add("dtm-hidden");
|
|
8081
|
+
}
|
|
7699
8082
|
};
|
|
7700
8083
|
const applyChord = () => {
|
|
7701
8084
|
const active = getActive();
|
|
@@ -7728,6 +8111,7 @@ var mountDAW = (target, options = {}) => {
|
|
|
7728
8111
|
applyMidiSelection(midi, selected);
|
|
7729
8112
|
};
|
|
7730
8113
|
const applyMidiSelection = (midi, selectedIndices) => {
|
|
8114
|
+
stop();
|
|
7731
8115
|
clearAll();
|
|
7732
8116
|
for (const t of trackStates) t.core.setLoadMode(true);
|
|
7733
8117
|
const { placements, bpm: parsedBpm } = isAdvanced ? extractMidiPlacementsByTrack(
|
|
@@ -8159,6 +8543,25 @@ var mountDAW = (target, options = {}) => {
|
|
|
8159
8543
|
const setLoading = (loading) => {
|
|
8160
8544
|
refs.topbar.classList.toggle("is-loading", loading);
|
|
8161
8545
|
};
|
|
8546
|
+
const getCurrentPlayStep = () => {
|
|
8547
|
+
if (playbackState === "playing") return currentPlayStep;
|
|
8548
|
+
if (playbackState === "paused") return pausedPlayStep;
|
|
8549
|
+
return playStartStep;
|
|
8550
|
+
};
|
|
8551
|
+
const forcePauseAt = (step) => {
|
|
8552
|
+
playStartStep = step;
|
|
8553
|
+
pausedPlayStep = step;
|
|
8554
|
+
currentPlayStep = step;
|
|
8555
|
+
playbackState = "paused";
|
|
8556
|
+
const canvas = getGridCanvas();
|
|
8557
|
+
currentOffsetX = Math.max(
|
|
8558
|
+
0,
|
|
8559
|
+
step * renderConfig.stepWidth - canvas.width * 0.5
|
|
8560
|
+
);
|
|
8561
|
+
setDrawOffset(currentOffsetX, currentOffsetY);
|
|
8562
|
+
updateTransport();
|
|
8563
|
+
redrawAll();
|
|
8564
|
+
};
|
|
8162
8565
|
return {
|
|
8163
8566
|
play,
|
|
8164
8567
|
pause,
|
|
@@ -8196,9 +8599,12 @@ var mountDAW = (target, options = {}) => {
|
|
|
8196
8599
|
exportMIDI: exportMIDI2,
|
|
8197
8600
|
setBpm,
|
|
8198
8601
|
getPlaybackState: () => playbackState,
|
|
8602
|
+
getCurrentPlayStep,
|
|
8603
|
+
forcePauseAt,
|
|
8199
8604
|
setLoading,
|
|
8200
8605
|
destroy: () => {
|
|
8201
8606
|
sequencer.stop();
|
|
8607
|
+
options.singingVoices?.stopStream();
|
|
8202
8608
|
resizeObserver.disconnect();
|
|
8203
8609
|
document.removeEventListener("pointermove", onPointerMove);
|
|
8204
8610
|
document.removeEventListener("pointerup", onPointerUp);
|
|
@@ -8208,110 +8614,6 @@ var mountDAW = (target, options = {}) => {
|
|
|
8208
8614
|
};
|
|
8209
8615
|
};
|
|
8210
8616
|
|
|
8211
|
-
// src/instrument-presets.ts
|
|
8212
|
-
var INSTRUMENT_PRESETS = {
|
|
8213
|
-
// --- STANDARD: 汎用性と完成度重視 ---
|
|
8214
|
-
piano: {
|
|
8215
|
-
displayName: "\u30B0\u30E9\u30F3\u30C9\u30D4\u30A2\u30CE",
|
|
8216
|
-
description: "\u6700\u3082\u7834\u7DBB\u3057\u306B\u304F\u3044\u69CB\u6210\u3002\u697D\u66F2\u5236\u4F5C\u306E\u30B9\u30B1\u30C3\u30C1\u306B\u3082\u6700\u9069\u3002",
|
|
8217
|
-
melody: "Acoustic Grand Piano",
|
|
8218
|
-
submelody: "Vibraphone",
|
|
8219
|
-
bass: "Electric Bass (finger)",
|
|
8220
|
-
chord: "Pad 2 (warm)"
|
|
8221
|
-
},
|
|
8222
|
-
acoustic: {
|
|
8223
|
-
displayName: "\u30A2\u30B3\u30FC\u30B9\u30C6\u30A3\u30C3\u30AF",
|
|
8224
|
-
description: "\u751F\u697D\u5668\u306E\u6E29\u304B\u307F\u3092\u91CD\u8996\u3002\u30D5\u30A9\u30FC\u30AF\u3084\u30DD\u30C3\u30D7\u30B9\u306B\u3002",
|
|
8225
|
-
melody: "Acoustic Guitar (steel)",
|
|
8226
|
-
submelody: "Harmonica",
|
|
8227
|
-
bass: "Acoustic Bass",
|
|
8228
|
-
chord: "Acoustic Guitar (nylon)"
|
|
8229
|
-
},
|
|
8230
|
-
jazz_night: {
|
|
8231
|
-
displayName: "\u30B8\u30E3\u30BA\u30FB\u30CA\u30A4\u30C8",
|
|
8232
|
-
description: "Rhodes\u98A8\u306EEP\u3068\u30A6\u30C3\u30C9\u30D9\u30FC\u30B9\u306B\u3088\u308B\u3001\u5927\u4EBA\u3073\u305F\u30A2\u30F3\u30B5\u30F3\u30D6\u30EB\u3002",
|
|
8233
|
-
melody: "Electric Piano 1",
|
|
8234
|
-
submelody: "Flute",
|
|
8235
|
-
bass: "Acoustic Bass",
|
|
8236
|
-
chord: "Electric Guitar (jazz)"
|
|
8237
|
-
},
|
|
8238
|
-
// --- MODERN & VIBE: エッジの効いた現代的な響き ---
|
|
8239
|
-
synth_pop: {
|
|
8240
|
-
displayName: "\u30B7\u30F3\u30BB\u30DD\u30C3\u30D7",
|
|
8241
|
-
description: "80s\u301C\u73FE\u4EE3\u307E\u3067\u3002\u629C\u3051\u308B\u30EA\u30FC\u30C9\u3068\u592A\u3044\u30D9\u30FC\u30B9\u306E\u738B\u9053\u3002",
|
|
8242
|
-
melody: "Lead 2 (sawtooth)",
|
|
8243
|
-
submelody: "Lead 4 (chiff)",
|
|
8244
|
-
bass: "Synth Bass 2",
|
|
8245
|
-
chord: "Pad 3 (polysynth)"
|
|
8246
|
-
},
|
|
8247
|
-
cyber_punk: {
|
|
8248
|
-
displayName: "\u30B5\u30A4\u30D0\u30FC\u30D1\u30F3\u30AF",
|
|
8249
|
-
description: "\u30C7\u30B8\u30BF\u30EB\u306A\u51B7\u305F\u3055\u3068\u6B6A\u307F\u304C\u6DF7\u3056\u308A\u5408\u3046\u3001\u672A\u6765\u7684\u306A\u97FF\u304D\u3002",
|
|
8250
|
-
melody: "Lead 8 (bass + lead)",
|
|
8251
|
-
submelody: "Lead 5 (charang)",
|
|
8252
|
-
bass: "Synth Bass 2",
|
|
8253
|
-
chord: "Pad 8 (sweep)"
|
|
8254
|
-
},
|
|
8255
|
-
rock: {
|
|
8256
|
-
displayName: "\u30CF\u30FC\u30C9\u30ED\u30C3\u30AF",
|
|
8257
|
-
description: "\u6B6A\u307F\u30AE\u30BF\u30FC\u3068\u91CD\u539A\u306A\u30D9\u30FC\u30B9\u3067\u3001\u30D1\u30EF\u30FC\u3092\u524D\u9762\u306B\u3002",
|
|
8258
|
-
melody: "Distortion Guitar",
|
|
8259
|
-
submelody: "Rock Organ",
|
|
8260
|
-
bass: "Electric Bass (pick)",
|
|
8261
|
-
chord: "Overdriven Guitar"
|
|
8262
|
-
},
|
|
8263
|
-
// --- WORLD & CLASSIC: 特定のジャンル・地域 ---
|
|
8264
|
-
orchestra: {
|
|
8265
|
-
displayName: "\u30AA\u30FC\u30B1\u30B9\u30C8\u30E9",
|
|
8266
|
-
description: "\u58EE\u5927\u306A\u7269\u8A9E\u3092\u4E88\u611F\u3055\u305B\u308B\u3001\u7BA1\u5F26\u697D\u5668\u306E\u91CD\u539A\u306A\u97FF\u304D\u3002",
|
|
8267
|
-
melody: "French Horn",
|
|
8268
|
-
submelody: "Pizzicato Strings",
|
|
8269
|
-
bass: "Cello",
|
|
8270
|
-
chord: "Tremolo Strings"
|
|
8271
|
-
},
|
|
8272
|
-
japanese_wa: {
|
|
8273
|
-
displayName: "\u548C\u98A8\u30FB\u96C5",
|
|
8274
|
-
description: "\u7434\u3068\u4E09\u5473\u7DDA\u306E\u7E4A\u7D30\u306A\u8ABF\u3079\u306B\u3001\u5C3A\u516B\u306E\u60C5\u7DD2\u3092\u6DFB\u3048\u3066\u3002",
|
|
8275
|
-
melody: "Koto",
|
|
8276
|
-
submelody: "Shamisen",
|
|
8277
|
-
bass: "Taiko Drum",
|
|
8278
|
-
chord: "Shakuhachi"
|
|
8279
|
-
},
|
|
8280
|
-
arabic_exotic: {
|
|
8281
|
-
displayName: "\u30A8\u30AD\u30BE\u30C1\u30C3\u30AF",
|
|
8282
|
-
description: "\u30B7\u30BF\u30FC\u30EB\u3084\u30D0\u30B0\u30D1\u30A4\u30D7\u306B\u3088\u308B\u3001\u7570\u56FD\u60C5\u7DD2\u6EA2\u308C\u308B\u30B5\u30A6\u30F3\u30C9\u3002",
|
|
8283
|
-
melody: "Sitar",
|
|
8284
|
-
submelody: "Bagpipe",
|
|
8285
|
-
bass: "Fretless Bass",
|
|
8286
|
-
chord: "Kalimba"
|
|
8287
|
-
},
|
|
8288
|
-
// --- FANTASY & ATMOSPHERE: 雰囲気と余韻 ---
|
|
8289
|
-
fantasy_rpg: {
|
|
8290
|
-
displayName: "\u30D5\u30A1\u30F3\u30BF\u30B8\u30FCRPG",
|
|
8291
|
-
description: "\u30AA\u30AB\u30EA\u30CA\u3068\u30CF\u30FC\u30D7\u304C\u7D21\u3050\u3001\u5192\u967A\u3068\u9B54\u6CD5\u306E\u4E16\u754C\u89B3\u3002",
|
|
8292
|
-
melody: "Ocarina",
|
|
8293
|
-
submelody: "Celesta",
|
|
8294
|
-
bass: "Timpani",
|
|
8295
|
-
chord: "Orchestral Harp"
|
|
8296
|
-
},
|
|
8297
|
-
ambient_cloud: {
|
|
8298
|
-
displayName: "\u30A2\u30F3\u30D3\u30A8\u30F3\u30C8",
|
|
8299
|
-
description: "\u8F2A\u90ED\u3092\u307C\u304B\u3057\u305F\u97F3\u8272\u3067\u3001\u6DF1\u3044\u6CA1\u5165\u611F\u3068\u4F59\u97FB\u3092\u6F14\u51FA\u3002",
|
|
8300
|
-
melody: "Lead 6 (voice)",
|
|
8301
|
-
submelody: "Music Box",
|
|
8302
|
-
bass: "Synth Bass 1",
|
|
8303
|
-
chord: "Pad 7 (halo)"
|
|
8304
|
-
},
|
|
8305
|
-
retro_game: {
|
|
8306
|
-
displayName: "8-bit \u30EC\u30C8\u30ED",
|
|
8307
|
-
description: "\u77E9\u5F62\u6CE2\u3092\u60F3\u8D77\u3055\u305B\u308B\u3001\u521D\u671F\u30B2\u30FC\u30E0\u6A5F\u306E\u3088\u3046\u306A\u61D0\u304B\u3057\u3044\u97FF\u304D\u3002",
|
|
8308
|
-
melody: "Lead 1 (square)",
|
|
8309
|
-
submelody: "Lead 2 (sawtooth)",
|
|
8310
|
-
bass: "Synth Bass 1",
|
|
8311
|
-
chord: "Clavinet"
|
|
8312
|
-
}
|
|
8313
|
-
};
|
|
8314
|
-
|
|
8315
8617
|
// src/headless-player.ts
|
|
8316
8618
|
var STEPS_PER_BAR2 = 192;
|
|
8317
8619
|
var playMML = (mml, options = {}) => {
|
|
@@ -8362,7 +8664,7 @@ var playMML = (mml, options = {}) => {
|
|
|
8362
8664
|
},
|
|
8363
8665
|
onTick: () => {
|
|
8364
8666
|
},
|
|
8365
|
-
onEnd: () => finish(),
|
|
8667
|
+
onEnd: (interrupted) => finish(),
|
|
8366
8668
|
stepsPerBar: STEPS_PER_BAR2
|
|
8367
8669
|
});
|
|
8368
8670
|
const finish = () => {
|
|
@@ -9182,11 +9484,13 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9182
9484
|
const mountedPlayers = [];
|
|
9183
9485
|
const mountedModeSwitches = [];
|
|
9184
9486
|
const mountEditor = (target, opts = {}) => {
|
|
9185
|
-
const { preset, presetUI, ...dawOverrides } = opts;
|
|
9487
|
+
const { preset, presetUI, onInstrumentChange, ...dawOverrides } = opts;
|
|
9186
9488
|
const tracks = dawOverrides.tracks ?? TRACKS_SIMPLE;
|
|
9187
9489
|
const trackIds = tracks.map((t) => t.id);
|
|
9188
9490
|
const presetKey = preset && INSTRUMENT_PRESETS[preset] ? preset : defaultPreset;
|
|
9189
|
-
|
|
9491
|
+
const meta = opts.initialMML ? parseMmlMeta(opts.initialMML) : {};
|
|
9492
|
+
const initialPreset = meta.instrument && INSTRUMENT_PRESETS[meta.instrument] ? meta.instrument : presetKey;
|
|
9493
|
+
let editorPreset = initialPreset;
|
|
9190
9494
|
const isAdvancedMode = dawOverrides.mode === "advanced";
|
|
9191
9495
|
const playNote = (e) => {
|
|
9192
9496
|
const sf = resolveSoundFont(
|
|
@@ -9204,6 +9508,14 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9204
9508
|
duration: e.duration
|
|
9205
9509
|
});
|
|
9206
9510
|
};
|
|
9511
|
+
let presetSelect = null;
|
|
9512
|
+
const handleInstrumentChange = (key) => {
|
|
9513
|
+
editorPreset = key;
|
|
9514
|
+
if (presetSelect) {
|
|
9515
|
+
presetSelect.setValue(key);
|
|
9516
|
+
}
|
|
9517
|
+
onInstrumentChange?.(key);
|
|
9518
|
+
};
|
|
9207
9519
|
const base = {
|
|
9208
9520
|
getAudioTime: () => audioCtx.currentTime,
|
|
9209
9521
|
onResumeAudio: resumeAudio,
|
|
@@ -9212,19 +9524,19 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9212
9524
|
singingVoices,
|
|
9213
9525
|
parseMidi,
|
|
9214
9526
|
onToggleRecord,
|
|
9527
|
+
onInstrumentChange: handleInstrumentChange,
|
|
9215
9528
|
...dawOverrides
|
|
9216
9529
|
};
|
|
9217
9530
|
const daw = mountDAW(target, base);
|
|
9218
9531
|
mountedEditors.push(daw);
|
|
9219
9532
|
const wantPresetUI = presetUI ?? features.presetUI;
|
|
9220
|
-
let presetSelect = null;
|
|
9221
9533
|
if (wantPresetUI) {
|
|
9222
9534
|
editorPresetSelects.get(target)?.destroy();
|
|
9223
9535
|
const rollEl = target.querySelector('[data-dtm="roll"]');
|
|
9224
9536
|
presetSelect = mountPresetSelect(target, {
|
|
9225
9537
|
getDaw: () => daw,
|
|
9226
9538
|
getTrackIds: () => trackIds,
|
|
9227
|
-
value:
|
|
9539
|
+
value: initialPreset,
|
|
9228
9540
|
loadingTarget: rollEl ?? target,
|
|
9229
9541
|
position: "prepend",
|
|
9230
9542
|
// 楽器変更時、このエディタの発音解決が使うプリセットも追従させる。
|
|
@@ -9234,10 +9546,10 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9234
9546
|
});
|
|
9235
9547
|
editorPresetSelects.set(target, presetSelect);
|
|
9236
9548
|
}
|
|
9237
|
-
daw.setInstrument(
|
|
9549
|
+
daw.setInstrument(initialPreset);
|
|
9238
9550
|
daw.setLoading?.(true);
|
|
9239
9551
|
void loadPreset(
|
|
9240
|
-
|
|
9552
|
+
initialPreset,
|
|
9241
9553
|
trackIds,
|
|
9242
9554
|
isAdvancedMode ? "advanced" : "simple"
|
|
9243
9555
|
).finally(() => {
|
|
@@ -9251,7 +9563,17 @@ var createDtmStudio = async (options = {}) => {
|
|
|
9251
9563
|
const i = mountedEditors.indexOf(daw);
|
|
9252
9564
|
if (i >= 0) mountedEditors.splice(i, 1);
|
|
9253
9565
|
};
|
|
9254
|
-
return {
|
|
9566
|
+
return {
|
|
9567
|
+
...daw,
|
|
9568
|
+
setInstrument: (name) => {
|
|
9569
|
+
daw.setInstrument(name);
|
|
9570
|
+
editorPreset = name;
|
|
9571
|
+
if (presetSelect) {
|
|
9572
|
+
presetSelect.setValue(name);
|
|
9573
|
+
}
|
|
9574
|
+
},
|
|
9575
|
+
destroy
|
|
9576
|
+
};
|
|
9255
9577
|
};
|
|
9256
9578
|
const mountModeSwitch = (target, opts) => {
|
|
9257
9579
|
const doc = target.ownerDocument;
|